puppeteer: Installation fails on Apple Silicon / M1

Steps to reproduce

  • Puppeteer version: 5.5.0
  • Platform / OS version: macOS Big Sur 11.0.1 (Apple Silicon)
  • Node.js version: 15.2.1

What steps will reproduce the problem?

  1. Install puppeteer using yarn or npm

What is the expected result? puppeteer gets installed

What happens instead? Installation fails.

error path-to-project/node_modules/puppeteer: Command failed.
Exit code: 1
Command: node install.js
Arguments:
Directory: path-to-project/node_modules/puppeteer
Output:
The chromium binary is not available for arm64:
If you are on Ubuntu, you can install with:

 apt-get install chromium-browser

path-to-project/node_modules/puppeteer/lib/cjs/puppeteer/node/BrowserFetcher.js:112
            throw new Error();
            ^

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Reactions: 138
  • Comments: 59 (2 by maintainers)

Commits related to this issue

Most upvoted comments

The solution for me using Chromium from Homebrew was:

brew install chromium
`which chromium`

You will get a security warning. Close it and go to System Preferences > Security & Privacy > General and click Open anyway.

Quit Chromium.

To ~/.zshrc add:

export PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true
export PUPPETEER_EXECUTABLE_PATH=`which chromium`

Then restart your terminal.

Edit: Thanks to @gwuah for clarifying that you may need to upgrade Puppeteer. puppeteer: ^9.1.1 should work.

A combination of steps from @chetbox and @Lxstr just worked for me. It involved creating a fork of puppeteer and changing a single line of source code. Here’s the exact steps for my project, in ~/Documents/my-project, where trying to install puppeteer gives me the following error:

The chromium binary is not available for arm64
  1. In Terminal, run export PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true. This will allow puppeteer to install.
  2. npm install puppeteer. It will skip trying to download chromium and install correctly.
  3. At this point, trying to run puppeteer (for me, using the command npm run test) gives the following error:
Error: Failed to launch the browser process! spawn /usr/bin/chromium-browser ENOENT
  1. brew install chromium. Run which chromium to make sure it installed properly, it should output the path to the new Chromium executable.

  2. In Terminal, run:

export PUPPETEER_EXECUTABLE_PATH=`which chromium`

Running export PUPPETEER_EXECUTABLE_PATH did not work for me on its own. This is because puppeteer currently hard-codes /usr/bin/chromium-browser in Launcher.ts (compiled to Launched.js) if it detects you’re on arm64. It doesn’t even bother to check the environment variables.

This is where I needed to fork puppeteer. I cloned it to ~/Documents/puppeteer and created a new branch.

  1. Open ~/Documents/puppeteer/src/node/Launcher.ts. Line 180 shows:
      if (os.arch() === 'arm64') {
        chromeExecutable = '/usr/bin/chromium-browser';
     } ....

This is where problem is with the hard-coded path. It immediately assumes where chromium-browser is located, which (at least for me) is not the case with Homebrew installs on Big Sur. The else part of this statement is where it checks your environment variables for configuration (like PUPPETEER_EXECUTABLE_PATH), but it never gets there if you’re on arm64.

By skipping this os.arch() === 'arm64' check, we force puppeteer to look for the environment variables. I just changed line 180 to below:

      if (false) {
        chromeExecutable = '/usr/bin/chromium-browser';
     } ....

Now we need to link our “forked” puppeteer to our original project. First install puppeteer dependencies…

  1. Still in ~/Documents/puppeteer, run npm install to install everything puppeteer needs. Make sure your export PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true is still set.
  2. npm run tsc to use the script in puppeteer’s package.json to compile the TypeScript. You need recompile anytime you make a change to the source code in ~/Documents/puppeteer.
  3. npm link to create a global npm “symlink” to your ~/Documents/puppeteer.
  4. Change directory back to your main project, for me it’s ~/Documents/my-project.
  5. npm link puppeteer to point my-project to your forked version of puppeteer.

npm run test again, and everything should work! As @chetbox suggested, you might add these to your ~/.zshrc~ to make sure your environment variables are set correctly when you re-open Terminal:

export PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true
export PUPPETEER_EXECUTABLE_PATH=`which chromium`

Hopefully this helps someone else from spending the many hours that I did trying to get this to work. This seems like it would be a pretty simple fix in puppeteer itself, so hopefully we get a real fix in a release soon. For anyone else that can’t wait for a release to run their tests, I hope this is a viable option without having to change anything in your own project.

After installing Chromium via Homebrew as described here I was getting this error when trying to start Chromium:

