From 21a26a9a72879aa38e6e12651412467fed48ca49 Mon Sep 17 00:00:00 2001 From: Paul Irish Date: Sat, 12 Sep 2026 13:16:22 -0700 Subject: [PATCH 1/2] docs: add authoritative http and websocket endpoints reference from chromium sources --- src/index.html | 468 ++++++++++++++++++++++++++++++++++++++++++++----- src/style.css | 61 +++++++ 2 files changed, 490 insertions(+), 39 deletions(-) diff --git a/src/index.html b/src/index.html index 142b9a52c..36a285015 100644 --- a/src/index.html +++ b/src/index.html @@ -290,8 +290,7 @@

- Can I get the protocol as JSON? - # + Can I get the protocol as JSON? #

@@ -344,76 +343,467 @@

HTTP Endpoints #

- If started with a remote-debugging-port, these HTTP endpoints are available on the same - port. + When Chromium or Chrome is launched with + --remote-debugging-port=<port> (for example, + --remote-debugging-port=9222), it starts an internal HTTP server that exposes + REST endpoints and WebSocket connections for target discovery, browser lifecycle + management, and DevTools Protocol communication.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
EndpointMethodDescription
/json/versionGETBrowser version metadata and browser-level WebSocket URL
/json or /json/listGETList of inspectable targets (pages, workers, tabs)
/json/new?{url}PUTCreate a new page or tab target (strictly requires PUT)
/json/activate/{targetId}GETBring a target page or tab to the foreground
/json/close/{targetId}GETClose the specified target
/json/protocolGETFull DevTools Protocol JSON schema
/devtools/browser/{guid}WSRoot browser-level WebSocket connection
/devtools/page/{targetId}WSTarget-specific WebSocket connection
+
+

- GET /json/version + GET /json/version #

-

Browser version metadata

+

+ Returns browser version metadata, engine versions, and the browser-level WebSocket + debugging URL. +

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FieldTypeDescription
Browserstring + Product name and version (e.g. Chrome/135.0.7012.0 or + HeadlessChrome/...) +
Protocol-VersionstringCurrent supported protocol version (e.g. 1.3)
User-AgentstringDefault browser User-Agent header string
V8-VersionstringV8 JavaScript engine version
WebKit-VersionstringWebKit / Blink version and Git revision hash
webSocketDebuggerUrlstring + WebSocket URL to attach to the root browser target (contains an unguessable UUID + on desktop) +
Android-PackagestringHost Android package ID (present on Android only)
+
+
 {
-    "Browser": "Chrome/124.0.6367.60",
-    "Protocol-Version": "1.3",
-    "User-Agent": "Mozilla/5.0 ...",
-    "V8-Version": "12.4.254.12",
-    "WebKit-Version": "537.36 ...",
-    "webSocketDebuggerUrl": "ws://localhost:9222/devtools/browser/..."
+  "Browser": "Chrome/135.0.7012.0",
+  "Protocol-Version": "1.3",
+  "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36",
+  "V8-Version": "13.5.100",
+  "WebKit-Version": "537.36 (@a1b2c3d4e5f60718293a4b5c6d7e8f9012345678)",
+  "webSocketDebuggerUrl": "ws://localhost:9222/devtools/browser/6b539824-7489-4a9c-9c02-4ec4dc1373ea"
 }

- GET /json or /json/list + GET /json or + /json/list #

-

A list of all available websocket targets.

-
-[ {
-  "description": "",
-  "devtoolsFrontendUrl": "/devtools/inspector.html?ws=localhost:9222/devtools/page/...",
-  "id": "...",
-  "title": "...",
-  "type": "page",
-  "url": "https://...",
-  "webSocketDebuggerUrl": "ws://localhost:9222/devtools/page/..."
-} ]
+

+ Returns an array of target descriptors for all inspectable contexts (pages, background + pages, service workers, shared workers). Targets are sorted in descending order by last + activity time. +

-

- GET /json/protocol/ - # -

-

The current devtools protocol, as JSON.

+

Query Parameters:

