{"record":{"id":"03d676f87149d4de","repo":"apify/crawlee","slug":"failed-to-get-cdp-url-from-stagehand","errorCode":null,"errorMessage":"Failed to get CDP URL from Stagehand","messagePattern":"Failed to get CDP URL from Stagehand","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/stagehand-crawler/src/internals/stagehand-plugin.ts","lineNumber":101,"sourceCode":"                      proxy: anonymizedProxyUrl ? { server: anonymizedProxyUrl } : launchOptions.proxy,\n                      viewport: (launchOptions as Record<string, unknown>).viewport as {\n                          width: number;\n                          height: number;\n                      },\n                  }\n                : undefined,\n        };\n\n        const stagehand = new Stagehand(stagehandConfig);\n\n        try {\n            // Initialize Stagehand (launches browser)\n            await stagehand.init();\n\n            // Get CDP URL and connect Playwright to the same browser\n            const cdpUrl = stagehand.connectURL();\n            if (!cdpUrl) {\n                throw new Error('Failed to get CDP URL from Stagehand');\n            }\n\n            const browser = await chromium.connectOverCDP(cdpUrl);\n\n            // Store the Stagehand instance for AI operations\n            this.#stagehandInstances.set(browser, stagehand);\n\n            // Handle browser disconnection - cleanup both Stagehand and anonymized proxy\n            browser.on('disconnected', async () => {\n                await this.cleanupStagehand(browser);\n                await closeAnonymizedProxy();\n            });\n\n            return browser;\n        } catch (error) {\n            // Clean up on failure\n            await stagehand.close().catch(() => {});\n            await closeAnonymizedProxy();","sourceCodeStart":83,"sourceCodeEnd":119,"githubUrl":"https://github.com/apify/crawlee/blob/dbe57fb09ca607ad59dcf998f3925ef9ac3bb26c/packages/stagehand-crawler/src/internals/stagehand-plugin.ts#L83-L119","documentation":"In StagehandPlugin._launch(), after stagehand.init() the plugin asks Stagehand for a CDP endpoint via stagehand.connectURL() so Playwright can attach to the same browser. If connectURL() returns a falsy value (Stagehand did not expose an endpoint), the plugin throws because connecting without the URL is impossible.","triggerScenarios":"stagehand.connectURL() returning undefined/empty — typically when the Stagehand config uses LOCAL browser mode where connectURL is unsupported, an incompatible @browserbasehq/stagehand version, or init() partially failed leaving the browser endpoint unset.","commonSituations":"Upgrading stagehand where connectURL() semantics changed, running in environments where Stagehand falls back to a mode without a connectable endpoint (e.g. some local launch setups), or env vars forcing a non-CDP browser mode.","solutions":["Check the Stagehand version supports connectURL() and that it returns a ws/http endpoint after init()","Configure Stagehand to launch a connectable browser (CDP-capable local Chromium) — avoid configs that bypass an exposed endpoint","Log the cdpUrl after init() to see whether Stagehand reports one at all","Pin compatible versions of @browserbasehq/stagehand with @crawlee/stagehand-crawler","Ensure stagehand.init() completed without swallowed errors before connectURL()"],"exampleFix":"// before\nconst stagehand = new Stagehand({ env: 'LOCAL', browserbaseResolveWSEndpoint: false, /* non-CDP mode */ });\nawait stagehand.init();\n// after\nconst stagehand = new Stagehand({ env: 'LOCAL', /* default local chromium exposes CDP endpoint */ });\nawait stagehand.init();\nconst cdpUrl = stagehand.connectURL();\nif (!cdpUrl) throw new Error('connectURL unavailable for this stagehand config');","handlingStrategy":"validation","validationCode":"const cdpUrl = stagehand.connectURL();\nif (typeof cdpUrl !== 'string' || cdpUrl.length === 0) {\n    throw new Error('Stagehand did not expose a CDP URL; check env/config before launching the crawler');\n}","typeGuard":"const hasCdpUrl = (stagehand) => typeof stagehand?.connectURL === 'function' && !!stagehand.connectURL();","tryCatchPattern":"try {\n    await plugin._launch();\n} catch (err) {\n    if (err.message === 'Failed to get CDP URL from Stagehand') {\n        log.error('connectURL() empty — verify Stagehand mode/version supports CDP endpoints');\n    }\n    throw err;\n}","preventionTips":["Pin a Stagehand version known to support connectURL()","Use a browser mode that exposes a CDP endpoint (default local Chromium)","Log cdpUrl right after init() in CI smoke tests","Ensure init() succeeded before calling connectURL()"],"tags":["stagehand","cdp","browser-launch","compatibility"],"backgroundTag":"cdp-url-unavailable","analyzedSha":"dbe57fb09ca607ad59dcf998f3925ef9ac3bb26c","analyzedAt":"2026-08-30T22:22:28.328Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}