“Chromium” is damanged and can’t be opened. You should move it to the Trash

I found a solution here:

  xattr -rc /Applications/Chromium.app

why is this closed? It does not work today

Following on from the great tips above, you can pass the executablePath as an option to puppeteer.launch(), i.e.

const browser = await puppeteer.launch({
    executablePath: '/opt/homebrew/bin/chromium',
})

This saved me from having to do the fork/code change steps (step 6 onwards).

The solution for me using Chromium from Homebrew was:

brew install chromium
`which chromium`

You will get a security warning. Close it and go to System Preferences > Security & Privacy > General and click Open anyway.

Quit Chromium.

To ~/.zshrc add:

export PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true
export PUPPETEER_EXECUTABLE_PATH=`which chromium`

Then restart your terminal.

Edit: Thanks to @gwuah for clarifying that you may need to upgrade Puppeteer. puppeteer: ^9.1.1 should work.

Works great for me! One tiny change though: on Catalina and newer, you must disable Gatekeeper for Chromium to start properly, as I did not see the option to allow it on Privacy > General.

You can install Chromium with Gatekeeper disabled by running:

brew install --no-quarantine chromium

Or

brew reinstall --no-quarantine chromium

If you have installed it already.

Just curious whether this is planned to be ever fixed.

Any ETA on the release date?

I got Puppeteer to work just fine on M1 by providing the Chromium binary myself from https://commondatastorage.googleapis.com/chromium-browser-snapshots/index.html?prefix=Mac/818858/ (it’s the Intel build, but runs fine via Rosetta 2 – get chrome-mac.zip). You can point Puppeteer to it using the executablePath option in .launch(). Note that you need to point to /Contents/MacOS/Chromium inside the app bunde.

Due to the bug described in #6634, I also had to make a minor code adjustment in the launcher, see https://github.com/joshuajung/puppeteer/commit/7987b91069adafa260c8b795eab3b901847240f7.

For everyone still coming across this issue: The fix for this has been published for a few months now. Update your puppeteer dependency in your project to resolve it. Anything newer or equal to version 10.0.0 will do.

I wanted to write up how I was able to solve this, because it was a huge headache for me till I found the right pieces. I hope it can help someone else - here’s how I setup a new Mac Mini to work with CodeceptJS & Puppeteer

Key articles that helped me discover what to do:

  1. The first part of “Tips and tricks to set up your Apple M1 for development” by Chris Gradwohl
  2. “Running Cypress on the Apple M1 ARM Architecture using Rosetta 2” by Kevin Old

Once you’re ready for Node installs:

  • Open up Terminal and run: softwareupdate --install-rosetta --agree-to-license
  • Go to Finder -> Applications -> Utilities -> Duplicate the Terminal and for that Terminal instance (by right click -> select “Get Info”) checkmark “Open using Rosetta” [See article 1]
  • Open the Rosetta Terminal window and type arch - output should be: “i386” if it’s correctly using Rosetta
  • If the previous point has the correct outcome, then run: curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.37.2/install.sh | bash
  • You’ll either need to restart the terminal for the changes to take effect or run the command they indicate at the end of the install.
  • Run `nvm -v’ to make sure that it’s installed correctly
  • Run nvm install v14
  • Run node -v to make sure that it’s installed correctly
  • Run node -p 'process.arch - output should be: “x64” if the version installed is the Rosetta version. [If you see “arch64”, then the wrong version is installed. In that case, uninstall if you’re able, check to make sure you’re in the correct terminal, and go from there.]
  • Once you’re done with the above, cd into your project and run npm install or yarn install etc. in Rosetta Terminal to download packages.

After following the above steps, the npm install installed Puppeteer with Chromium as a part of the process (I didn’t have to install separately or set executablePath, etc.). Right afterwards, I was able to open and run my CodeceptJS test suites.

This is even more complicated if you’re trying to support local and Docker workflows multi-arch.

@gijo-varghese Nothing special, Node.js 12 and 14 is installed via nvm. The problem is Node 15, which is arm compiled and then it requires Chromium ARM.

I found the issue I was having and hopefully it can help others. Since this is day 1 on the m1, I installed as brew as arm in /opt/homebrew and set up /etc/path and .zshrc to use that dir for all the brew-installed things. Once you need to go back to using i86, you need to update /etc/path to use /usr/local/bin again and fix the references in .zshrc. I then installed nvm from the i86 version of homebrew and now it’s working correctly using Rosetta 2. Hope that helps others get this working.

I wanted to write up how I was able to solve this, because it was a huge headache for me till I found the right pieces. I hope it can help someone else - here’s how I setup a new Mac Mini to work with CodeceptJS & Puppeteer

Key articles that helped me discover what to do:

  1. The first part of “Tips and tricks to set up your Apple M1 for development” by Chris Gradwohl
  2. “Running Cypress on the Apple M1 ARM Architecture using Rosetta 2” by Kevin Old

Once you’re ready for Node installs:

  • Open up Terminal and run: softwareupdate --install-rosetta --agree-to-license
  • Go to Finder -> Applications -> Utilities -> Duplicate the Terminal and for that Terminal instance (by right click -> select “Get Info”) checkmark “Open using Rosetta” [See article 1]
  • Open the Rosetta Terminal window and type arch - output should be: “i386” if it’s correctly using Rosetta
  • If the previous point has the correct outcome, then run: curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.37.2/install.sh | bash
  • You’ll either need to restart the terminal for the changes to take effect or run the command they indicate at the end of the install.
  • Run `nvm -v’ to make sure that it’s installed correctly
  • Run nvm install v14
  • Run node -v to make sure that it’s installed correctly
  • Run node -p 'process.arch - output should be: “x64” if the version installed is the Rosetta version. [If you see “arch64”, then the wrong version is installed. In that case, uninstall if you’re able, check to make sure you’re in the correct terminal, and go from there.]
  • Once you’re done with the above, cd into your project and run npm install or yarn install etc. in Rosetta Terminal to download packages.

