Skip to content

Instantly share code, notes, and snippets.

@sachinraja
Created July 18, 2025 21:53
Show Gist options
  • Save sachinraja/f1125b230680849a76c6d06b4b790591 to your computer and use it in GitHub Desktop.
Save sachinraja/f1125b230680849a76c6d06b4b790591 to your computer and use it in GitHub Desktop.
browser-in-sandbox
import { Sandbox } from "@vercel/sandbox";
import z from 'zod';
import { chromium } from 'playwright'
export async function retryWithBackoff<T>(fn: () => Promise<T>, retries = 3) {
let delay = 1000;
for (let i = 0; i < retries; i++) {
try {
return await fn();
} catch {
await new Promise((resolve) => setTimeout(resolve, delay));
delay *= 2;
}
}
throw new Error("Failed to execute function after retries");
}
const cdpVersionSchema = z.object({
webSocketDebuggerUrl: z.string(),
});
const BROWSERS_DIR = "browsers";
const PORT = 9222;
async function setupSandbox(sandbox: Sandbox) {
console.log('Creating browsers directory...');
await sandbox.mkDir(BROWSERS_DIR);
const chromeRpmPath = `${BROWSERS_DIR}/google-chrome-stable_current_x86_64.rpm`;
console.log("Downloading Chrome RPM...");
const downloadRpm = await sandbox.runCommand({
cmd: "curl",
args: [
"https://dl.google.com/linux/direct/google-chrome-stable_current_x86_64.rpm",
"--output",
chromeRpmPath,
],
});
if (downloadRpm.exitCode !== 0) {
console.error("Failed to download Chrome RPM:", downloadRpm.stderr);
throw new Error("Chrome RPM download failed");
}
console.log("Installing Chrome...")
const installChrome = await sandbox.runCommand({
cmd: "dnf",
args: ["install", "-y", chromeRpmPath],
sudo: true,
});
if (installChrome.exitCode !== 0) {
console.error("Failed to install Chrome:", installChrome.stderr);
throw new Error("Chrome installation failed");
}
console.log("Starting Chrome...")
await sandbox.runCommand({
cmd: "google-chrome",
args: [
"--headless",
"--no-sandbox",
`--remote-debugging-port=${PORT}`,
"--remote-debugging-address=0.0.0.0",
],
detached: true,
});
console.log("Waiting for Chrome to start...");
// health check until the browser is ready
const fetchVersion = await retryWithBackoff(async () => {
const result = await sandbox.runCommand({
cmd: "curl",
args: [`-s`, `http://localhost:${PORT}/json/version`],
});
if (result.exitCode !== 0) {
throw new Error("Failed to fetch version");
}
return result;
});
const versionOutput = await fetchVersion.output();
const data = JSON.parse(versionOutput);
const { webSocketDebuggerUrl } = cdpVersionSchema.parse(data);
const url = new URL(webSocketDebuggerUrl);
const sandboxUrl = new URL(sandbox.domain(PORT));
const externalUrl = `wss://${sandboxUrl.host}${url.pathname}`;
console.log("Chrome started successfully. WebSocket URL:", externalUrl);
return externalUrl;
}
export async function createBrowserSandbox() {
console.log("Setting up sandbox...");
const sandbox = await Sandbox.create({
timeout: 300000,
ports: [PORT],
});
try {
const webSocketDebuggerUrl = await setupSandbox(sandbox);
return { sandbox, webSocketDebuggerUrl };
} catch (e) {
await sandbox.stop();
throw e;
}
}
async function main() {
const { sandbox, webSocketDebuggerUrl } = await createBrowserSandbox()
const browser = await chromium.connectOverCDP(webSocketDebuggerUrl)
const page = await browser.newPage()
await page.goto("https://nytimes.com")
await page.screenshot({ path: "headlines.png" })
await sandbox.stop()
}
main().catch(console.error);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment