How do I get started with Lightpanda locally and expose a CDP server for my existing Playwright/Puppeteer scripts?
Headless Browser Infrastructure

How do I get started with Lightpanda locally and expose a CDP server for my existing Playwright/Puppeteer scripts?

10 min read

Most scraping and testing stacks today are bottlenecked by one thing: Headless Chrome cold starts in the cloud. Every new container or lambda spins up a full UI browser stack you never render, burns 200+ MB of RAM, and takes seconds to become usable. When you do this hundreds or thousands of times in parallel, cost and latency explode.

Lightpanda exists to fix that: an AI-native, headless-first browser built from scratch for machines, not humans. It speaks Chrome DevTools Protocol (CDP), so you can keep your existing Playwright or Puppeteer scripts and just point them at a different browser endpoint.

This guide walks you through running Lightpanda locally and exposing a CDP server so your existing Playwright/Puppeteer code “just connects” — with instant startup and a fraction of the memory footprint.


Why swap Chrome for Lightpanda in your CDP stack?

Before we touch commands, it’s worth being explicit about what changes when you put Lightpanda under your existing CDP scripts:

  • Instant startup instead of multi‑second cold starts
    In our Puppeteer 100‑page benchmark on an AWS EC2 m5.large, Lightpanda completed the run in ~2.3s vs 25.2s for Headless Chrome — roughly 11× faster.

  • Minimal memory instead of 200+ MB per browser
    The same test showed a memory peak of ~24 MB vs 207 MB for Headless Chrome — around 9× less memory per process.

  • Headless‑only, purpose‑built for automation
    No rendering stack, no UI baggage, no decades of desktop browser legacy. Just a machine browser that executes JavaScript and Web APIs, controlled entirely via CDP.

  • Drop‑in integration via CDP
    Lightpanda exposes a CDP server. You connect with:

    • browserWSEndpoint in Puppeteer
    • connectOverCDP / endpointURL in Playwright
      The rest of your script remains the same.

If you already have a CDP stack (Playwright, Puppeteer, chromedp), you don’t need to rewrite flows. You just swap the “browser under the hood.”


What you’ll set up locally

By the end of this guide you will:

  1. Install the Lightpanda browser locally.
  2. Start a Lightpanda CDP server on 127.0.0.1:9222.
  3. Connect Puppeteer to that server.
  4. Connect Playwright to that server.
  5. Cleanly start/stop the Lightpanda process from your Node.js script.

You’ll be ready to run your existing automation against a browser designed for cloud‑scale workloads.


Step 1 — Install Lightpanda locally

Lightpanda is distributed as a standalone binary and via the @lightpanda/browser helper for Node.js. The Node helper gives you a small API to spawn and manage the Lightpanda process directly from your test/scraping scripts.

  1. Install the Node helper:
npm install @lightpanda/browser --save-dev
# or
yarn add @lightpanda/browser --dev
  1. (If needed) Install the binary following the instructions on the Lightpanda site or GitHub. The @lightpanda/browser package expects lightpanda to be available on your PATH or will use its embedded binary if shipped for your platform.

Once this is in place, your Node.js script can start a local CDP server with a few lines of code.


Step 2 — Start a local CDP server from Node

The key concept: you don’t launch Playwright/Puppeteer’s bundled browser anymore. You launch Lightpanda, which exposes a CDP server, then connect your existing client to that server.

Lightpanda’s Node API gives you lightpanda.serve(options):

import { lightpanda } from '@lightpanda/browser';

const lpdopts = {
  host: '127.0.0.1',
  port: 9222,
};

(async () => {
  // Start Lightpanda browser in a separate process.
  const proc = await lightpanda.serve(lpdopts);

  console.log('🐼 Running Lightpanda\'s CDP server...', { pid: proc.pid });

  // Do your magic ✨  (CDP client connects here)

  // Stop Lightpanda browser process.
  proc.stdout.destroy();
  proc.stderr.destroy();
  proc.kill();
})();

This:

  • Starts Lightpanda listening on ws://127.0.0.1:9222.
  • Prints the process PID for debugging.
  • Gives you full control to cleanly terminate the browser when you’re done.

Now we plug Playwright or Puppeteer into that CDP endpoint.


Step 3 — Connect Puppeteer to the Lightpanda CDP server

If you’re running Puppeteer, you likely use something like puppeteer.launch() today. With Lightpanda, you don’t “launch Chromium” — you connect to an existing CDP endpoint.