+ + +
+[
+  {
+    "description": "",
+    "devtoolsFrontendUrl": "https://chrome-devtools-frontend.appspot.com/serve_rev/@a1b2c3d4/inspector.html?ws=localhost:9222/devtools/page/D598C123456789ABCDEF0123456789AB",
+    "faviconUrl": "https://example.com/favicon.ico",
+    "id": "D598C123456789ABCDEF0123456789AB",
+    "title": "Example Domain",
+    "type": "page",
+    "url": "https://example.com/",
+    "webSocketDebuggerUrl": "ws://localhost:9222/devtools/page/D598C123456789ABCDEF0123456789AB"
+  }
+]

- PUT /json/new?{url} + PUT /json/new or + PUT /json/new?{url} #

-

Opens a new tab. Responds with the websocket target data for the new tab.

+

+ Creates a new browsing context (page or tab) navigated to the specified URL and returns + its target descriptor. +

+

+ Method Requirement: This endpoint + strictly requires the PUT method. Calling it with + GET, POST, or any other verb fails with + 405 Method Not Allowed ("Using unsafe HTTP verb GET to invoke /json/new. This action supports only PUT + verb."). +

+

Query Parameters:

+

- GET /json/activate/{targetId} + GET + /json/activate/{targetId} #

-

Brings a page into the foreground (activate a tab).

+

Brings the specified target tab or window to the foreground.

+

- GET /json/close/{targetId} + GET /json/close/{targetId} #

-

Closes the target page identified by targetId.

+

Closes the specified target page.

+ + +

+ GET /json/protocol + # +

+

+ Returns the complete Chrome DevTools Protocol JSON schema containing all domains, methods, + events, and type definitions. +

+ +

+ Target Descriptor Object + # +

+

+ The JSON object structure returned in target lists (/json/list) and new + target creation (/json/new): +

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FieldTypePresenceDescription
idstringRequiredUnique target identifier (UUIDv4)
parentIdstringOptionalTarget ID of the parent context (omitted for top-level pages)
typestringRequiredTarget classification string (see table below)
titlestringRequiredDocument title or worker label (HTML-escaped)
descriptionstringRequiredHuman-readable target description (may be empty string)
urlstringRequiredCurrent URL loaded in the target
faviconUrlstringOptionalFavicon URL (omitted if not present or invalid)
webSocketDebuggerUrlstringRequiredWebSocket URL for CDP clients to attach to this target
devtoolsFrontendUrlstringRequiredComplete URL to launch the hosted DevTools web inspector for this target
+
+ +

+ Target Types + # +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
type ValueDescription
"page"Primary top-level web page or tab frame
"tab" + Tab target container (parent of all subframes and prerendered pages in a + WebContents) +
"iframe"Out-of-process subframe or iframe
"worker"Dedicated Web Worker (new Worker())
"shared_worker"Shared Web Worker (new SharedWorker())
"service_worker"Service Worker registration execution context
"worklet"Generic Worklet (Paint, Audio, Layout)
"auction_worklet"Protected Audience (FLEDGE) Auction Worklet
"browser"Browser-wide process target
"webview"Guest view or <webview> content
"background_page"Chrome Extension background page or offscreen document
"app"Packaged app, platform app, or Isolated Web App (IWA)
"browser_ui"Internal Chrome WebUI window or contents
"other"Fallback classification for other inspectable targets
+

- WebSocket /devtools/page/{targetId} + WebSocket + /devtools/page/{targetId} & /devtools/browser/{guid} #

-

The WebSocket endpoint for the protocol.

+

+ Clients communicate with the DevTools Protocol over full-duplex WebSocket connections. +

+

- GET /devtools/inspector.html + GET /devtools/inspector.html #

-

A copy of the DevTools frontend that ships with Chrome.

+

+ Legacy endpoint serving the bundled DevTools frontend. In modern Chrome, inspect targets + using the remote frontend URL provided in target descriptors (devtoolsFrontendUrl). +

+ +

+ Security & Origin Restrictions + # +

