Solari Browserdocs

Sessions

A session is a Chromium instance you drive with the standard Playwright API. Create, drive, release.

Lifecycle

launch() opens a session and connects the browser in one call. close() closes the browser and releases the session — safe to call from finally.

import { Solari } from "@solaribrowser/sdk"

const client = new Solari({ apiKey: process.env.SOLARI_API_KEY! })

const browser = await client.launch()
try {
  const page = await browser.newPage()
  await page.goto("https://example.com")

  await page.locator("h1").waitFor()
  console.log(await page.locator("h1").innerText())
} finally {
  await browser.close()
}

Bring your own client

If you're wiring Solari into Puppeteer, browser-use, or anything else that speaks raw Chrome DevTools Protocol, drop down to sessions.create() and connect to the session's CDP endpoint yourself.

const session = await client.sessions.create({ stealth: true })

// Any CDP client. Examples: playwright-core's connectOverCDP,
// puppeteer-core's connect, browser-use's BrowserSession.
const browser = await chromium.connectOverCDP(session.cdpEndpoint)

// ...drive the browser...

await browser.close()
await client.sessions.releaseAndWait(session.id)

The CDP endpoint has no version pinning to the pool — any recent CDP-compatible client works against it. The default launch() path uses Playwright's wire protocol under the hood for slightly lower per-action latency, with the SDK shipping its own version-matched client so you don't manage it.

Or connect via the wire protocol with wsEndpoint for slightly lower per-action latency.

const session = await client.sessions.create()
const browser = await chromium.connect(session.wsEndpoint)
Pin patchright-core to 1.59.3
The wire protocol requires a version-matched client. Pin patchright-core@1.59.3 in your project.

Options

Every option is opt-in. The default is a fast headless browser with no profile, recording, proxy, or stealth.

stealth

Enables full Chromium with a fingerprint shim. Required for proxy and captcha. See Stealth.

profileId

Hydrates cookies and localStorage from a saved profile before the first navigation. See Profiles.

recording

Captures every DOM mutation with rrweb and stores the replay in S3. See Session recording.

proxy

Managed proxy egress. proxy: "us" picks rotating residential; the object form lets you choose static ISP, mobile carrier, sticky sessions, or ASN. See Proxies.

captcha

Auto-solves reCaptcha v2/v3, hCaptcha, Turnstile, and others. See Captcha solving.

Full example

const browser = await client.launch({
  stealth: true,
  recording: true,
  captcha: true,
  profileId: "prof_abc123",
  proxy: { country: "us", session: "warmup-1", sessionDuration: 10 },
})

const page = await browser.newPage()
await page.goto("https://example.com")
await page.locator("button[type=submit]").click()
await browser.close()

Releasing

browser.close() closes the underlying browser and releases the session in one step — that's the path most callers want. If you used sessions.create() directly, release(id) is fire-and-forget and releaseAndWait(id) blocks until the release is confirmed (use it before reading getReplayUrl()).