3.1. Install puppeteer-core

Use puppeteer-core so you don’t pull in a large Chromium bundle you’re not going to use:

npm install puppeteer-core --save-dev
# or
yarn add puppeteer-core --dev

3.2. Wire Puppeteer to Lightpanda

Create or edit index.js:

'use strict';

import { lightpanda } from '@lightpanda/browser';
import puppeteer from 'puppeteer-core';

const lpdopts = {
  host: '127.0.0.1',
  port: 9222,
};

const puppeteeropts = {
  browserWSEndpoint: 'ws://' + lpdopts.host + ':' + lpdopts.port,
};

(async () => {
  // Start Lightpanda browser in a separate process.
  const proc = await lightpanda.serve(lpdopts);

  // Connect Puppeteer to the browser.
  const browser = await puppeteer.connect(puppeteeropts);
  const page = await browser.newPage();

  // Do your magic ✨
  await page.goto('https://news.ycombinator.com', { waitUntil: 'domcontentloaded' });
  console.log('CDP connection is working with Puppeteer + Lightpanda');

  // Cleanly disconnect Puppeteer.
  await page.close();
  await browser.disconnect();

  // Stop Lightpanda browser process.
  proc.stdout.destroy();
  proc.stderr.destroy();
  proc.kill();
})();

3.3. Run the script

node index.js

You should see something like:

$ node index.js
🐼 Running Lightpanda's CDP server... { pid: 4084512 }
CDP connection is working with Puppeteer + Lightpanda

Under the hood:

  • Puppeteer speaks CDP over browserWSEndpoint.
  • Lightpanda executes your navigation and JS in a lightweight, headless‑only runtime.
  • You get instant startup and a much smaller memory peak every time this script runs.

If you already have complex Puppeteer flows, the main change is replacing puppeteer.launch() with puppeteer.connect() and pointing at Lightpanda’s browserWSEndpoint.


Step 4 — Connect Playwright to the Lightpanda CDP server

Playwright also has native support for attaching to an existing browser via CDP. Instead of chromium.launch(), you use chromium.connectOverCDP() with Lightpanda’s endpointURL.

4.1. Install playwright-core

You only need playwright-core:

npm install playwright-core --save-dev
# or
yarn add playwright-core --dev

4.2. Wire Playwright to Lightpanda

Create or edit index.js:

'use strict';

import { lightpanda } from '@lightpanda/browser';
import { chromium } from 'playwright-core';

const lpdopts = {
  host: '127.0.0.1',
  port: 9222,
};

const playwrightopts = {
  endpointURL: 'ws://' + lpdopts.host + ':' + lpdopts.port,
};

(async () => {
  // Start Lightpanda browser in a separate process.
  const proc = await lightpanda.serve(lpdopts);

  // Connect using Playwright's chromium driver to the browser.
  const browser = await chromium.connectOverCDP(playwrightopts);
  const context = await browser.newContext({});
  const page = await context.newPage();

  // Do your magic ✨
  await page.goto('https://news.ycombinator.com', { waitUntil: 'domcontentloaded' });
  console.log('CDP connection is working with Playwright + Lightpanda');

  // Disconnect Playwright.
  await page.close();
  await context.close();
  await browser.close();

  // Stop Lightpanda browser process.
  proc.stdout.destroy();
  proc.stderr.destroy();
  proc.kill();
})();

4.3. Run the script

node index.js

Expected output:

$ node index.js
🐼 Running Lightpanda's CDP server... { pid: 31371 }
CDP connection is working with Playwright + Lightpanda

Everything else in your Playwright tests — selectors, assertions, fixtures — stays the same. The only structural change is swapping launch() for connectOverCDP() and using Lightpanda as the CDP server.


Step 5 — Controlling behavior via Lightpanda flags

Because Lightpanda is a headless‑only machine browser, the CLI is where you control low‑level behavior relevant to crawling, scraping, and testing at scale.