+ diff --git a/src/style.css b/src/style.css index 036409a6c..7074073c8 100644 --- a/src/style.css +++ b/src/style.css @@ -165,6 +165,67 @@ figure.screenshot img { box-shadow: var(--elevation-shadow); } +.table-responsive { + width: 100%; + overflow-x: auto; + margin: 14px 0 22px 0; + -webkit-overflow-scrolling: touch; +} + +table { + width: 100%; + border-collapse: collapse; + font-size: 13.5px; + line-height: 1.5; +} + +th, +td { + padding: 8px 12px; + text-align: left; + border-bottom: 1px solid var(--color-border); + vertical-align: top; +} + +th { + background-color: #f8f9fa; + font-weight: 600; + color: var(--color-text); + border-top: 1px solid var(--color-border); + white-space: nowrap; +} + +tr:hover td { + background-color: #fcfdfe; +} + +.http-method { + display: inline-block; + padding: 1.5px 6px; + border-radius: 3px; + font-size: 11px; + font-weight: 700; + letter-spacing: 0.5px; + font-family: var(--font-mono); + vertical-align: middle; + text-transform: uppercase; +} + +.http-method-get { + background-color: #e8f0fe; + color: #1967d2; +} + +.http-method-put { + background-color: #fef7e0; + color: #b06000; +} + +.http-method-ws { + background-color: #e6f4ea; + color: #137333; +} + /* ========================================================================== Toolbar Header (50px) - Indigo Theme ========================================================================== */ From f8dacb2970faea5502b16863c75bfb624cd354bf Mon Sep 17 00:00:00 2001 From: Paul Irish Date: Sat, 12 Sep 2026 13:27:24 -0700 Subject: [PATCH 2/2] test: make chrome websocket url resolution resilient in e2e tests --- test/e2e.test.js | 68 ++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 57 insertions(+), 11 deletions(-) diff --git a/test/e2e.test.js b/test/e2e.test.js index a23145e0f..d3e659a22 100644 --- a/test/e2e.test.js +++ b/test/e2e.test.js @@ -214,28 +214,74 @@ test('Chrome DevTools Protocol Viewer E2E Tests', async (t) => { let pageApi = null; try { - // 3. Parse WebSocket URL from Chrome stderr + // 3. Resolve WebSocket URL from Chrome (via DevToolsActivePort file or stderr) const wsUrl = await new Promise((resolve, reject) => { - const timeout = setTimeout( - () => reject(new Error('Timed out waiting for Chrome WebSocket URL')), - 10000, - ); + let resolved = false; let stderrBuffer = ''; + + /** + * @param {string} url + */ + const finish = (url) => { + if (resolved) return; + resolved = true; + clearTimeout(timeout); + clearInterval(activePortInterval); + resolve(url); + }; + + /** + * @param {Error} err + */ + const fail = (err) => { + if (resolved) return; + resolved = true; + clearTimeout(timeout); + clearInterval(activePortInterval); + reject(err); + }; + + const timeout = setTimeout(() => { + fail( + new Error( + `Timed out waiting for Chrome WebSocket URL (waited 30s).\nChrome stderr:\n${stderrBuffer}`, + ), + ); + }, 30000); + + // Check DevToolsActivePort file written to user-data-dir + const activePortPath = path.join(tmpUserDataDir, 'DevToolsActivePort'); + const activePortInterval = setInterval(() => { + if (fs.existsSync(activePortPath)) { + try { + const content = fs.readFileSync(activePortPath, 'utf8').trim().split('\n'); + if (content.length >= 2) { + const port = content[0]?.trim(); + const targetPath = content[1]?.trim(); + if (port && targetPath) { + finish(`ws://127.0.0.1:${port}${targetPath}`); + } + } + } catch {} + } + }, 50); + chromeProcess.stderr.on('data', (chunk) => { stderrBuffer += chunk.toString(); const match = stderrBuffer.match(/DevTools listening on (ws:\/\/[^\s]+)/); if (match) { - clearTimeout(timeout); - resolve(match[1]); + finish(match[1]); } }); chromeProcess.on('error', (err) => { - clearTimeout(timeout); - reject(err); + fail(err); }); chromeProcess.on('exit', (code) => { - clearTimeout(timeout); - reject(new Error(`Chrome exited prematurely with code ${code}`)); + fail( + new Error( + `Chrome exited prematurely with code ${code}.\nChrome stderr:\n${stderrBuffer}`, + ), + ); }); });