diff --git a/app/components/all.scss b/app/components/all.scss
index 261f720c6b22233100ee20d1e27dff5fce2d0dc3..a6135e7bad22bedcd3671127cea7fa806e91eae9 100644
--- a/app/components/all.scss
+++ b/app/components/all.scss
@@ -22,6 +22,7 @@
 @import "./elements/TagList";
 @import "./elements/ChangePassword";
 @import "./elements/Reputation";
+@import "./elements/YoutubePreview";
 
 // modules
 @import "./modules/Header";
diff --git a/app/components/cards/MarkdownViewer.jsx b/app/components/cards/MarkdownViewer.jsx
index db1e25afac1060268c7107ab3705cc537b6c4d91..ff1880fb975aee1baef8b337381897981cc69fe2 100644
--- a/app/components/cards/MarkdownViewer.jsx
+++ b/app/components/cards/MarkdownViewer.jsx
@@ -3,9 +3,11 @@ import {connect} from 'react-redux'
 import {Component} from 'react'
 import Remarkable from 'remarkable'
 // import CardView from 'app/components/cards/CardView'
+import YoutubePreview from 'app/components/elements/YoutubePreview'
 import sanitizeConfig, {noImageText} from 'app/utils/SanitizeConfig'
+import {renderToString} from 'react-dom/server';
 import sanitize from 'sanitize-html'