Some key flags you’ll commonly use when you scale beyond local:

  • --obey_robots
    When enabled, Lightpanda will fetch and obey robots.txt for the sites you crawl.

    Example:

    ./lightpanda serve --obey_robots
    

    Or via the Node helper (pass flags through your serve options) as your stack evolves.

  • Timeouts and networking behavior
    Lightpanda exposes flags to control transfer timeouts (e.g., a default of 10000 ms; 0 to never timeout). You’ll typically tune this when running large crawls to balance resilience and cost.

  • Proxy configuration
    When you move to the cloud or need geo/load distribution, you’ll use HTTP/SOCKS proxy settings (--http_proxy in CLI or proxy parameters in Cloud endpoints). Locally, this is often not needed, but it’s good to design your Playwright/Puppeteer setup so proxy configuration is a single variable, not hard‑coded.

These flags are part of what makes Lightpanda a better primitive for machine workloads: finer control over network behavior without carrying a full UI browser.


Step 6 — Responsible automation: robots.txt and rate limits

Running a browser that can spin up in milliseconds and consume ~24 MB of memory per process is powerful but also dangerous if misused. You can DDoS a target far faster than you might expect if you naively parallelize.

Keep these practices in your stack:

  • Respect robots.txt
    Use --obey_robots whenever you’re crawling the public web and don’t have an explicit agreement with the site owner.

  • Be rate‑aware
    Even with instant startup, implement delays and concurrency caps in your Playwright/Puppeteer code. Use queues and jitter backoff, and monitor response codes for throttling.

  • Isolate sessions
    Instead of reusing a single browser with shared cookies, take advantage of Lightpanda’s low memory to spin up many short‑lived, isolated sessions. This reduces cross‑tenant leakage and makes your system easier to reason about.

The same properties that lower your cloud bill also make high frequency requesting trivial; build guardrails into your code accordingly.


How this maps to your existing Playwright/Puppeteer stack

If you’re migrating an existing codebase, the minimal diff usually looks like:

For Puppeteer

Before (Chrome)

import puppeteer from 'puppeteer';

const browser = await puppeteer.launch({
  headless: 'new',
  // ...
});
const page = await browser.newPage();

After (Lightpanda via CDP)

import { lightpanda } from '@lightpanda/browser';
import puppeteer from 'puppeteer-core';

const lpdopts = { host: '127.0.0.1', port: 9222 };
const puppeteeropts = { browserWSEndpoint: 'ws://' + lpdopts.host + ':' + lpdopts.port };

const proc = await lightpanda.serve(lpdopts);
const browser = await puppeteer.connect(puppeteeropts);
const page = await browser.newPage();

Everything past newPage() can remain identical.

For Playwright

Before (Chromium)

import { chromium } from 'playwright';

const browser = await chromium.launch({ headless: true });
const context = await browser.newContext();
const page = await context.newPage();

After (Lightpanda via CDP)

import { lightpanda } from '@lightpanda/browser';
import { chromium } from 'playwright-core';

const lpdopts = { host: '127.0.0.1', port: 9222 };
const playwrightopts = { endpointURL: 'ws://' + lpdopts.host + ':' + lpdopts.port };

const proc = await lightpanda.serve(lpdopts);
const browser = await chromium.connectOverCDP(playwrightopts);
const context = await browser.newContext();
const page = await context.newPage();

Again, the rest of your test logic does not need to change.


When you’re ready to move from local to cloud

Running locally is the easiest way to validate compatibility and CDP behavior. Once you’re comfortable:

  • Use the same browserWSEndpoint/endpointURL pattern with Lightpanda Cloud.
  • Point your clients at region endpoints (e.g., wss://euwest.lightpanda.io?token=...).
  • Configure proxies via query parameters to control datacenter and country where traffic exits.
  • Keep the same connect / connectOverCDP flow; only the ws://127.0.0.1:9222 URL changes to a wss:// Cloud endpoint.

Because the local browser and Cloud product both speak CDP and are driven by the same machine‑first design, migration is mostly a matter of swapping connection strings.


Summary

To get started with Lightpanda locally and expose a CDP server for your existing Playwright/Puppeteer scripts:

  1. Install @lightpanda/browser (and puppeteer-core and/or playwright-core).
  2. Start Lightpanda with lightpanda.serve({ host: '127.0.0.1', port: 9222 }).
  3. Connect Puppeteer using browserWSEndpoint or Playwright using connectOverCDP / endpointURL.
  4. Keep your test and scraping logic the same; only the browser bootstrapping changes.
  5. Add flags like --obey_robots and timeouts as you scale out, and be deliberate about concurrency.

You end up with the same CDP automation surface, but backed by a browser that was actually designed to run in the cloud — with instant startup, ~9× less memory, and a much simpler operational profile.

Next Step

Get Started