Skip to main content
Reproduce the failure with one browser and keep it open for inspection. Record the request status, error body, and x-cloud-tracing-uuid response header before changing configuration.

Find the failing step

The browser will not start

A 401 not_authorized usually means the API token is absent or invalid. Send it as X-Cloud-Api-Token and use the base URL assigned to your account. A namespace_not_allowed error means the request reached a host that does not serve the account. For proxy tier selection, see choosing the tier. "tier": "shared" is for testing only and is not intended for production; use "tier": "premium" in production. With the shared tier, only country is accepted. Sending type, region, city, pool, asn, lat and lon, or a session field such as session_minutes returns 422 validation_error with the message the shared tier targets 'country' only. For other 422 validation_error responses, inspect data for the field that failed. Creating a persistent profile requires a title and a fingerprint with an OS; starting a one-time session has different defaults. See errors for the full code list. Avoid retrying a timed-out start without checking whether it created a browser.

The site is blocking you

Confirm that you received a block or challenge page. HTTP 200 alone does not prove that the expected content loaded.

Start with the proxy

Compare the same small test through another suitable proxy while keeping other settings unchanged. Check the exit country, connection type, and whether the IP changes during a session. A residential or mobile IP may behave differently from a datacenter IP, but no proxy type guarantees access. If the job runs on "tier": "shared", switch to "tier": "premium" before comparing anything else. The shared tier is for testing only and is not intended for production. Keep the IP stable when the site ties a login or challenge to it. More restrictive targeting can reduce availability; see proxies.

Check fingerprint overrides

Remove unnecessary overrides and retest. If you set language, timezone, user agent, screen, or device fields manually, make sure they describe the browser you intend to use. See fingerprints.

Tune the fingerprint

If the block persists with default settings, try another OS. Some sites treat desktop and mobile traffic differently, and a fresh profile with a different device can pass where the current one does not:

Check the automation client

Make sure your Playwright or Puppeteer code does not override the browser: user agent, viewport, locale, timezone, or device emulation set by the framework replace parts of the profile’s fingerprint. Connect with the defaults. Use a patched build of Playwright or Puppeteer, such as Patchright or rebrowser. Do not use the framework’s default interactions for clicks, typing, and scrolling; use Human commands instead.

Keep the page intact

Detection scripts can inspect changes to window, document, navigator, and the DOM, including redefined properties and wrapped native functions. Do not use stealth plugins or other anti-detection libraries with Surfsky: their overrides can conflict with the browser’s fingerprint configuration or introduce detectable changes. Check your own init scripts for the same problems.

Check the request pattern

Reduce concurrency and repeat a single user flow. Wait for each page state before triggering the next action. Use Human commands for input and follow Human behavior for action order and timing. Compare the results after each change. Test navigation through the site’s search, menus, or internal links if opening the target URL directly fails. Where the task allows, vary the route between sessions. If the target requires many navigation steps and the site allows it, you can change an existing internal link’s destination and click it. The navigation then originates from that page. This modifies the DOM and may be detected (see Keep the page intact), so test it on the target first. If a challenge appears, confirm the selected CAPTCHA solver is enabled and observe its completion or failure events.

Keep a profile that got through

On a well-protected site a browser is often let in only after a proof-of-work check, a CAPTCHA, or a few pages of ordinary browsing. A one-time profile has to earn that again on every start, and each attempt is a fresh chance to be blocked. Once a session gets through, keep it. Run such jobs on a persistent profile with cookies enabled, plus local storage if the site keeps its clearance there. Stop the session through the API so the state is saved, then start the same profile for the next run. The site sees a returning browser with valid cookies instead of a new one to challenge. Keep the proxy stable for that profile. A clearance tied to one IP is useless from another; see session control.

Sessions that will not stay logged in

Work through the checklist in cookies for storage options, browser context, and expired logins. Two causes come from session handling:
  • The profile was still running. Starting a running profile returns the existing session and ignores the settings in the new request, so a proxy, fingerprint, or storage change appears to have no effect. Check GET /profiles/active, stop the session, then start again.
  • The previous session ended in a crash or infrastructure failure. An explicit stop and an inactivity stop both save the enabled storage. A crash does not, so anything done after the last saved stop is lost.
Importing cookies alone may not reproduce a login that depends on other browser state. Open the Network panel and identify which request or page condition never completed. networkidle may never occur on a site with continuous background traffic. Try domcontentloaded followed by a selector that proves the required content is ready. Check request blocking: a blocked script, API endpoint, or challenge resource can leave the page incomplete. Increasing the timeout will not restore a resource you prevented from loading. A wait that outlives the inactivity timeout ends with a closed target, not a timeout error from your framework. The Scraping API returns 400 scrape_timeout when the whole request exceeds 120 seconds. Its per-page timeout option, 30000 ms by default, applies to each navigation or selector wait inside that budget. Keep batches and wait conditions within it.

The browser stopped by itself

A browser stops after browser_settings.inactive_kill_timeout seconds without activity. The default is 30 seconds; the maximum is 3600. Activity means CDP commands sent by your client, ChromeDriver requests, and Scraping API calls. A connection that sends nothing, an idle DevTools tab, and a screencast viewer do not count. One long client-side wait can be a single CDP command. A waitForSelector with a 60-second timeout under the default setting can fail with Target closed because the browser stopped at 30 seconds. Raise the timeout for such waits and for manual inspection:
A longer timeout also leaves an abandoned browser running, and counting against your concurrency limit, for longer. See how a session ends.

CDP errors and disconnections

These messages can occur during normal tab closure or cleanup. Treat them as harmless only if the expected work already completed. During an active job, check whether the page closed, the browser crashed, the inactivity timeout expired, or another worker stopped the session. Use GET /profiles/active to confirm the browser still exists. A stopped session’s connection URL will not restart it: the WebSocket opens and closes at once with the reason Profile not found. Start a session and use the returned URL.

Page limit

The browser already has five automation-created pages. The limit is per browser and shared by every CDP client connected to it. It counts Target.createTarget calls, including ones still in flight. The initial tab and popups opened by the site are not counted. A slot is released when your client closes the page or the browser destroys it. Close pages you no longer need, or reuse one. For independent parallel work, use separate browsers within your account’s concurrency limit.

Everything feels slow

Measure startup, navigation, interaction, and extraction separately. Check speed optimization for reducing commands, waits, and downloads. Increase concurrency only while completed results improve. For framework-specific connection and cleanup details, use the Playwright, Puppeteer, or Selenium quickstart.

Reporting a problem

Send support:
  • A minimal request or script that reproduces the failure.
  • The HTTP status, error response, and x-cloud-tracing-uuid header.
  • The approximate time in UTC and the API host used.
  • The expected page result and what happened instead.
Share the internal_uuid privately if support needs the session identifier. Remove API tokens, proxy passwords, cookies, provider keys, and live connection URLs before sharing logs or screenshots.