-import HtmlReady, {sectionHtml} from 'shared/HtmlReady'
+import HtmlReady from 'shared/HtmlReady'
 
 const remarkable = new Remarkable({
     html: true, // remarkable renders first then sanitize runs...
@@ -75,7 +77,7 @@ class MarkdownViewer extends Component {
         let renderedText = html ? text : remarkable.render(text)
 
         // Embed videos, link mentions and hashtags, etc...
-        if(renderedText) renderedText = HtmlReady(renderedText, {large}).html
+        if(renderedText) renderedText = HtmlReady(renderedText).html
 
         // Complete removal of javascript and other dangerous tags..
         // The must remain as close as possible to dangerouslySetInnerHTML
@@ -89,8 +91,24 @@ class MarkdownViewer extends Component {
 
         const noImageActive = cleanText.indexOf(noImageText) !== -1
 
-        // Split and key HTML doc by its root children.  This allows react to compare separately preventing excessive re-rendering.
-        const sections = sectionHtml(cleanText).map( (s, idx) => <div key={idx++} dangerouslySetInnerHTML={{__html: s}} />);
+        // In addition to inserting the youtube compoennt, this allows react to compare separately preventing excessive re-rendering.
+        let idx = 0
+        const sections = []
+        // HtmlReady inserts ~~~ youtube:${id} ~~~
+        for(let section of cleanText.split('~~~ youtube:')) {
+            if(/^[A-Za-z0-9\_\-]+ ~~~/.test(section)) {
+                const youTubeId = section.split(' ')[0]
+                section = section.substring(youTubeId.length + ' ~~~'.length)
+                const w = large ? 640 : 320,
+                      h = large ? 480 : 180
+                sections.push(
+                    <YoutubePreview key={idx++} width={w} height={h} youTubeId={youTubeId}
+                        frameBorder="0" allowFullScreen="true" />
+                )
+            }
+            if(section === '') continue
+            sections.push(<div key={idx++} dangerouslySetInnerHTML={{__html: section}} />)
+        }
 
         const cn = 'Markdown' + (this.props.className ? ` ${this.props.className}` : '') + (html ? ' html' : '')
         return (<div className={"MarkdownViewer " + cn}>
diff --git a/app/components/elements/Template.jsx b/app/components/elements/Template.jsx
index 1f827c641e8644c48223fdd62437bb004b3fc7b4..da4b80ddb1695356aac1ecad13bd60c6931ab146 100644
--- a/app/components/elements/Template.jsx
+++ b/app/components/elements/Template.jsx
@@ -5,30 +5,40 @@ import transaction from 'app/redux/Transaction'
 import shouldComponentUpdate from 'app/utils/shouldComponentUpdate'
 import {Map} from 'immutable'
 
-const {func, string, object} = React.PropTypes
+const {string, object} = React.PropTypes
 
 class Template extends React.Component {
     static propTypes = {
     }
+
     static defaultProps = {
     }
+
     constructor() {
         super()
         this.state = {}
     }
+
     componentWillMount() {
     }
+
     componentDidMount() {
     }
+
     componentWillReceiveProps(nextProps) {
     }
-    shouldComponentUpdate = shouldComponentUpdate(this, 'Template') // This is based on react PureRenderMixin, it makes the component very efficient by not re-rendering unless something in the props or state changed.. PureRenderMixin comes highly recommended.  shouldComponentUpdate adds a debug boolean to show you why your component rendered (what changed, in the browser console type: steemDebug_shouldComponentUpdate=true).
+
+    // This is based on react PureRenderMixin, it makes the component very efficient by not re-rendering unless something in the props or state changed.. PureRenderMixin comes highly recommended.  shouldComponentUpdate adds a debug boolean to show you why your component rendered (what changed, in the browser console type: steemDebug_shouldComponentUpdate=true).
+    shouldComponentUpdate = shouldComponentUpdate(this, 'Template')
     componentWillUpdate(nextProps, nextState) {
     }
+
     componentDidUpdate(prevProps, prevState) {
     }
+
     componentWillUnmount() {
     }
+
     render() {
         const {} = this.props
         return (
@@ -37,7 +47,9 @@ class Template extends React.Component {
         )
     }
 }
+
 import {connect} from 'react-redux'
+
 export default connect(
     (state, ownProps) => {
         return {
diff --git a/app/components/elements/YoutubePreview.jsx b/app/components/elements/YoutubePreview.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..55b3d842605718f727262304f44e421192010acd
--- /dev/null
+++ b/app/components/elements/YoutubePreview.jsx
@@ -0,0 +1,52 @@
+/* eslint react/prop-types: 0 */
+import React from 'react'
+import shouldComponentUpdate from 'app/utils/shouldComponentUpdate'
+
+const {string, number} = React.PropTypes
+
+/** Lots of iframes in a post can be very slow.  This component only inserts the iframe when it is actually needed. */
+export default class YoutubePreview extends React.Component {
+    static propTypes = {
+        youTubeId: string.isRequired,
+        width: number,
+        height: number,
+        dataParams: string,
+    }
+
+    static defaultProps = {
+        width: 640,
+        height: 480,
+        dataParams: 'enablejsapi=0&rel=0&origin=https://steemit.com'
+    }
+
+    constructor() {
+        super()
+        this.state = {}
+    }
+
+    shouldComponentUpdate = shouldComponentUpdate(this, 'YoutubePreview')
+
+    onPlay = () => {
+        this.setState({play: true})
+    }
+
+    render() {
+        const {youTubeId, width, height, dataParams} = this.props
+        const {play} = this.state
+        if(!play) {
+            // mqdefault.jpg (medium quality version, 320px × 180px)
+            // hqdefault.jpg (high quality version, 480px × 360px
+            // sddefault.jpg (standard definition version, 640px × 480px)
+            const thumbnail = width <= 320 ? 'mqdefault.jpg' : width <= 480 ? 'hqdefault.jpg' : 'sddefault.jpg'
+            const previewLink = `http://img.youtube.com/vi/${youTubeId}/${thumbnail}`
+            return (
+                <div className="youtube" onClick={this.onPlay}>
+                    <div className="play"></div>
+                    <img src={previewLink} style={{width, maxWidth: width, height, maxHeight: height}} />
+                </div>
+            )
+        }
+        const autoPlaySrc = `//www.youtube.com/embed/${youTubeId}?autoplay=1&autohide=1&${dataParams}`
+        return <iframe width={width} height={height} src={autoPlaySrc} frameBorder="0" allowFullScreen="true"></iframe>
+    }
+}
diff --git a/app/components/elements/YoutubePreview.scss b/app/components/elements/YoutubePreview.scss
new file mode 100644
index 0000000000000000000000000000000000000000..c9df0f272821f019f19f36667a838db69a57a209
--- /dev/null
+++ b/app/components/elements/YoutubePreview.scss
@@ -0,0 +1,25 @@
+.youtube {
+    background-position: center;
+    background-repeat: no-repeat;
+    position: relative;
+    display: inline-block;
+    overflow: hidden;
+    transition: all 200ms ease-out;
+    cursor: pointer;
+}
+
+.youtube .play {
+    background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAERklEQVR4nOWbTWhcVRTHb1IJVoxGtNCNdal2JYJReC6GWuO83PM/59yUS3FRFARdFlwYP1CfiojQWt36sRCUurRIdVFXIn41lAoVdRGrG1M01YpKrWjiYmaSl8ybZJL3cd+YA//NLObd3++eO8x79z5jSq5Gw+8kov0AP8vMR5l1BtBZQM4B8ks75wCdZdYZZj5qLZ4hov2Nht9Z9vhKKSIaB/gI4M4w62KeAO6Mte4lYOq20FxrlqqOibhHmeWbvNC9ZfDX1mLae391aN6limO/gwgvAPJbWeAZuSDingdwXTBw7/0IsyaA/Fkh+KqOkD+YNfHej1QKD+y7iVlOhgLvFqFfNJvNGyuBJ+KDAF8MDd0tgS8y64OlgSdJMsysL4cG7SOHkyQZLhTee7+d2R2rAVy/S+Jd7/32ouBHAP4gNNRGQyTHc/84NhqNywZp5rvjjnnvt21aABFeCQ+RLwAf2hQ8s7sv9OCLk6AHNgQvIrvbfzKCD76g/O6cu7lf/iER/aQGgy448pExZmhdegAPhR9sObFWH1gT3lp7DaA/5bkIgJhZPgsNmz02novj+KqeApj1ubwXWe4kdyeznAgNvTpE/HQmvKqOMeuFogTUVQSRno+iaLRLAJF7uIgL9O4ubgL8aWgB7S44mNX+35YpICUiAvS9sBLkq1WzT+NFffl6AuoiApi6NT37h6sWkBIRZGkQ8YtLgyji6e1mBYTqCEBPG2Naz+0BWQgtoGoRgCzEsd9hAN1X5BfnFZASUfrSAFQNsyZ1FJASUVpHiLinDJG8U2cBZYogkrcNs5waBAGdstbeU9zdqpw0gPwwSAI6VUxHyFlDpOcHUUBBIuYNs14aZAE5RVwyzPr3/0EAEY0TyfGNjBWQvwZ +CTSbehfAH29mrID8bET0+0EUkAd8WYDOmqJ3ecsG30yr9wqRfm6Y+a1BEFDEjHfHvWmY9ck6CygHvBVr8Xhtb4ZE5HZA3y8DvBNA1TjnrmXWf+sioMwZX5V/VHXMGGMMoKdDCxCRvRWBdzKzdHEO+EisilbPyopHYqp6S9UCAsz4iojI7hUDAtyXVQgIDd6KnOoaWNkbI6FaPSuZGyMArsi7MZoloB4zviI/Nhr3X95jltwTRQmoIfgisy5ai+me67OI7fE4nrqjrqfK1t0eby0FPRB6oGVlchL3rgnfrq19RKbVBdhV9IOSwJmfmJi4vi/4ThERitwyCxVAFqydshuCX5awhQ9KtmuIWd8IDZED/nXT77rvVVv6sHRKwjYi91poqP7Dr+Y6JJ1VSZIMA3wkPNy6bX+o8Bcm0sXMdwM8Fxo0A3xORPaWBp6uPXsmbxCRD0NDL0dOANhVCXy6iAjMcjbcrMt3RITKwdMVRdFo+y5yvkL4eWZ+zHt/ZVD4dEVRNGotpst+dZZZH8k86lqn2pIvT/eqrNfn2xuyqYPZ8mv7s8pfn/8Pybm4TIjanscAAAAASUVORK5CYII=") no-repeat center center;
+    background-size: 64px 64px;
+    position: absolute;
+    height: 100%;
+    width: 100%;
+    opacity: .8;
+    filter: alpha(opacity=80);
+    transition: all 0.2s ease-out;
+}
+
+.youtube .play:hover {
+    opacity: 1;
+    filter: alpha(opacity=100);
+}
diff --git a/shared/HtmlReady.js b/shared/HtmlReady.js
index 6889be81c4e0e2d0b943213ffc6179fa7d53a981..f82a22bb5d1088609257e1ee02fa63b90ede53ba 100644
--- a/shared/HtmlReady.js
+++ b/shared/HtmlReady.js
@@ -11,16 +11,16 @@ const XMLSerializer = new xmldom.XMLSerializer()
 /** Split the HTML on top-level elements. This allows react to compare separately, preventing excessive re-rendering.
  * Used in MarkdownViewer.jsx
  */
-export function sectionHtml (html) {
-  const doc = DOMParser.parseFromString(html, 'text/html')
-  const sections = Array(...doc.childNodes).map(child => XMLSerializer.serializeToString(child))
-  return sections
-}
+// export function sectionHtml (html) {
+//   const doc = DOMParser.parseFromString(html, 'text/html')
+//   const sections = Array(...doc.childNodes).map(child => XMLSerializer.serializeToString(child))
+//   return sections
+// }
 
 /** Embed videos, link mentions and hashtags, etc...
 */
-export default function (html, {large = false, mutate = true}) {
-    const state = {large, mutate}
+export default function (html, {mutate = true} = {}) {
+    const state = {mutate}
     state.hashtags = new Set()
     state.usertags = new Set()
     state.htmltags = new Set()
@@ -50,7 +50,7 @@ function traverse(node, state, depth = 0) {
             img(state, child)
         else if(/a/i.test(child.tagName))
             link(state, child)
-        else if(!embedYouTubeNode(child, state.large, state.links))
+        else if(!embedYouTubeNode(child, state.links))
             linkifyNode(child, state)
         traverse(child, state, ++depth)
     })
@@ -143,7 +143,7 @@ function linkify(content, mutate, hashtags, usertags, images, links) {
     return content
 }
 
-function embedYouTubeNode(child, large, links) {try{
+function embedYouTubeNode(child, links) {try{
     if(!child.data) return false
     const data = child.data
     if(/code/i.test(child.parentNode.tagName)) return false
@@ -152,10 +152,7 @@ function embedYouTubeNode(child, large, links) {try{
         const match = url.match(linksRe.youTubeId)
         if(match && match.length >= 2) {
             const id = match[1]
-            const src = `//www.youtube.com/embed/${id}?enablejsapi=0&rel=0&origin=https://steemit.com`
-            const w = large ? 640 : 384,
-                  h = large ? 360 : 240
-            const v = DOMParser.parseFromString(`<iframe width="${w}" height="${h}" src="${src}" frameBorder="0" allowFullScreen="true"></iframe>`)
+            const v = DOMParser.parseFromString(`~~~ youtube:${id} ~~~`)
             child.parentNode.replaceChild(v, child)
             replaced = true
             if(links) links.add(url)