Headless Chrome on Heroku

I’ve been experimenting with headless chrome for a Link Unshortener tool I’ve built to take screenshots of websites. I’ve been using BrowserShot which is great. It’s a php wrapper around Puppeteer which makes it simple to use in Laravel. To experiment more with Puppeteer, I wanted to get a node app running on Heroku. Overall it’s pretty straight forward but there are a few gotchas.

Here is a sample project that should get you started. Clone this and take a look at the source. You’ll notice I specified the node.js version in the package.json file. This is required for Heroku to know what version of node to use. Another issue I ran into is to run Puppeteer on Heroku you have to specify –no-sandbox. They last hurdle was adding the puppeteer Heroku buildpack. Follow the steps below and you should have a working screenshot app running locally and on Heroku. These instructions assume you are familiar with node and Heroku.

Setup Steps

  1. Clone sample project: git [email protected]:timleland/headless-chrome.git
  2. Make sure you are in the correct directory: cd headless-chrome
  3. Install node dependencies: npm install
  4. Run the app to test: npm start
  5. Open your browser to: http://localhost:8080/?url=google.com
  6. You should have download a png screenshot of google.com
  7. To deploy to Heroku make sure you have the Heroku cli tool installed 
  8. Create a new app on Heroku: heroku create APPNAMEHERE
  9. Add the puppeteer heroku buildpack: heroku buildpacks:add https://github.com/jontewks/puppeteer-heroku-buildpack
  10. Deploy to Heroku: git push heroku master
  11. Now just append the query string url=site.
  12. You should now have a working Heroku app that will screenshot any url you send it.

Leave your questions and feedback in the comments below.


