diff --git a/src/Clone.js b/src/Clone.js
index dec96b1..180980c 100644
--- a/src/Clone.js
+++ b/src/Clone.js
@@ -3,27 +3,39 @@
 import type {Bounds} from './Bounds';
 import type {Options} from './index';
 import type Logger from './Logger';
+import type {ImageElement} from './ImageLoader';
 
 import ImageLoader from './ImageLoader';
 import {copyCSSStyles} from './Util';
 import {parseBackgroundImage} from './parsing/background';
+import CanvasRenderer from './renderer/CanvasRenderer';
 
 export class DocumentCloner {
     scrolledElements: Array<[HTMLElement, number, number]>;
     referenceElement: HTMLElement;
     clonedReferenceElement: HTMLElement;
     documentElement: HTMLElement;
-    imageLoader: ImageLoader<string>;
+    imageLoader: ImageLoader<*>;
     logger: Logger;
+    options: Options;
     inlineImages: boolean;
     copyStyles: boolean;
+    renderer: (element: HTMLElement, options: Options, logger: Logger) => Promise<*>;
 
-    constructor(element: HTMLElement, options: Options, logger: Logger, copyInline: boolean) {
+    constructor(
+        element: HTMLElement,
+        options: Options,
+        logger: Logger,
+        copyInline: boolean,
+        renderer: (element: HTMLElement, options: Options, logger: Logger) => Promise<*>
+    ) {
         this.referenceElement = element;
         this.scrolledElements = [];
         this.copyStyles = copyInline;
         this.inlineImages = copyInline;
         this.logger = logger;
+        this.options = options;
+        this.renderer = renderer;
         this.imageLoader = new ImageLoader(options, logger, window);
         // $FlowFixMe
         this.documentElement = this.cloneNode(element.ownerDocument.documentElement);
@@ -90,6 +102,51 @@ export class DocumentCloner {
             }
         }
 
+        if (node instanceof HTMLIFrameElement) {
+            const tempIframe = node.cloneNode(false);
+            const iframeKey = generateIframeKey();
+            tempIframe.setAttribute('data-html2canvas-internal-iframe-key', iframeKey);
+
+            this.imageLoader.cache[iframeKey] = getIframeDocumentElement(node, this.options)
+                .then(documentElement => {
+                    return this.renderer(
+                        documentElement,
+                        {
+                            async: this.options.async,
+                            allowTaint: this.options.allowTaint,
+                            backgroundColor: '#ffffff',
+                            canvas: null,
+                            imageTimeout: this.options.imageTimeout,
+                            proxy: this.options.proxy,
+                            removeContainer: this.options.removeContainer,
+                            scale: this.options.scale,
+                            target: new CanvasRenderer(),
+                            type: 'view',
+                            windowWidth: documentElement.ownerDocument.defaultView.innerWidth,
+                            windowHeight: documentElement.ownerDocument.defaultView.innerHeight,
+                            offsetX: documentElement.ownerDocument.defaultView.pageXOffset,
+                            offsetY: documentElement.ownerDocument.defaultView.pageYOffset
+                        },
+                        this.logger.child(iframeKey)
+                    );
+                })
+                .then(canvas => {
+                    const iframeCanvas = document.createElement('img');
+                    iframeCanvas.src = canvas.toDataURL();
+                    if (tempIframe.parentNode) {
+                        tempIframe.parentNode.replaceChild(
+                            copyCSSStyles(
+                                node.ownerDocument.defaultView.getComputedStyle(node),
+                                iframeCanvas
+                            ),
+                            tempIframe
+                        );
+                    }
+                    return canvas;
+                });
+            return tempIframe;
+        }
+
         return node.cloneNode(false);
     }
 
@@ -99,11 +156,13 @@ export class DocumentCloner {
                 ? document.createTextNode(node.nodeValue)
                 : this.createElementClone(node);
 
-        if (this.referenceElement === node && clone instanceof HTMLElement) {
+        const window = node.ownerDocument.defaultView;
+
+        if (this.referenceElement === node && clone instanceof window.HTMLElement) {
             this.clonedReferenceElement = clone;
         }
 
-        if (clone instanceof HTMLBodyElement) {
+        if (clone instanceof window.HTMLBodyElement) {
             createPseudoHideStyles(clone);
         }
 
@@ -114,10 +173,10 @@ export class DocumentCloner {
                 }
             }
         }
-        if (node instanceof HTMLElement && clone instanceof HTMLElement) {
+        if (node instanceof window.HTMLElement && clone instanceof window.HTMLElement) {
             this.inlineAllImages(inlinePseudoElement(node, clone, PSEUDO_BEFORE));
             this.inlineAllImages(inlinePseudoElement(node, clone, PSEUDO_AFTER));
-            if (this.copyStyles) {
+            if (this.copyStyles && !(node instanceof HTMLIFrameElement)) {
                 copyCSSStyles(node.ownerDocument.defaultView.getComputedStyle(node), clone);
             }
             this.inlineAllImages(clone);
@@ -127,13 +186,11 @@ export class DocumentCloner {
             switch (node.nodeName) {
                 case 'CANVAS':
                     if (!this.copyStyles) {
-                        // $FlowFixMe
                         cloneCanvasContents(node, clone);
                     }
                     break;
                 case 'TEXTAREA':
                 case 'SELECT':
-                    // $FlowFixMe
                     clone.value = node.value;
                     break;
             }
@@ -248,14 +305,29 @@ const initNode = ([element, x, y]: [HTMLElement, number, number]) => {
     element.scrollTop = y;
 };
 
+const generateIframeKey = (): string =>
+    Math.ceil(Date.now() + Math.random() * 10000000).toString(16);
+
+const getIframeDocumentElement = (
+    node: HTMLIFrameElement,
+    options: Options
+): Promise<HTMLElement> => {
+    try {
+        return Promise.resolve(node.contentWindow.document.documentElement);
+    } catch (e) {
+        return Promise.reject();
+    }
+};
+
 export const cloneWindow = (
     ownerDocument: Document,
     bounds: Bounds,
     referenceElement: HTMLElement,
     options: Options,
-    logger: Logger
-): Promise<[HTMLIFrameElement, HTMLElement]> => {
-    const cloner = new DocumentCloner(referenceElement, options, logger, false);
+    logger: Logger,
+    renderer: (element: HTMLElement, options: Options, logger: Logger) => Promise<*>
+): Promise<[HTMLIFrameElement, HTMLElement, ImageLoader<ImageElement>]> => {
+    const cloner = new DocumentCloner(referenceElement, options, logger, false, renderer);
     const cloneIframeContainer = ownerDocument.createElement('iframe');
 
     cloneIframeContainer.className = 'html2canvas-container';
@@ -275,7 +347,7 @@ export const cloneWindow = (
         );
     }
     return new Promise((resolve, reject) => {
-        let cloneWindow = cloneIframeContainer.contentWindow;
+        const cloneWindow = cloneIframeContainer.contentWindow;
         const documentClone = cloneWindow.document;
 
         /* Chrome doesn't detect relative background-images assigned in inline <style> sheets when fetched through getComputedStyle
@@ -302,7 +374,11 @@ export const cloneWindow = (
                         cloner.clonedReferenceElement instanceof cloneWindow.HTMLElement ||
                         cloner.clonedReferenceElement instanceof HTMLElement
                     ) {
-                        resolve([cloneIframeContainer, cloner.clonedReferenceElement]);
+                        resolve([
+                            cloneIframeContainer,
+                            cloner.clonedReferenceElement,
+                            cloner.imageLoader
+                        ]);
                     } else {
                         reject(
                             __DEV__
diff --git a/src/Logger.js b/src/Logger.js
index bbdf241..c426805 100644
--- a/src/Logger.js
+++ b/src/Logger.js
@@ -3,9 +3,15 @@
 
 export default class Logger {
     start: number;
+    id: ?string;
 
-    constructor() {
-        this.start = Date.now();
+    constructor(id: ?string, start: ?number) {
+        this.start = start ? start : Date.now();
+        this.id = id;
+    }
+
+    child(id: string) {
+        return new Logger(id, this.start);
     }
 
     // eslint-disable-next-line flowtype/no-weak-types
@@ -15,7 +21,10 @@ export default class Logger {
                 .call(window.console.log, window.console)
                 .apply(
                     window.console,
-                    [Date.now() - this.start + 'ms', 'html2canvas:'].concat([].slice.call(args, 0))
+                    [
+                        Date.now() - this.start + 'ms',
+                        this.id ? `html2canvas (${this.id}):` : 'html2canvas:'
+                    ].concat([].slice.call(args, 0))
                 );
         }
     }
@@ -27,7 +36,10 @@ export default class Logger {
                 .call(window.console.error, window.console)
                 .apply(
                     window.console,
-                    [Date.now() - this.start + 'ms', 'html2canvas:'].concat([].slice.call(args, 0))
+                    [
+                        Date.now() - this.start + 'ms',
+                        this.id ? `html2canvas (${this.id}):` : 'html2canvas:'
+                    ].concat([].slice.call(args, 0))
                 );
         }
     }
diff --git a/src/NodeContainer.js b/src/NodeContainer.js
index 17a1f0c..d1558d3 100644
--- a/src/NodeContainer.js
+++ b/src/NodeContainer.js
@@ -239,6 +239,13 @@ const getImage = (
         case 'CANVAS':
             // $FlowFixMe
             return imageLoader.loadCanvas(node);
+        case 'DIV':
+            const iframeKey = node.getAttribute('data-html2canvas-internal-iframe-key');
+            if (iframeKey) {
+                console.log('ok');
+                return iframeKey;
+            }
+            break;
     }
 
     return null;
diff --git a/src/Window.js b/src/Window.js
new file mode 100644
index 0000000..07a8b5e
--- /dev/null
+++ b/src/Window.js
@@ -0,0 +1,131 @@
+/* @flow */
+'use strict';
+
+import type {Options} from './index';
+
+import Logger from './Logger';
+
+import {NodeParser} from './NodeParser';
+import Renderer from './Renderer';
+import ForeignObjectRenderer from './renderer/ForeignObjectRenderer';
+
+import Feature from './Feature';
+import {Bounds, parseDocumentSize} from './Bounds';
+import {cloneWindow, DocumentCloner} from './Clone';
+import {FontMetrics} from './Font';
+import Color, {TRANSPARENT} from './Color';
+
+export const renderElement = (
+    element: HTMLElement,
+    options: Options,
+    logger: Logger
+): Promise<*> => {
+    const ownerDocument = element.ownerDocument;
+
+    const windowBounds = new Bounds(
+        options.offsetX,
+        options.offsetY,
+        options.windowWidth,
+        options.windowHeight
+    );
+
+    const bounds = options.type === 'view' ? windowBounds : parseDocumentSize(ownerDocument);
+
+    // http://www.w3.org/TR/css3-background/#special-backgrounds
+    const documentBackgroundColor = ownerDocument.documentElement
+        ? new Color(getComputedStyle(ownerDocument.documentElement).backgroundColor)
+        : TRANSPARENT;
+    const bodyBackgroundColor = ownerDocument.body
+        ? new Color(getComputedStyle(ownerDocument.body).backgroundColor)
+        : TRANSPARENT;
+
+    const backgroundColor =
+        element === ownerDocument.documentElement
+            ? documentBackgroundColor.isTransparent()
+              ? bodyBackgroundColor.isTransparent()
+                ? options.backgroundColor ? new Color(options.backgroundColor) : null
+                : bodyBackgroundColor
+              : documentBackgroundColor
+            : options.backgroundColor ? new Color(options.backgroundColor) : null;
+
+    // $FlowFixMe
+    return Feature.SUPPORT_FOREIGNOBJECT_DRAWING.then(
+        supportForeignObject =>
+            supportForeignObject
+                ? (cloner => {
+                      if (__DEV__) {
+                          logger.log(`Document cloned, using foreignObject rendering`);
+                      }
+
+                      return cloner.imageLoader.ready().then(() => {
+                          const renderer = new ForeignObjectRenderer(cloner.clonedReferenceElement);
+                          return renderer.render({
+                              bounds,
+                              backgroundColor,
+                              logger,
+                              scale: options.scale
+                          });
+                      });
+                  })(new DocumentCloner(element, options, logger, true, renderElement))
+                : cloneWindow(
+                      ownerDocument,
+                      windowBounds,
+                      element,
+                      options,
+                      logger,
+                      renderElement
+                  ).then(([container, clonedElement, imageLoader]) => {
+                      if (__DEV__) {
+                          logger.log(`Document cloned, using computed rendering`);
+                      }
+
+                      const stack = NodeParser(clonedElement, imageLoader, logger);
+                      const clonedDocument = clonedElement.ownerDocument;
+                      const width = bounds.width;
+                      const height = bounds.height;
+
+                      if (backgroundColor === stack.container.style.background.backgroundColor) {
+                          stack.container.style.background.backgroundColor = TRANSPARENT;
+                      }
+
+                      return imageLoader.ready().then(imageStore => {
+                          if (options.removeContainer === true) {
+                              if (container.parentNode) {
+                                  container.parentNode.removeChild(container);
+                              } else if (__DEV__) {
+                                  logger.log(
+                                      `Cannot detach cloned iframe as it is not in the DOM anymore`
+                                  );
+                              }
+                          }
+
+                          const fontMetrics = new FontMetrics(clonedDocument);
+                          if (__DEV__) {
+                              logger.log(`Starting renderer`);
+                          }
+
+                          const renderOptions = {
+                              backgroundColor,
+                              fontMetrics,
+                              imageStore,
+                              logger,
+                              scale: options.scale,
+                              width,
+                              height
+                          };
+
+                          if (Array.isArray(options.target)) {
+                              return Promise.all(
+                                  options.target.map(target => {
+                                      const renderer = new Renderer(target, renderOptions);
+                                      return renderer.render(stack);
+                                  })
+                              );
+                          } else {
+                              const renderer = new Renderer(options.target, renderOptions);
+                              return renderer.render(stack);
+                          }
+                      });
+                  })
+    );
+};
diff --git a/src/index.js b/src/index.js
index b2e2476..017528c 100644
--- a/src/index.js
+++ b/src/index.js
@@ -3,17 +3,9 @@
 
 import type {RenderTarget} from './Renderer';
 
-import {NodeParser} from './NodeParser';
-import Renderer from './Renderer';
-import ForeignObjectRenderer from './renderer/ForeignObjectRenderer';
 import CanvasRenderer from './renderer/CanvasRenderer';
 import Logger from './Logger';
-import ImageLoader from './ImageLoader';
-import Feature from './Feature';
-import {Bounds, parseDocumentSize} from './Bounds';
-import {cloneWindow, DocumentCloner} from './Clone';
-import {FontMetrics} from './Font';
-import Color, {TRANSPARENT} from './Color';
+import {renderElement} from './Window';
 
 export type Options = {
     async: ?boolean,
@@ -58,118 +50,7 @@ const html2canvas = (element: HTMLElement, conf: ?Options): Promise<*> => {
         offsetY: defaultView.pageYOffset
     };
 
-    const options = {...defaultOptions, ...config};
-
-    const windowBounds = new Bounds(
-        options.offsetX,
-        options.offsetY,
-        options.windowWidth,
-        options.windowHeight
-    );
-
-    const bounds = options.type === 'view' ? windowBounds : parseDocumentSize(ownerDocument);
-
-    // http://www.w3.org/TR/css3-background/#special-backgrounds
-    const documentBackgroundColor = ownerDocument.documentElement
-        ? new Color(getComputedStyle(ownerDocument.documentElement).backgroundColor)
-        : TRANSPARENT;
-    const bodyBackgroundColor = ownerDocument.body
-        ? new Color(getComputedStyle(ownerDocument.body).backgroundColor)
-        : TRANSPARENT;
-
-    const backgroundColor =
-        element === ownerDocument.documentElement
-            ? documentBackgroundColor.isTransparent()
-              ? bodyBackgroundColor.isTransparent()
-                ? options.backgroundColor ? new Color(options.backgroundColor) : null
-                : bodyBackgroundColor
-              : documentBackgroundColor
-            : options.backgroundColor ? new Color(options.backgroundColor) : null;
-
-    // $FlowFixMe
-    const result = Feature.SUPPORT_FOREIGNOBJECT_DRAWING.then(
-        supportForeignObject =>
-            supportForeignObject
-                ? (cloner => {
-                      if (__DEV__) {
-                          logger.log(`Document cloned, using foreignObject rendering`);
-                      }
-
-                      return cloner.imageLoader.ready().then(() => {
-                          const renderer = new ForeignObjectRenderer(cloner.clonedReferenceElement);
-                          return renderer.render({
-                              bounds,
-                              backgroundColor,
-                              logger,
-                              scale: options.scale
-                          });
-                      });
-                  })(new DocumentCloner(element, options, logger, true))
-                : cloneWindow(
-                      ownerDocument,
-                      windowBounds,
-                      element,
-                      options,
-                      logger
-                  ).then(([container, clonedElement]) => {
-                      if (__DEV__) {
-                          logger.log(`Document cloned, using computed rendering`);
-                      }
-
-                      const imageLoader = new ImageLoader(
-                          options,
-                          logger,
-                          clonedElement.ownerDocument.defaultView
-                      );
-                      const stack = NodeParser(clonedElement, imageLoader, logger);
-                      const clonedDocument = clonedElement.ownerDocument;
-                      const width = bounds.width;
-                      const height = bounds.height;
-
-                      if (backgroundColor === stack.container.style.background.backgroundColor) {
-                          stack.container.style.background.backgroundColor = TRANSPARENT;
-                      }
-
-                      return imageLoader.ready().then(imageStore => {
-                          if (options.removeContainer === true) {
-                              if (container.parentNode) {
-                                  container.parentNode.removeChild(container);
-                              } else if (__DEV__) {
-                                  logger.log(
-                                      `Cannot detach cloned iframe as it is not in the DOM anymore`
-                                  );
-                              }
-                          }
-
-                          const fontMetrics = new FontMetrics(clonedDocument);
-                          if (__DEV__) {
-                              logger.log(`Starting renderer`);
-                          }
-
-                          const renderOptions = {
-                              backgroundColor,
-                              fontMetrics,
-                              imageStore,
-                              logger,
-                              scale: options.scale,
-                              width,
-                              height
-                          };
-
-                          if (Array.isArray(options.target)) {
-                              return Promise.all(
-                                  options.target.map(target => {
-                                      const renderer = new Renderer(target, renderOptions);
-                                      return renderer.render(stack);
-                                  })
-                              );
-                          } else {
-                              const renderer = new Renderer(options.target, renderOptions);
-                              return renderer.render(stack);
-                          }
-                      });
-                  })
-    );
+    const result = renderElement(element, {...defaultOptions, ...config}, logger);
 
     if (__DEV__) {
         return result.catch(e => {
diff --git a/tests/reftests/iframe.html b/tests/reftests/iframe.html
index e6a5cf1..1aa7f03 100644
--- a/tests/reftests/iframe.html
+++ b/tests/reftests/iframe.html
@@ -5,6 +5,7 @@
     <script type="text/javascript" src="../test.js"></script>
 </head>
 <body>
-<iframe src="/tests/assets/iframe/frame1.html" width="500" height="500"></iframe>
+    <div style="background: cornflowerblue; padding: 20px; width: 200px;">Parent document content</div>
+    <iframe src="/tests/assets/iframe/frame1.html" width="500" height="500"></iframe>
 </body>
 </html>