There is a lot of options and they all have their pro and cons.

Option 1: Use an API

  • ApiFlash (based on chrome)
  • EvoPDF (has an option for html)
  • Grabzit
  • HTML/CSS to Image API
  • ...

Pros

  • Execute Javascript
  • Near perfect rendering
  • Fast when caching options are correctly used
  • Scale is handled by the APIs
  • Precise timing, viewport, ...
  • Most of the time they offer a free plan

Cons

  • Not free if you plan to use them a lot

Option 2: Use one of the many available libraries

  • dom-to-image
  • wkhtmltoimage (included in the wkhtmltopdf tool)
  • IMGKit (for ruby and based on wkhtmltoimage)
  • imgkit (for python and based on wkhtmltoimage)
  • python-webkit2png
  • ...

Pros

  • Conversion is quite fast most of the time

Cons

  • Bad rendering
  • Does not execute javascript
  • No support for recent web features (FlexBox, Advanced Selectors, Webfonts, Box Sizing, Media Queries, ...)
  • Sometimes not so easy to install
  • Complicated to scale

Option 3: Use PhantomJs and maybe a wrapper library

  • PhantomJs
  • node-webshot (javascript wrapper library for PhantomJs)
  • ...

Pros

  • Execute Javascript
  • Quite fast

Cons

  • Bad rendering
  • No support for recent web features (FlexBox, Advanced Selectors, Webfonts, Box Sizing, Media Queries, ...)
  • Complicated to scale
  • Not so easy to make it work if there is images to be loaded ...

Option 4: Use Chrome Headless and maybe a wrapper library

  • Chrome Headless
  • chrome-devtools-protocol
  • Puppeteer (javascript wrapper library for Chrome headless)
  • ...

Pros

  • Execute Javascript
  • Near perfect rendering

Cons

  • Not so easy to have exactly the wanted result regarding:
    • page load timing
    • viewport dimensions
  • Complicated to scale
  • Quite slow and even slower if the html contains external links

Disclosure: I'm the founder of ApiFlash. I did my best to provide an honest and useful answer.


Yes. HTML2Canvas exists to render HTML onto <canvas> (which you can then use as an image).

NOTE: There is a known issue, that this will not work with SVG


May I recommend dom-to-image library, that was written solely to address this problem (I'm the maintainer).
Here is how you use it (some more here):

var node = document.getElementById('my-node');

domtoimage.toPng(node)
    .then (function (dataUrl) {
        var img = new Image();
        img.src = dataUrl;
        document.appendChild(img);
    })
    .catch(function (error) {
        console.error('oops, something went wrong!', error);
    });