48 thoughts to “Headless Chrome on Heroku”

      1. @Tim

        Yeah, sorry I meant: `heroku buildpacks:add heroku/nodejs` (Note the `add` instead of `set` as `set` seems to overwrite the existing buildpacks)


    1. I am using the same commands but it is giving me the following error ->
      Error: Failed to launch the browser process
      [20:20:0610/055305.613555:ERROR:browser_main_loop.cc(1425)] Unable to open X display.

  1. Hello!

    Thanks for the tutorial in the first place. I’ve followed the steps but I got the following error in my console:

    /app/node_modules/puppeteer/.local-chromium/linux-508693/chrome-linux/chrome: error while loading shared libraries: libcairo-gobject.so.2: cannot open shared object file: No such file or directory

    Do you know anything about this issue?

      1. I’ve already done that and it’s still not working. I’ve added the libcairo-gobject to the buildpack and I’ve managed to get it run.

  2. Thank you,.
    2018-01-08T21:50:44.412485+00:00 heroku[router]: at=error code=H14 desc=”No web processes running” method=GET path=”/?url=google.com” host=infinite-headland-44709.herokuapp.com request_id=85fa1725-7ee0-4404-bb19-8dd54fbfffbe fwd=”″ dyno= connect= service= status=503 bytes= protocol=https
    2018-01-08T21:50:44.862414+00:00 heroku[router]: at=error code=H14 desc=”No web processes running” method=GET path=”/favicon.ico” host=infinite-headland-44709.herokuapp.com request_id=46644015-4aed-4038-a941-80321c466eb0 fwd=”″ dyno= connect= service= status=503 bytes= protocol=https

    #2 Tried doing this
    heroku ps:scale web=1


    Scaling dynos… !
    ▸ Couldn’t find that process type.

    #4 Tried removing buildpacks
    heroku buildpacks:remove heroku/nodejs
    heroku buildpacks:remove https://github.com/jontewks/puppeteer-heroku-buildpack

    #5 Tried doing this now
    heroku ps:scale web=1


    Scaling dynos… !
    ▸ Couldn’t find that process type.

    Not sure if any issues with https://github.com/timleland/headless-chrome.git

  3. After following your instructions I’m getting this weird error when launching puppeteer:

    TypeError: input.on is not a function
    2018-01-19T06:16:08.710918+00:00 app[web.1]: at new Interface (readline.js:181:11)
    2018-01-19T06:16:08.710919+00:00 app[web.1]: at Object.createInterface (readline.js:64:10)
    2018-01-19T06:16:08.710922+00:00 app[web.1]: at waitForWSEndpoint (/app/node_modules/puppeteer/lib/Launcher.js:195:10)
    2018-01-19T06:16:08.710921+00:00 app[web.1]: at new Promise ()
    2018-01-19T06:16:08.710923+00:00 app[web.1]: at Function.launch (/app/node_modules/puppeteer/lib/Launcher.js:133:39)
    2018-01-19T06:16:08.710924+00:00 app[web.1]: at
    2018-01-19T06:16:08.805193+00:00 app[web.1]: events.js:183
    2018-01-19T06:16:08.805197+00:00 app[web.1]: throw er; // Unhandled ‘error’ event
    2018-01-19T06:16:08.710920+00:00 app[web.1]: at Promise (/app/node_modules/puppeteer/lib/Launcher.js:196:25)

    Any idea what’s going on? Your help is much appreciated :).

    1. For this example use “web: node app.js” as the example does not have an index.js, but an app.js 🙂

  4. Has anyone tried to start puppeteer with –proxy-server option on Heroku? I’m getting always timeout when attempting to connect (not a problem of the proxy, it works on my local env)


  5. For who is trying to make it work on heroku you need to launch puppeteer with the following options:

    puppeteer.launch({ headless: true, args:[‘–no-sandbox’, ‘–disable-setuid-sandbox’] })

    Also, make sure you call heroku buildpacks:add , not heroku buildpacks:set, set is removing all buildpacks you already have!

    1. I’m using puppeteer version 1.20.0 and the instructions are working for me, so yes.

      Importantly I also needed to add the Node buildpack mentioned in the comments, without it I was getting ‘node: command not found’ errors.

      My own application is running. But when I tried to run this one out of curiosity, I got an error:
      ‘No web processes running’
      Perhaps what’s needed is adding a Procfile with text: ‘web: node app.js’? Not sure, just an idea, really.

  6. Hi, I added the heroku build back and it shows up in the settings > buidpacks. However my app still wont run. When I run heroku logs –tail I get (node:4) UnhandledPromiseRejectionWarning: Error: Failed to launch chrome!
    2019-10-17T19:04:21.485029+00:00 app[worker.1]: /app/node_modules/puppeteer/.local-chromium/linux-686378/chrome-linux/chrome: error while loading shared libraries: libX11-xcb.so.1: cannot open shared object file: No such file or directory
    I have no idea what to do any help is appreciated thank you so much!
    ps in my main file I placed this code:
    const browser = puppeteer.launch({
    ‘args’: [
    If you have any questions or would like to see any more code feel free to contact me! Instagram: joey2031

    1. I had the exact same issue. Check out the URL error

      “/app/node_modules/puppeteer/.local-chromium/ –> linux-686378/chrome-linux/ <–"

      I noticed that this program wanted to use Chrome-linux, but I was using the Windows version of Chrome on WIndows! Also I noticed I was using the wrong version of Node. All I did was switch Operating Systems and now it works. Try running the program again in a Linux environment like Ubuntu or Fedora.

      Good luck!

  7. thanks, guys this code it’s worked!! 😀 only I say that add like say “DAN” and too Procfile web: node app.js

  8. I feel like I have tried everything suggested and still no luck.

    My launch:

    args: [‘–no-sandbox’, ‘–disable-setuid-sandbox’]

    I have these buildpack: https://github.com/jontewks/puppeteer-heroku-buildpack

    But still get this message:

    /app/node_modules/puppeteer/.local-chromium/linux-737027/chrome-linux/chrome: error while loading shared libraries: libgbm.so.1: cannot open shared object file: No such file or directory

    HELP, please!

  9. Hello TIM,

    Thanks for the article.

    But I have been trying to deploy my app on Heroku but it is still not working even after doing all these steps.

    My puppeteer lunch statement is as follows:

    const browser = await puppetter.launch({
    headless: true,
    args: [“–no-sandbox”,

    When I deploy it Just exits with the following error:

    Starting process with command `npm start`
    2020-10-13T16:33:17.284061+00:00 app[web.1]:
    2020-10-13T16:33:17.284089+00:00 app[web.1]: > [email protected] start /app
    2020-10-13T16:33:17.284089+00:00 app[web.1]: > node index
    2020-10-13T16:33:17.284089+00:00 app[web.1]:
    2020-10-13T16:33:17.795600+00:00 app[web.1]: Innitializing…..
    2020-10-13T16:33:17.795944+00:00 app[web.1]: Starting the server….
    2020-10-13T16:33:17.796003+00:00 app[web.1]: Server started..
    2020-10-13T16:33:17.796051+00:00 app[web.1]: Server Listening on port 4000
    2020-10-13T16:33:18.086323+00:00 app[web.1]: DB Connected successfully
    2020-10-13T16:33:18.790572+00:00 app[web.1]: Scraping Done
    2020-10-13T16:33:19.789613+00:00 app[web.1]: Scraping Done
    2020-10-13T16:33:20.857065+00:00 app[web.1]: Scraping Done
    2020-10-13T16:33:21.863133+00:00 app[web.1]: Scraping Done
    2020-10-13T16:33:22.064961+00:00 app[web.1]: events.js:291
    2020-10-13T16:33:22.064963+00:00 app[web.1]: throw er; // Unhandled ‘error’ event
    2020-10-13T16:33:22.064964+00:00 app[web.1]: ^
    2020-10-13T16:33:22.064965+00:00 app[web.1]:
    2020-10-13T16:33:22.064966+00:00 app[web.1]: Error: read ENOTCONN
    2020-10-13T16:33:22.064966+00:00 app[web.1]: at tryReadStart (net.js:575:20)
    2020-10-13T16:33:22.064967+00:00 app[web.1]: at Socket._read (net.js:586:5)
    2020-10-13T16:33:22.064967+00:00 app[web.1]: at Socket.Readable.read (_stream_readable.js:470:10)
    2020-10-13T16:33:22.064986+00:00 app[web.1]: at Socket.read (net.js:626:39)
    2020-10-13T16:33:22.064987+00:00 app[web.1]: at new Socket (net.js:378:12)
    2020-10-13T16:33:22.064987+00:00 app[web.1]: at Object.Socket (net.js:269:41)
    2020-10-13T16:33:22.064987+00:00 app[web.1]: at createSocket (internal/child_process.js:314:14)
    2020-10-13T16:33:22.064988+00:00 app[web.1]: at ChildProcess.spawn (internal/child_process.js:437:23)
    2020-10-13T16:33:22.064988+00:00 app[web.1]: at Object.spawn (child_process.js:553:9)
    2020-10-13T16:33:22.064989+00:00 app[web.1]: at BrowserRunner.start (/app/node_modules/puppeteer/lib/launcher/BrowserRunner.js:51:34)
    2020-10-13T16:33:22.064990+00:00 app[web.1]: at ChromeLauncher.launch (/app/node_modules/puppeteer/lib/Launcher.js:64:16)
    2020-10-13T16:33:22.064990+00:00 app[web.1]: at async localScrape (/app/Scraper/localScrape.js:10:22)
    2020-10-13T16:33:22.064990+00:00 app[web.1]: Emitted ‘error’ event on Socket instance at:
    2020-10-13T16:33:22.064991+00:00 app[web.1]: at emitErrorNT (internal/streams/destroy.js:92:8)
    2020-10-13T16:33:22.064991+00:00 app[web.1]: at emitErrorAndCloseNT (internal/streams/destroy.js:60:3)
    2020-10-13T16:33:22.064992+00:00 app[web.1]: at processTicksAndRejections (internal/process/task_queues.js:84:21) {
    2020-10-13T16:33:22.064992+00:00 app[web.1]: errno: ‘ENOTCONN’,
    2020-10-13T16:33:22.064993+00:00 app[web.1]: code: ‘ENOTCONN’,
    2020-10-13T16:33:22.064993+00:00 app[web.1]: syscall: ‘read’
    2020-10-13T16:33:22.064993+00:00 app[web.1]: }
    2020-10-13T16:33:22.079027+00:00 app[web.1]: npm ERR! code ELIFECYCLE
    2020-10-13T16:33:22.079442+00:00 app[web.1]: npm ERR! errno 1
    2020-10-13T16:33:22.088068+00:00 app[web.1]: npm ERR! [email protected] start: `node index`
    2020-10-13T16:33:22.088603+00:00 app[web.1]: npm ERR! Exit status 1
    2020-10-13T16:33:22.088605+00:00 app[web.1]: npm ERR!
    2020-10-13T16:33:22.088605+00:00 app[web.1]: npm ERR! Failed at the [email protected] start script.
    2020-10-13T16:33:22.088778+00:00 app[web.1]: npm ERR! This is probably not a problem with npm. There is likely additional logging output above.
    2020-10-13T16:33:22.097784+00:00 app[web.1]:
    2020-10-13T16:33:22.098004+00:00 app[web.1]: npm ERR! A complete log of this run can be found in:
    2020-10-13T16:33:22.098157+00:00 app[web.1]: npm ERR! /app/.npm/_logs/2020-10-13T16_33_22_089Z-debug.log
    2020-10-13T16:33:22.158923+00:00 heroku[web.1]: Process exited with status 1

  10. i made a discord bot and when im pushing it to a git repository because i want to host it on heroku
    its showing this error

    remote: Resolving deltas: 100% (201/201), done.
    remote: error: GH001: Large files detected. You may want to try Git Large File Storage – https://git-
    remote: error: Trace: 7d64b752d73168c3a6458afa6527db0648f1e315d28d8ec81702616a674ae731
    remote: error: See http://git.io/iEPt8g for more information.
    remote: error: File node_modules/puppeteer/.local-chromium/win64-818858/chrome-win/chrome.dll is
    138.94 MB; this exceeds GitHub’s file size limit of 100.00 MB
    remote: error: File node_modules/puppeteer/.local-chromium/win64-818858/chrome-
    win/interactive_ui_tests.exe is 141.87 MB; this exceeds GitHub’s file size limit of 100.00 MB
    To https://github.com/sanidhyajain1/discord-bot.git
    ! [remote rejected] master -> master (pre-receive hook declined)
    error: failed to push some refs to ‘https://github.com/sanidhyajain1/discord-bot.git’

  11. Hey. I followed the guide but I got this error when running:

    /app/node_modules/puppeteer/.local-chromium/linux-848005/chrome-linux/chrome: error while loading shared libraries: libnss3.so: cannot open shared object file: No such file or directory

    Can someone help me out?

  12. I put my project in herku but after 2 minutes im getting “Error R10 (Boot timeout) -> Web process failed to bind to $PORT within 60 seconds of launch”

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.