Generating live website thumbnail previews using an Iframe

I was looking for a good way to generate website thumbnail previews for the end-user which would load near instantly. With a quick Google search I came across services that can take a screenshot but they were neither free or fast. So I set out to create my own home brewed solution which looked something like this:

I’m going to use KnockoutJS which is a MVVM JavaScript framework for the purpose of this demo just for the convenience factor. You can do this in plain old JavaScript as well if you wanted to.

TL;DR: Scroll to the bottom for a link to the demo


<div class="live-example">
  <input data-bind='value: myURL' />
  <button data-bind='click: initLinkPreview'>Show Preview</button>
  <!-- ko if: showPreview -->
  <iframe class="link-preview" data-bind="attr: {target: '_top', src: myURL}" sandbox='' scrolling="no" />
  <!-- /ko -->

Key part to note in the HTML is that we are loading the iFrame in a sandbox mode to make sure it loads the link with a white-list of restrictions to mitigate any risk of malicious activity.


.live-example {
  height: 200px !important;
  overflow: hidden;
.link-preview {
  width: 1028px;
  height: 800px;
  border: none;
  pointer-events: none;
  -webkit-transform: scale(0.2);
  -moz-transform: scale(0.2);
  -ms-transform: scale(0.2);
  transform: scale(0.2);
  -webkit-transform-origin: 0 0;
  -moz-transform-origin: 0 0;
  -ms-transform-origin: 0 0;
  transform-origin: 0 0;

The main crux of this technique comes down to the transform CSS property which will allow us to render the URL in a full sized iFrame and then scale it down to a smaller size to make it look like a thumbnail. Also as you can see, the container class .live-example has a height restriction of 200px to hide the space that the browser will initially occupy to render a full-sized iFrame.


def get_headers
  meta = open(params[:url]) { |f| f.meta }
  render :json => {status: "success", headers: meta}

I also created a back-end endpoint (in this case in RoR) to return the website headers to the front-end. This is to allow the front-end to detect if the site which we are loading allows itself to be rendered in an iFrame. Lot of mainstream sites such as Google and Yahoo explicitly set X-Frame-Options header to avoid Clickjacking attacks, etc. By doing this we can control the UX and make sure we either show a default thumbnail or hide the area in which we were supposed to render the iFrame in case the X-Frame-Options header was set to DENY or SAMEORIGIN.


var MyViewModel = function MyViewModel() {
  var self = this;
  self.myURL = ko.observable();
  self.showPreview = ko.observable();

  self.initLinkPreview = function () {
      type: "POST",
      url: "/get_headers/url=?" + self.myURL(),
      success: function (data) {
        var headers = data.headers;
        if (headers['x-frame-options'] && (headers['x-frame-options'].toUpperCase() == 'DENY' || headers['x-frame-options'].toUpperCase() == 'SAMEORIGIN')) {
        } else {


ko.applyBindings(new MyViewModel());

So lastly the JS ties everything together. It grabs the URL from the front-end, checks with back-end to see if it’s kosher to render it in an iFrame and then either shows or hides the iFrame with that URL.


If you have any questions or comments, please post them below. If you liked this post, you can share it with your followers or follow me on Twitter!