After following the above steps, the npm install installed Puppeteer with Chromium as a part of the process (I didn’t have to install separately or set executablePath, etc.). Right afterwards, I was able to open and run my CodeceptJS test suites.

Great solution, thank you!

It finally works when I follow the variable down the line and replace line 79 or BroswerRunner.js

    this.proc = childProcess.spawn("/Applications/Chromium.app/Contents/MacOS/Chromium", this._processArguments, 

This is what I’ve tried (after many circles) and installs but still doesn’t run PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=1 npm i puppeteer

Then find this file node_modules/puppeteer/lib/esm/puppeteer/node/Launcher.js

Replace line 54 with chromeExecutable = “/Applications/Brave Browser.app/Contents/MacOS/Brave Browser” (or any other)

See #6641

I’m having the same issue on a Raspberry Pi4 (also has arm64 chip).

Found this workaround (https://samiprogramming.medium.com/puppeteer-on-raspbian-nodejs-3425ccea470e) when running the 32bit os, but it fails when running the 64bit Raspian beta.

Managed to get puppeteer installed by using PUPPETEER_SKIP_CHROMIUM_DOWNLOAD, but still get this error,

(node:17769) UnhandledPromiseRejectionWarning: Error: Failed to launch the browser process! spawn /usr/bin/chromium-browser ENOENT

Puppeteer is using the path “/usr/bin/chromium-browser”, but my launch config is “executablePath: ‘/usr/bin/chromium’”

I know this is a Mac thread, but this discussion is the closest I’ve seen to my issue. Thanks!

Yup, what @steida says above. As long as you are running Node (or your whole shell) via Rosetta, Puppeteer doesn’t even notice it’s on ARM and is happy.

Once you use an ARM Node however (>= 15, built on an ARM Mac), you run into #6634 and need to supply Chromium yourself. Chromium can still be an Intel build, but Puppeteer will struggle to install and/or find it. For a workaround, see https://github.com/puppeteer/puppeteer/issues/6622#issuecomment-749069120.

Another solution that does not require rebuilding the puppeteer project is to use Patch Package

I just replace this in the Launcher.js files:

 if (os.arch() === 'arm64') {
  chromeExecutable = '/usr/bin/chromium-browser';
 }

with:

 if (os.arch() === 'arm64') {
   chromeExecutable = process.env.PUPPETEER_EXECUTABLE_PATH || '/usr/bin/chromium-browser';
 }

Here are the paths to the launcher files in my node_modules as of now: node_modules/puppeteer/lib/esm/puppeteer/node/Launcher.js node_modules/puppeteer/lib/cjs/puppeteer/node/Launcher.js

After that you can run npx patch-package puppeteer in the root of you project and it will create a diff patch for you in the projects ./patches directory.

If you include a postinstall npm script in you package.json

{
  ...
  "postinstall": "npx patch-package",
  ...
}

This will automatically apply with npm installs. This should make a commit-able change that you can push to your repo. Now anyone with an M1 will just need to add the env vars specified above to your shell rc file and make sure you installed chromium locally and you should be up and going.

brew install chromium
export PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true
export PUPPETEER_EXECUTABLE_PATH=`which chromium`

It is worth noting that this patch will only work as long as it does not conflict with what the maintainers have changed in future versions. It will tell you when the patch fails to apply in the future and you will have to go fix it yourself again manually.

I had this error message:

...
/Users/usern_name/path_to_repo/node_modules/puppeteer/lib/cjs/puppeteer/node/BrowserRunner.js:193
            reject(new Error([
                   ^

Error: Failed to launch the browser process! spawn /usr/bin/chromium-browser ENOENT


TROUBLESHOOTING: https://github.com/puppeteer/puppeteer/blob/main/docs/troubleshooting.md
...

I solved this problem by doing this:

  1. Installed Chromium via brew
$ brew install chromium
  1. Know the path location of the Chromium installation.
$ which chromium
/opt/homebrew/bin/chromium
  1. Search into the node_modules for this string: /usr/bin/chromium-browser. This is hardcoded for the 'arm64' processors in the Puppeteer code.
  2. Replace every usage of /usr/bin/chromium-browser for the one that which chromium prints.
  3. In my case I replaced /usr/bin/chromium-browser by /opt/homebrew/bin/chromium

Worked for the puppeteer@5.5.0 version, using a Macbook Pro M1 Max.

To improve on @Lxstr Solution, just add the following line to your .~/.zshrc file and restart your terminal:

export PUPPETEER_EXECUTABLE_PATH="/Applications/Brave Browser.app/Contents/MacOS/Brave Browser"

And now, no extra changes are needed in node_modules files

Note: You can use the binary of any chromium-based browser(like brave, opera etc).

For anyone on the mac m1 facing issues installing & using puppeteer, this is how I resolved my problems.

Step 1 - follow the exact steps provided here (https://github.com/puppeteer/puppeteer/issues/6622#issuecomment-787912758) by @chetbox Step 2 - upgrade your puppeteer version. I upgraded mine to puppeteer: ^9.1.1

hope this prevents someone else from also wasting 4hrs of their morning.

aside: this pull request (https://github.com/puppeteer/puppeteer/pull/7099) was the one that rectified the bug

Mac OS

Here is my working solution using puppeteer’s native chromium instead of installing your own:

  1. Uninstall puppeteer
  2. Open native terminal
  3. cd repo
  4. enter arch and see if it returns arm64
  5. enter nvm install stable
  6. enter nvm use stable
  7. verify installation by entering node -e 'console.log(process.arch)' and see if it returns arm64
  8. enter npm i puppeteer
  9. enter node node_modules/puppeteer/install.mjs (or node node_modules/puppeteer/install.js – depending on your node modules)
  10. it should work 🥳

@ReDrUm you should not use PUPPETEER_EXPERIMENTAL_CHROMIUM_MAC_ARM in docker. This flag for MacOS ARM. In docker, you have Linux so you need chromium for Linux.

To delete the quarantine attribute: xattr -d com.apple.quarantine /Applications/Chromium.app

Can anyone share a working Dockerfile using PUPPETEER_EXPERIMENTAL_CHROMIUM_MAC_ARM?

I’m building on an M1 using docker buildx build --push --platform linux/arm64 ... and i’ve tried both strategies below, but both error out with:

The chromium binary is not available for arm64. ... Failed to set up Chromium r1002410! Set "PUPPETEER_SKIP_DOWNLOAD" env variable to skip download.

FROM node:16.15.1-bullseye-slim

RUN apt-get update && apt-get install --no-install-recommends -yq dumb-init \
  # Install Chromium dependencies, necessary for running Puppeteer
  # Consult the Debian dependencies list for an updates when bumping Puppeteer or base images:
  # https://developers.google.com/web/tools/puppeteer/troubleshooting#chrome_headless_doesnt_launch_on_unix
  ca-certificates fonts-liberation libayatana-appindicator3-1 libasound2 libatk-bridge2.0-0 libatk1.0-0 libc6 libcairo2 \
  libcups2 libdbus-1-3 libexpat1 libfontconfig1 libgbm1 libgcc1 libglib2.0-0 libgtk-3-0 libnspr4 libnss3 \
  libpango-1.0-0 libpangocairo-1.0-0 libstdc++6 libx11-6 libx11-xcb1 libxcb1 libxcomposite1 libxcursor1 libxdamage1 \
  libxext6 libxfixes3 libxi6 libxrandr2 libxrender1 libxss1 libxtst6 lsb-release wget xdg-utils \
  && apt-get clean && apt-get autoremove -y && rm -rf /var/lib/apt/lists/*

# Attempt 1
ENV PUPPETEER_EXPERIMENTAL_CHROMIUM_MAC_ARM true
RUN yarn global add puppeteer@14.4.1

# Attempt 2
RUN export PUPPETEER_EXPERIMENTAL_CHROMIUM_MAC_ARM=true && yarn global add puppeteer@14.4.1

The expected arm64 build for 1002410 does exist here. It looks like puppeteer/lib/cjs/puppeteer/node/install.js doesn’t consider thePUPPETEER_EXPERIMENTAL_CHROMIUM_MAC_ARM variable at all, even under 14.x which is supposed to support Apple Silicon 🤷‍♂️

Does anyone have this working with the new native binaries? Or, am I misinterpreting the point of that env var and it’s only for running natively on an M1 mac directly rather than within a Linux based docker file?

The solution for me using Chromium from Homebrew was:

brew install chromium
`which chromium`

You will get a security warning. Close it and go to System Preferences > Security & Privacy > General and click Open anyway.

As of Big Sur 11.6.7, the control panel has changed. If you’re using the standard Apple Terminal, you should be good to go. But who uses that? 😃 I’m using iTerm. Here’s what worked for me:

  1. Quit iTerm
  2. Go into System Preferences -> Security & Privacy
  3. Scroll down to Developer Tools and click4.
  4. You’ll see the standard Apple Terminal listed in the list of apps “Allow the apps below to run software locally that does not meet the system’s security policy”.
  5. Add iTerm to that list.
  6. Restart iTerm

For everyone still coming across this issue: The fix for this has been published for a few months now. Update your puppeteer dependency in your project to resolve it. Anything newer or equal to version 10.0.0 will do. Thank you for your reply , the problem has been solved.

I was stuck in the same issue. I took puppeteer-core. https://www.npmjs.com/package/puppeteer-core Developers wrote: “Since version 1.7.0 we publish the puppeteer-core package, a version of Puppeteer that doesn’t download any browser by default.”

So install puppeteer-core, download chromium. After that point puppeteer to the installation of the browser. For example: const puppeteer = require('puppeteer-core'); const browser = await puppeteer.launch({ executablePath: '/Applications/Chromium.app/Contents/MacOS/Chromium', }) Have fun 😃

@SirasornT

But this gets me an error Error: Failed to launch the browser process! spawn /usr/bin/chromium-browser ENOENT.

Am I missing something here?

You probably didn’t patch Launcher.ts as described in https://github.com/joshuajung/puppeteer/commit/7987b91069adafa260c8b795eab3b901847240f7 yet (still required until the fix for #6634 is released).

brew install chromium --no-quarantine

I found the above line on reddit. So take with a grain of salt, but this was necessary to get which chromium to work.

set PUPPETEER_EXPERIMENTAL_CHROMIUM_MAC_ARM to true works for me (puppeteer@14.1.2). I like the fact that I don’t have to install chromium globally via brew, which makes it harder to manage

You can install any package using rosetta. To use rosetta just configure your terminal “open with rosetta”. If you are in a rosetta terminal you can npm i puppeteer without any problem. Once installed you can invoke your app from the same rosetta terminal or from your regular mac terminal.

Also note the arch command will show you which architecture your terminal is

image

For everyone still coming across this issue: The fix for this has been published for a few months now. Update your puppeteer dependency in your project to resolve it. Anything newer or equal to version 10.0.0 will do.

this did the trick

Found the exact issue regarding M1: https://github.com/puppeteer/puppeteer/issues/6957

Step 2 - upgrade your puppeteer version. I upgraded mine to puppeteer: ^9.1.1

@gwuah Thank you for saving me hours of work! 😄

For the record, I can run puppeteer inside a native ARM terminal with ARM node and chromium via rosetta. All I needed was the fixed installation path in puppeteer.

Hello @joshuajung . I am downloaded the chrome-mac.zip from the link you have provided and unzipped it to the root of my project. Then I did

import chromium from "chrome-aws-lambda";

module.exports = (async function () {
  const browser = await chromium.puppeteer.launch({
    args: [...chromium.args, "--hide-scrollbars", "--disable-web-security"],
    defaultViewport: chromium.defaultViewport,
    executablePath: "../../chrome-mac/Chromium.app/Contents/MacOS/Chromium",
    headless: true,
    ignoreHTTPSErrors: true,
  });

  return browser;
})();

But this gets me an error Error: Failed to launch the browser process! spawn /usr/bin/chromium-browser ENOENT. Am I missing something here?

@gijo-varghese It works OOTB with Rosetta. I did not have to change anything.