I am using Puppeteer in my Node.js project, and it works perfectly fine on my local machine. However, after deploying the project to Azure, I am encountering issues where Puppeteer does not seem to function properly.
Issue:
The error message I get is:
Could not find Chrome (ver. 131.0.6778.85). This can occur if either
1. you did not perform an installation before running the script (e.g. `npx puppeteer browsers install chrome`) or
2. your cache path is incorrectly configured (which is: /root/.cache/puppeteer).
For (2), check out our guide on configuring puppeteer at /guides/configuration.
This suggests that Puppeteer is unable to locate a Chromium instance in the Azure environment.
Environment Details:
Local Machine: Works fine without any issues.
Azure Deployment: Fails to find Chrome.
Steps I Have Tried:
Installing Puppeteer with Chromium:
npm install puppeteer
Setup the api
app.get("/_api/screenshot", async (req, res) => {
try {
// Get the URL from query string, default to example if not provided
const targetUrl = req.query.url || ";;
console.log("Starting browser launch...");
// Launch Puppeteer with necessary arguments for cloud environments
const browser = await puppeteer.launch({
headless: true,
args: [
"--no-sandbox",
"--disable-setuid-sandbox",
"--disable-dev-shm-usage",
"--single-process",
"--no-zygote",
],
// Use the path from environment variable or let Puppeteer find it
executablePath: process.env.PUPPETEER_EXECUTABLE_PATH,
});
console.log("Browser launched successfully");
const page = await browser.newPage();
console.log("Navigating to:", targetUrl);
// Navigate to the target URL and wait until network is idle
await page.goto(targetUrl, { waitUntil: "networkidle0" });
console.log("Page loaded, taking screenshot");
// Take a screenshot as a base64 string
const screenshotBuffer = await page.screenshot({ encoding: "base64" });
console.log("Screenshot taken, closing browser");
await browser.close();
// Return the screenshot as an HTML image
res.send(`<img src="data:image/png;base64,${screenshotBuffer}" />`);
} catch (error) {
console.error("Error in /api/screenshot:", error);
res.status(500).json({
error: "Failed to take screenshot",
message: error.message,
stack: error.stack,
puppeteerInfo: process.env.PUPPETEER_EXECUTABLE_PATH || "No path set",
});
}
});
But still getting the above error
Note: We're using the Github workflow to deploy the updated code to Azure, if anyone know or have done this please let us know what will be proper method to do this, would be great help :)
Following is my .yml file
name: app-name
on:
push:
branches:
- main
workflow_dispatch:
jobs:
build:
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- uses: actions/checkout@v4
- name: Cache Node modules
uses: actions/cache@v3
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
- name: Set up Node.js version
uses: actions/setup-node@v3
with:
node-version: "22.x"
- name: Install dependencies
run:
npm ci
# Add the Prepare for Puppeteer step here
- name: Prepare for Puppeteer
run: |
npm uninstall puppeteer-core
npm install puppeteer
npx puppeteer browsers install chrome
echo "PUPPETEER_EXECUTABLE_PATH=$(node -e 'console.log(require(\"puppeteer\").executablePath())')" >> .env
- name: Create startup script
run: |
echo '#!/bin/bash
echo "Listing directory contents to debug:"
ls -la /home/site/wwwroot
echo ""
echo "Installing Chrome dependencies..."
apt-get update && apt-get install -y \
libx11-xcb1 \
libxcomposite1 \
libxcursor1 \
libxdamage1 \
libxi6 \
libxtst6 \
libnss3 \
libcups2 \
libxss1 \
libxrandr2 \
libasound2 \
libatk1.0-0 \
libatk-bridge2.0-0 \
libpangocairo-1.0-0 \
libgtk-3-0 \
libgbm1
echo "Starting Node.js application..."
# Try server.js first, fall back to index.js, then try app.js
if [ -f "/home/site/wwwroot/server.js" ]; then
node server.js
elif [ -f "/home/site/wwwroot/index.js" ]; then
node index.js
elif [ -f "/home/site/wwwroot/app.js" ]; then
node app.js
else
echo "No main entry file found. Looking for JavaScript files:"
find /home/site/wwwroot -name "*.js" -type f | head -10
exit 1
fi' > startup.sh
chmod +x startup.sh
- name: Zip artifact for deployment
run: zip release.zip . -r
- name: Upload artifact for deployment job
uses: actions/upload-artifact@v4
with:
name: node-app
path: release.zip
deploy:
runs-on: ubuntu-latest
needs: build
environment:
name: "Production"
url: ${{ steps.deploy-to-webapp.outputs.webapp-url }}
permissions:
id-token: write
contents: read
steps:
- name: Download artifact from build job
uses: actions/download-artifact@v4
with:
name: node-app
- name: Login to Azure
uses: azure/login@v2
with:
client-id: ${{ secrets.AZUREAPPSERVICE_CLIENTID_ }}
tenant-id: ${{ secrets.AZUREAPPSERVICE_TENANTID_ }}
subscription-id: ${{ secrets.AZUREAPPSERVICE_SUBSCRIPTIONID_2F56DD }}
- name: "Deploy to Azure Web App"
id: deploy-to-webapp
uses: azure/webapps-deploy@v3
with:
app-name: "app-name"
slot-name: "Production"
package: release.zip
- name: Configure startup command
uses: azure/[email protected]
with:
inlineScript: |
az webapp config set --resource-group AppName --name project_name --startup-file "bash startup.sh"
I am using Puppeteer in my Node.js project, and it works perfectly fine on my local machine. However, after deploying the project to Azure, I am encountering issues where Puppeteer does not seem to function properly.
Issue:
The error message I get is:
Could not find Chrome (ver. 131.0.6778.85). This can occur if either
1. you did not perform an installation before running the script (e.g. `npx puppeteer browsers install chrome`) or
2. your cache path is incorrectly configured (which is: /root/.cache/puppeteer).
For (2), check out our guide on configuring puppeteer at https://pptr.dev/guides/configuration.
This suggests that Puppeteer is unable to locate a Chromium instance in the Azure environment.
Environment Details:
Local Machine: Works fine without any issues.
Azure Deployment: Fails to find Chrome.
Steps I Have Tried:
Installing Puppeteer with Chromium:
npm install puppeteer
Setup the api
app.get("/_api/screenshot", async (req, res) => {
try {
// Get the URL from query string, default to example if not provided
const targetUrl = req.query.url || "https://example";
console.log("Starting browser launch...");
// Launch Puppeteer with necessary arguments for cloud environments
const browser = await puppeteer.launch({
headless: true,
args: [
"--no-sandbox",
"--disable-setuid-sandbox",
"--disable-dev-shm-usage",
"--single-process",
"--no-zygote",
],
// Use the path from environment variable or let Puppeteer find it
executablePath: process.env.PUPPETEER_EXECUTABLE_PATH,
});
console.log("Browser launched successfully");
const page = await browser.newPage();
console.log("Navigating to:", targetUrl);
// Navigate to the target URL and wait until network is idle
await page.goto(targetUrl, { waitUntil: "networkidle0" });
console.log("Page loaded, taking screenshot");
// Take a screenshot as a base64 string
const screenshotBuffer = await page.screenshot({ encoding: "base64" });
console.log("Screenshot taken, closing browser");
await browser.close();
// Return the screenshot as an HTML image
res.send(`<img src="data:image/png;base64,${screenshotBuffer}" />`);
} catch (error) {
console.error("Error in /api/screenshot:", error);
res.status(500).json({
error: "Failed to take screenshot",
message: error.message,
stack: error.stack,
puppeteerInfo: process.env.PUPPETEER_EXECUTABLE_PATH || "No path set",
});
}
});
But still getting the above error
Note: We're using the Github workflow to deploy the updated code to Azure, if anyone know or have done this please let us know what will be proper method to do this, would be great help :)
Following is my .yml file
name: app-name
on:
push:
branches:
- main
workflow_dispatch:
jobs:
build:
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- uses: actions/checkout@v4
- name: Cache Node modules
uses: actions/cache@v3
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
- name: Set up Node.js version
uses: actions/setup-node@v3
with:
node-version: "22.x"
- name: Install dependencies
run:
npm ci
# Add the Prepare for Puppeteer step here
- name: Prepare for Puppeteer
run: |
npm uninstall puppeteer-core
npm install puppeteer
npx puppeteer browsers install chrome
echo "PUPPETEER_EXECUTABLE_PATH=$(node -e 'console.log(require(\"puppeteer\").executablePath())')" >> .env
- name: Create startup script
run: |
echo '#!/bin/bash
echo "Listing directory contents to debug:"
ls -la /home/site/wwwroot
echo ""
echo "Installing Chrome dependencies..."
apt-get update && apt-get install -y \
libx11-xcb1 \
libxcomposite1 \
libxcursor1 \
libxdamage1 \
libxi6 \
libxtst6 \
libnss3 \
libcups2 \
libxss1 \
libxrandr2 \
libasound2 \
libatk1.0-0 \
libatk-bridge2.0-0 \
libpangocairo-1.0-0 \
libgtk-3-0 \
libgbm1
echo "Starting Node.js application..."
# Try server.js first, fall back to index.js, then try app.js
if [ -f "/home/site/wwwroot/server.js" ]; then
node server.js
elif [ -f "/home/site/wwwroot/index.js" ]; then
node index.js
elif [ -f "/home/site/wwwroot/app.js" ]; then
node app.js
else
echo "No main entry file found. Looking for JavaScript files:"
find /home/site/wwwroot -name "*.js" -type f | head -10
exit 1
fi' > startup.sh
chmod +x startup.sh
- name: Zip artifact for deployment
run: zip release.zip . -r
- name: Upload artifact for deployment job
uses: actions/upload-artifact@v4
with:
name: node-app
path: release.zip
deploy:
runs-on: ubuntu-latest
needs: build
environment:
name: "Production"
url: ${{ steps.deploy-to-webapp.outputs.webapp-url }}
permissions:
id-token: write
contents: read
steps:
- name: Download artifact from build job
uses: actions/download-artifact@v4
with:
name: node-app
- name: Login to Azure
uses: azure/login@v2
with:
client-id: ${{ secrets.AZUREAPPSERVICE_CLIENTID_ }}
tenant-id: ${{ secrets.AZUREAPPSERVICE_TENANTID_ }}
subscription-id: ${{ secrets.AZUREAPPSERVICE_SUBSCRIPTIONID_2F56DD }}
- name: "Deploy to Azure Web App"
id: deploy-to-webapp
uses: azure/webapps-deploy@v3
with:
app-name: "app-name"
slot-name: "Production"
package: release.zip
- name: Configure startup command
uses: azure/[email protected]
with:
inlineScript: |
az webapp config set --resource-group AppName --name project_name --startup-file "bash startup.sh"
Share
Improve this question
edited Mar 13 at 8:32
Akshay Pagare
asked Mar 13 at 6:50
Akshay PagareAkshay Pagare
1523 silver badges10 bronze badges
2
|
1 Answer
Reset to default 1I've created a sample Node.js
project using Puppeteer
to launch a headless browser and take a screenshot of a webpage.
I got the same issue when I deployed to Azure App Service, to resolve the issue I've added the below startup command in the configuration section of my web app.
apt-get update && apt-get install -y wget && wget -q -O - https://dl.google/linux/linux_signing_key.pub | apt-key add - && echo "deb [arch=amd64] http://dl.google/linux/chrome/deb/ stable main" | tee /etc/apt/sources.list.d/google-chrome.list && apt-get update && apt-get install -y google-chrome-stable && node server.js
Add the below environment variables in your Azure app service.
server.js:
require("dotenv").config();
const express = require("express");
const puppeteer = require("puppeteer");
const fs = require("fs");
const app = express();
const PORT = process.env.PORT || 3000;
app.get("/screenshot", async (req, res) => {
try {
const targetUrl = req.query.url || "https://example";
console.log("Launching Puppeteer...");
const browser = await puppeteer.launch({
headless: "new",
args: [
"--no-sandbox",
"--disable-setuid-sandbox",
"--disable-dev-shm-usage",
"--single-process",
"--no-zygote",
],
executablePath: process.env.PUPPETEER_EXECUTABLE_PATH || puppeteer.executablePath(),
});
const page = await browser.newPage();
await page.goto(targetUrl, { waitUntil: "networkidle0" });
const screenshotPath = "screenshot.png";
await page.screenshot({ path: screenshotPath });
await browser.close();
res.sendFile(screenshotPath, { root: __dirname }, (err) => {
if (err) {
console.error("Error sending file:", err);
res.status(500).json({ error: "Failed to send screenshot" });
} else {
console.log("Screenshot successfully sent.");
}
});
} catch (error) {
console.error("Error:", error);
res.status(500).json({ error: error.message });
}
});
app.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
});
Workflow file:
name: Build and deploy Node.js app to Azure Web App - puppetternode18
on:
push:
branches:
- main
workflow_dispatch:
jobs:
build:
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- uses: actions/checkout@v4
- name: Set up Node.js version
uses: actions/setup-node@v3
with:
node-version: '20.x'
- name: Install system dependencies for Puppeteer
run: |
sudo apt-get update
sudo apt-get install -y google-chrome-stable \
libnss3 libxss1 libasound2t64 libatk1.0-0 \
libatk-bridge2.0-0 libcups2 libdrm2 libgbm1 \
libgtk-3-0 libnspr4 libxcomposite1 libxcursor1 \
libxdamage1 libxfixes3 libxrandr2 libxrender1 \
libxshmfence1
- name: Set Puppeteer environment variables
run: |
echo "PUPPETEER_SKIP_DOWNLOAD=false" >> $GITHUB_ENV
echo "PUPPETEER_EXECUTABLE_PATH=/usr/bin/google-chrome-stable" >> $GITHUB_ENV
- name: Install dependencies, build, and test
run: |
npm install
npm run build --if-present
npm run test --if-present
- name: Zip artifact for deployment
run: zip release.zip ./* -r
- name: Upload artifact for deployment job
uses: actions/upload-artifact@v4
with:
name: node-app
path: release.zip
deploy:
runs-on: ubuntu-latest
needs: build
environment:
name: 'Production'
url: ${{ steps.deploy-to-webapp.outputs.webapp-url }}
steps:
- name: Download artifact from build job
uses: actions/download-artifact@v4
with:
name: node-app
- name: Unzip artifact for deployment
run: unzip release.zip
- name: 'Deploy to Azure Web App'
id: deploy-to-webapp
uses: azure/webapps-deploy@v3
with:
app-name: 'puppetternode18'
slot-name: 'Production'
package: .
publish-profile: ${{ secrets.AZUREAPPSERVICE_PUBLISHPROFILE_705EF5D45F054804AA01E0B93B6AF9D7 }}
I've successfully deployed my application to Azure app service via GitHub actions.
Production output:
.yml
file. – Sirra Sneha Commented Mar 13 at 7:17