
How do I connect Puppeteer to Lightpanda Cloud using browserWSEndpoint, and how do I set the region?
Most Puppeteer stacks hit the same bottleneck in the cloud: Headless Chrome is slow to cold-start, heavy on memory, and expensive to scale when you’re driving hundreds or thousands of concurrent browser sessions. Lightpanda Cloud exists to fix exactly that, without forcing you to rewrite your scripts—Puppeteer just connects over CDP using browserWSEndpoint.
This guide shows, step by step, how to:
- Connect Puppeteer to Lightpanda Cloud using
browserWSEndpoint - Choose the right region (
euwestvsuswest) - Keep your existing Puppeteer code with minimal changes
- Layer on responsible crawling defaults
Quick overview: what changes in your Puppeteer code
In a regular Puppeteer setup you typically do:
import puppeteer from "puppeteer";
const browser = await puppeteer.launch({
headless: "new",
// ...other options
});
With Lightpanda Cloud, you don’t launch a local browser. Instead you connect to a managed, headless-only browser via CDP:
import puppeteer from "puppeteer-core";
const browser = await puppeteer.connect({
browserWSEndpoint: "wss://euwest.cloud.lightpanda.io/ws?token=YOUR_TOKEN",
});
// The rest of your script remains the same.
const page = await browser.newPage();
Everything else—page.goto, page.evaluate, selectors, waits—stays unchanged. You’re swapping the engine under the hood, not the way you write automation logic.
1. Prerequisites
Before you connect Puppeteer to Lightpanda Cloud, you’ll need:
- A Lightpanda Cloud account with an API token
- You’ll get a token from the Lightpanda console.
- Keep it secret; treat it like any other production credential.
- Node.js and Puppeteer in your project
- Prefer
puppeteer-corefor CDP-only setups:npm install puppeteer-core
- Prefer
- A region choice
euwest– typically better if your workloads or target sites are closer to Europe.uswest– typically better for US West / Americas–adjacent workloads.
Latency matters for automation. Running the browser closer to your target domains reduces total execution time (especially when you’re doing millions of pages a day).
2. Connect Puppeteer with browserWSEndpoint
The key primitive is puppeteer.connect({ browserWSEndpoint }).
Basic Cloud connection example
import puppeteer from "puppeteer-core";
async function main() {
const token = process.env.LPD_TOKEN; // store your token in env
if (!token) {
throw new Error("Missing LPD_TOKEN environment variable");
}
// Region: euwest (see next section for uswest)
const browserWSEndpoint =
`wss://euwest.cloud.lightpanda.io/ws?token=${token}`;
const browser = await puppeteer.connect({ browserWSEndpoint });
const page = await browser.newPage();
await page.goto("https://example.com", { waitUntil: "networkidle0" });
const title = await page.title();
console.log("Page title:", title);
await browser.close();
}
main().catch((err) => {
console.error(err);
process.exit(1);
});
Key points:
- Use
puppeteer.connect, notpuppeteer.launch. browserWSEndpointis a standard CDP WebSocket URL.- The
tokenis passed as a query parameter to authenticate your session. - Once connected, you use
browserexactly like in a local Puppeteer flow.
3. How to set the region (euwest vs uswest)
Region selection is encoded directly in the hostname of the browserWSEndpoint.
Region endpoints
You can currently choose between:
wss://euwest.cloud.lightpanda.io/wswss://uswest.cloud.lightpanda.io/ws
You append your token as a query parameter:
wss://euwest.cloud.lightpanda.io/ws?token=YOUR_TOKEN
wss://uswest.cloud.lightpanda.io/ws?token=YOUR_TOKEN
Region-aware Puppeteer config
A simple pattern is to parameterize the region via environment variables:
import puppeteer from "puppeteer-core";
async function main() {
const token = process.env.LPD_TOKEN;
if (!token) throw new Error("Missing LPD_TOKEN");
const region = process.env.LPD_REGION || "euwest"; // default to euwest
// Validate region
if (!["euwest", "uswest"].includes(region)) {
throw new Error(`Unsupported LPD_REGION: ${region}`);
}
const browserWSEndpoint =
`wss://${region}.cloud.lightpanda.io/ws?token=${token}`;
const browser = await puppeteer.connect({ browserWSEndpoint });
const page = await browser.newPage();
await page.goto("https://example.com", { waitUntil: "networkidle0" });
// Do your magic ✨
const html = await page.content();
console.log("HTML length:", html.length);
await browser.close();
}
main().catch((err) => {
console.error(err);
process.exit(1);
});
Now you can deploy the same code to different regions simply by changing LPD_REGION:
LPD_TOKEN=xxx LPD_REGION=euwest node index.js
LPD_TOKEN=xxx LPD_REGION=uswest node index.js
4. Migrating from a local Headless Chrome setup
If you’re currently spinning up Headless Chrome locally, the minimal diff to use Lightpanda Cloud looks like this.
Before: local launch
import puppeteer from "puppeteer";
async function main() {
const browser = await puppeteer.launch({
headless: "new",
args: ["--no-sandbox"],
});
const page = await browser.newPage();
await page.goto("https://example.com");
await browser.close();
}
After: Cloud connect with browserWSEndpoint
import puppeteer from "puppeteer-core";
async function main() {
const token = process.env.LPD_TOKEN;
if (!token) throw new Error("Missing LPD_TOKEN");
const region = process.env.LPD_REGION || "euwest";
const browserWSEndpoint =
`wss://${region}.cloud.lightpanda.io/ws?token=${token}`;
const browser = await puppeteer.connect({ browserWSEndpoint });
const page = await browser.newPage();
await page.goto("https://example.com");
await browser.close();
}
The rest of your Puppeteer script—navigation, scraping, testing flows—stays untouched. That’s deliberate: we built Lightpanda around CDP so you can keep your existing tooling and just change where the browser lives.
5. Why this matters for large-scale automation
When you’re automating at scale—crawling, testing, or driving agents—two numbers dominate your cloud bill and your reliability:
- Cold-start time: Every new browser process that takes multiple seconds to start becomes a tax you pay across thousands of sessions.
- Memory peak per browser: Multiply 200+ MB by hundreds of concurrent sessions and you quickly hit the ceiling of a single node or cluster.
Lightpanda Cloud runs a browser that was built from scratch in Zig, specifically for headless automation:
- No UI or rendering stack
- Instant startup
- Minimal memory footprint
In our own Puppeteer 100‑page benchmark on an AWS EC2 m5.large:
- Execution time: 2.3s with Lightpanda vs 25.2s with Headless Chrome
→ ~11× faster - Memory peak: 24MB vs 207MB
→ ~9× less memory
You feel these gains immediately when you switch your browserWSEndpoint from a local Chrome instance to a Lightpanda Cloud endpoint—and you don’t have to touch the rest of your script.
6. Responsible crawling with Lightpanda Cloud
Performance cuts both ways: when startup is instant and memory is low, it’s easy to accidentally overload a site.
When you connect Puppeteer to Lightpanda Cloud using browserWSEndpoint, keep the same operational hygiene you would with any large-scale crawler:
- Respect
robots.txt- In self-hosted Lightpanda you can enforce this with
--obey_robots. - In Cloud, implement checks at your job scheduler / URL queue level.
- In self-hosted Lightpanda you can enforce this with
- Throttle concurrency
- Limit per-domain concurrency and add small delays when necessary.
- DDOS-level traffic is trivial to generate by accident when your browser starts instantly.
- Centralize rate limits
- If you’re fanning out many Puppeteer workers, enforce global caps per target domain.
Lightpanda is optimized for scale, but scale needs guardrails.
7. Troubleshooting common connection issues
A few issues I’ve seen repeatedly when teams first connect Puppeteer to Lightpanda Cloud:
7.1 Invalid or missing token
Symptom: Connection fails immediately.
- Ensure the token is present:
echo $LPD_TOKEN - Confirm you’re passing it as a query parameter in the URL:
const browserWSEndpoint = `wss://euwest.cloud.lightpanda.io/ws?token=${token}`;
7.2 Wrong region hostname
Symptom: DNS errors or failed handshake.
- Check for typos:
- Correct:
wss://euwest.cloud.lightpanda.io/ws - Correct:
wss://uswest.cloud.lightpanda.io/ws
- Correct:
- Avoid stray slashes or missing
wss://.
7.3 Using puppeteer instead of puppeteer-core in minimal environments
While you can use puppeteer, I recommend puppeteer-core when you’re only connecting via CDP. It avoids bundling and managing a local Chrome binary you’re never going to launch.
npm install puppeteer-core
8. Putting it all together: a small “real-world” snippet
Here’s a compact, production-style script that:
- Selects region via env
- Connects using
browserWSEndpoint - Scrapes the
<title>tag for a list of URLs
import puppeteer from "puppeteer-core";
const URLs = [
"https://example.com",
"https://www.wikipedia.org",
];
async function run() {
const token = process.env.LPD_TOKEN;
if (!token) throw new Error("Missing LPD_TOKEN");
const region = process.env.LPD_REGION || "euwest";
if (!["euwest", "uswest"].includes(region)) {
throw new Error(`Unsupported region: ${region}`);
}
const browserWSEndpoint =
`wss://${region}.cloud.lightpanda.io/ws?token=${token}`;
const browser = await puppeteer.connect({ browserWSEndpoint });
try {
const page = await browser.newPage();
for (const url of URLs) {
await page.goto(url, { waitUntil: "networkidle0" });
const title = await page.title();
console.log(`[${region}] ${url} => ${title}`);
}
} finally {
await browser.close();
}
}
run().catch((err) => {
console.error(err);
process.exit(1);
});
If you want multi-region coverage, you can run this script in parallel with different LPD_REGION values, or factor region into your job queue.
9. Where this fits into your broader stack
Once Puppeteer is talking to Lightpanda Cloud over browserWSEndpoint, you can:
- Swap in Playwright or chromedp using the same CDP endpoint pattern:
- Playwright example from the docs:
import playwright from "playwright-core"; const browser = await playwright.chromium.connectOverCDP( "wss://euwest.cloud.lightpanda.io/ws?token=TOKEN", ); const context = await browser.newContext(); const page = await context.newPage();
- Playwright example from the docs:
- Mix Lightpanda and Chrome in the same infrastructure if you need Chrome for edge compatibility while keeping Lightpanda as the default for high-volume workloads.
- Move from Cloud to self-hosted (or vice versa) by just changing the
browserWSEndpointURL—fromwss://…cloud.lightpanda.io/wstows://127.0.0.1:9222, for example.
The connection primitive remains:
puppeteer.connect({ browserWSEndpoint: CDP_URL });
Everything else is just which browser engine sits on the other end of that WebSocket.
Next step
If you want to see how this feels in your own stack, wire up browserWSEndpoint to Lightpanda Cloud, set a region close to your workloads, and run one of your existing Puppeteer flows unchanged. That’s usually all it takes to experience instant startup and lower memory footprints in practice.