One of the major usages of PhantomJS is to capture web pages and render them as image. There are many rendering aspects which can be tweaked, the most popular one is the zoom factor, particularly useful to create thumbnails. A rather not-so-known parameter is the clipping rectangle which is very handy to limit the capture to a selected area only.

A common use of the clipping rectangle is when you need to track the position and the size of a particular element (likely via getBoundingClientRect) and render only that element. This is also what CasperJS offers in its convenient function captureSelector.

Another variant is to produce the semi-paginated version of a web page. Mostly on mobile, the user needs to scroll up and down (typically) and getting the feeling of the continuity of the contents is quite important. For example, the very first “page” needs to show a complete intro. If an important central image is cut into half, that does not give a good impression.

The following images shows the approximate rendering of BBC web site on mobile which looks really good: a full intro followed by a bunch of story summaries.


The script used to generated the two images above is shown here.

var page = require('webpage').create();
page.settings.userAgent = 'WebKit/534.46 Mobile/9A405 Safari/7534.48.3';
page.settings.viewportSize = { width: 400, height: 600 };
page.open('http://m.bbc.co.uk/news/business', function (status) {
    if (status !== 'success') {
        console.log('Unable to load BBC!');
    } else {
        window.setTimeout(function () {
            page.clipRect = { left: 0, top: 0, width: 400, height: 600 };
            page.clipRect = { left: 0, top: 600, width: 400, height: 600 };
        }, 2000);

It is rather simple, especially if you understand the screen capture use case of PhantomJS. The user agent tweak is necessary to ensure that the delivered page is the mobile version. Two images are produced, each corresponds to the first and second “page” the user is going to see. This is achieved by adjusting the top value to offset that page. Pretty straightforward!

What do you want to webclip today?

  • Asha12345

    The screen capture does not work on Jenkins though. It gives following error:
    -_RegisterApplication(), FAILED TO establish the default connection to the WindowServer, _CGSDefaultConnection() is NULL

    • http://ariya.ofilabs.com/ Ariya Hidayat

      Nothing to do with PhantomJS. All Mac Cocoa app will have the same problem. The workaround is to login (e.g. as the Jenkins user) and leave the session (don’t log out, just switch user if necessary).

  • Asha12345

    Thanks for the reply. However, same error is thrown even after login as a Jenkins user (https://wiki.jenkins-ci.org/display/JENKINS/Standard+Security+Setup). Any other workaround?

  • Fab

    Often getBoundingClientRect returns an incorrect value with PhantomJS. I am having issues with grabbing all the iframes and on certain sites it is consistently off. The code I use has no issues when run in Chrome’s console.