One line connects
Swap launch() for connect() pointed at our WebSocket. Nothing else changes.
const browser = await chromium.connectOverCDP(
`wss://cdp-lb.axiom.ai/?token=${process.env.AXIOM_API_KEY}`
);
The Chrome API gives you cloud browsers that connect to your existing Puppeteer, Playwright, or CDP code. One long-lived WebSocket per session. No Chromium to install. No servers to manage.
1import { chromium } from "playwright";2 3const browser = await chromium.connectOverCDP(4 `wss://cdp-lb.axiom.ai/?token=${process.env.AXIOM_API_KEY}`5);6 7try {8 const context = browser.contexts()[0];9 const page = context.pages()[0] ?? await context.newPage();10 await page.goto("https://example.com");11 await page.screenshot({ path: "out.png", fullPage: true });12} finally {13 await browser.close();14}Connect
Instead of launching Chrome locally, your script connects to one of ours over a WebSocket. The rest of the script stays the same.
Swap launch() for connect() pointed at our WebSocket. Nothing else changes.
const browser = await chromium.connectOverCDP(
`wss://cdp-lb.axiom.ai/?token=${process.env.AXIOM_API_KEY}`
);
Puppeteer, Playwright's connectOverCDP, Python, Go, or raw WebSocket frames.
Raw CDP, not a wrapper SDK. Every click, wait, and selector stays yours.
Point your script back at launch() and it runs locally again.
In practice
The endpoint is the same in all three. Point Playwright at it with connectOverCDP, point Puppeteer at it with connect, or call a Step API function on the browser you connected to and delete the loop you were about to write.
Playwright over CDP
connectOverCDP takes the same endpoint, and locators, tracing, and assertions all keep working.
Explore Playwright
const browser = await chromium.connectOverCDP(
`wss://cdp-lb.axiom.ai/?token=${KEY}`
);
const ctx = browser.contexts()[0];
const page = ctx.pages()[0] ?? await ctx.newPage();
await page.goto("https://example.com");
await page.getByRole("button",
{ name: "Accept" }).click();
Puppeteer over CDP
puppeteer.connect points at the same WebSocket, so your selectors, waits, and evaluate calls keep working.
Explore Puppeteer
const browser = await puppeteer.connect({
browserWSEndpoint:
`wss://cdp-lb.axiom.ai/?token=${KEY}`
});
const [page] = await browser.pages();
await page.goto("https://example.com");
await page.click("button.accept");
CDP plus a step
Step API functions run on the browser you connected to. scrape takes the selector for the data, the next-page button, and how many rows you want, then does the waiting and paging itself. Twenty of them cover the jobs you would otherwise write out, captchas and date pickers included.
Explore the Step API
// your own interception, on your terms
await page.setRequestInterception(true);
page.on("request", r =>
r.url().endsWith(".png") ? r.abort() : r.continue());
await page.goto("https://example.com/list");
// one call instead of a paging loop
const rows = await axiom.scrape(
null, ".row", ".next", 500, {});
Run
We run the browsers, keep them patched, and queue the work. You open a connection when you need one and pay for the minutes it stays open.
Every session gets clean, current cloud Chrome. No installs, no version drift between environments.
More parallel work means more connections. We handle concurrency and queueing on our infrastructure.
Runtime only meters while a session is open. No idle servers.
Query your allowance, minutes used, and minutes remaining over the API.
Docs
Quickstarts, worked examples, and full endpoint references for each layer. Start with the quickstart, generate a key, and build from there.
Start with the quickstartGet an API key and try the Chrome API for free.
2 free hours of runtime. No card required.