You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: server/lib/cdpmonitor/README.md
+145-6Lines changed: 145 additions & 6 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -10,13 +10,13 @@ Chrome can restart independently of the monitor. When that happens, `UpstreamPro
10
10
11
11
## Event taxonomy
12
12
13
-
**CDP-derived** (1-to-1 with a CDP notification): `console_log`, `console_error`, `network_request`, `network_response`, `network_loading_failed`, `navigation`, `dom_content_loaded`, `page_load`, `layout_shift`
13
+
**CDP-derived** (1-to-1 with a CDP notification): `console_log`, `console_error`, `network_request`, `network_response`, `network_loading_failed`, `page_tab_opened`, `page_navigation`, `page_dom_content_loaded`, `page_load`, `page_layout_shift`
14
14
15
-
**Computed** (inferred from sequences of CDP events): `network_idle` (fires when in-flight requests drop to zero), `layout_settled` (1 s after `page_load` with no intervening layout shifts), `navigation_settled` (fires once `dom_content_loaded`, `network_idle`, and `layout_settled` have all fired for the same navigation).
15
+
**Computed** (inferred from sequences of CDP events): `network_idle` (fires when in-flight requests drop to zero), `page_layout_settled` (1 s after `page_load` with no intervening layout shifts), `page_navigation_settled` (fires once `page_dom_content_loaded`, `network_idle`, and `page_layout_settled` have all fired for the same navigation).
16
16
17
-
**Interaction** (fired by `interaction.js` via `Runtime.bindingCalled`): `interaction_click`, `interaction_key`, `scroll_settled`
17
+
**Interaction** (fired by `interaction.js` via `Runtime.bindingCalled`): `interaction_click`, `interaction_key`, `interaction_scroll_settled`
18
18
19
-
**Monitor lifecycle** (emitted by the monitor itself, not by Chrome): `screenshot`, `monitor_disconnected`, `monitor_reconnected`, `monitor_reconnect_failed`, `monitor_init_failed`
19
+
**Monitor lifecycle** (emitted by the monitor itself, not by Chrome): `monitor_screenshot`, `monitor_disconnected`, `monitor_reconnected`, `monitor_reconnect_failed`, `monitor_init_failed`
|`computed.mu`| All `computedState` fields: counters and timers for the `network_idle`, `layout_settled`, and `navigation_settled` state machines |
73
+
|`computed.mu`| All `computedState` fields: counters and timers for the `network_idle`, `page_layout_settled`, and `page_navigation_settled` state machines |
74
74
|`pendMu`|`pending` (id -> reply channel): in-flight CDP commands waiting for a response from Chrome |
75
75
|`sessionsMu`|`sessions` (sessionID ->`targetInfo`): the set of currently attached CDP targets (tabs, iframes, workers) |
76
76
|`bindingRateMu`|`bindingLastSeen` (sessionID:eventType -> time): rate-limit state for `__kernelEvent` binding calls |
@@ -79,4 +79,143 @@ Fields that need no mutex use `sync/atomic`: `nextID`, `mainSessionID`, `running
79
79
80
80
### WebSocket concurrency
81
81
82
-
`coder/websocket` guarantees one concurrent `Read` and one concurrent `Write` are safe on the same connection. `readLoop` is the sole reader. All writes go through `send`, which calls `conn.Write` directly -- `conn.Write` is internally serialized by the library, so no external write mutex is needed.
82
+
`coder/websocket` guarantees one concurrent `Read` and one concurrent `Write` are safe on the same connection. `readLoop` is the sole reader. All writes go through `send`, which calls `conn.Write` directly -- `conn.Write` is internally serialized by the library, so no external write mutex is needed.
83
+
84
+
## Event data model
85
+
86
+
### Envelope and top-level fields
87
+
88
+
Every event arrives as an `Envelope`:
89
+
90
+
```json
91
+
{
92
+
"capture_session_id": "cs_abc123",
93
+
"seq": 42,
94
+
"event": {
95
+
"ts": 1746123456789000,
96
+
"type": "network_request",
97
+
"category": "network",
98
+
"source": { ... },
99
+
"data": { ... },
100
+
"truncated": false
101
+
}
102
+
}
103
+
```
104
+
105
+
| Field | Type | Description |
106
+
| --- | --- | --- |
107
+
|`capture_session_id`| string | Pipeline-assigned ID for the capture session (not a CDP concept). |
|`event.truncated`| bool |`true` if `data` was nulled to fit the 1 MB pipeline limit. |
113
+
114
+
### Source object
115
+
116
+
```json
117
+
"source": {
118
+
"kind": "cdp",
119
+
"event": "Network.requestWillBeSent",
120
+
"metadata": {
121
+
"cdp_session_id": "...",
122
+
"target_id": "...",
123
+
"target_type": "page"
124
+
}
125
+
}
126
+
```
127
+
128
+
| Field | Description |
129
+
| --- | --- |
130
+
|`event`| The raw CDP method that triggered the event (e.g. `Network.requestWillBeSent`). Empty for computed events. |
131
+
|`metadata.cdp_session_id`| The CDP WebSocket session multiplexer ID for this target. Changes if Chrome restarts. |
132
+
|`metadata.target_id`| Stable identifier for the browser target (tab/window). Survives navigations within the same tab. |
133
+
|`metadata.target_type`| Target type as reported by Chrome: `page`, `iframe`, `worker`, etc. |
134
+
135
+
### CDP identity primer
136
+
137
+
Five IDs appear across events. Understanding how they nest prevents confusion:
138
+
139
+
```
140
+
target_id <- one per tab/window; stable across navigations
141
+
└── cdp_session_id <- WebSocket multiplexer channel to that target; resets on Chrome restart
142
+
└── frame_id <- one per frame (top-level or iframe); changes on navigation
143
+
└── loader_id <- one per document load; links a navigation to its network requests
144
+
└── request_id <- one per request (stable across redirects in a chain)
145
+
```
146
+
147
+
| ID | Where it appears | What it identifies |
148
+
| --- | --- | --- |
149
+
|`target_id`|`source.metadata`, most `data` objects | The browser tab. Use this to group all events from one tab session. |
150
+
|`cdp_session_id`|`source.metadata`| The WebSocket sub-channel. Not stable across reconnects. |
151
+
|`frame_id`|`page_navigation`, `network_request`, `network_response`, `network_loading_failed`| The frame the request or navigation belongs to. Top-level frame has no `parent_frame_id`. |
152
+
|`source_frame_id`|`page_layout_shift`| The frame where the layout shift occurred. Distinct from the nav context `frame_id`, which is always the top-level navigated frame. |
153
+
|`loader_id`|`page_navigation`, `network_request`, `network_response`| The document load that owns a request. Join `network_request.loader_id` to `page_navigation.loader_id` to correlate requests with the navigation that triggered them. |
154
+
|`request_id`|`network_request`, `network_response`, `network_loading_failed`| A single request chain (including redirects). Links request to its eventual response or failure. |
155
+
156
+
### Navigation context fields
157
+
158
+
Most event `data` objects include a nav context block stamped at the last `page_navigation`. These fields reflect the top-level frame most recently navigated in the session:
159
+
160
+
| Field | Description |
161
+
| --- | --- |
162
+
|`session_id`| Same as `source.metadata.cdp_session_id`. Repeated for data-only consumers. |
163
+
|`frame_id`| Frame ID of the navigated top-level frame. |
164
+
|`loader_id`| Loader ID of the current document. |
165
+
|`url`| URL of the current page at the time of the last navigation. |
166
+
|`nav_seq`| Monotonically increasing counter, incremented on each `page_navigation`. Use it to detect that the page has navigated between two events in the same session. |
167
+
168
+
### Per-event data fields
169
+
170
+
Fields below are the unique additions per event type. Unless otherwise noted, events also include the nav context fields described above. Network events are the exception: they carry their own `loader_id` and `frame_id` directly and do not include nav context.
171
+
172
+
#### Console events
173
+
174
+
| Event | Unique fields |
175
+
| --- | --- |
176
+
|`console_log`|`level` (CDP type string), `text` (first arg), `args` (all args as strings), `stack_trace`|
177
+
|`console_error`| Same as `console_log` when `source.event` is `Runtime.consoleAPICalled`. When `source.event` is `Runtime.exceptionThrown`: `text`, `line`, `column`, `source_url` (script file URL, not page URL), `stack_trace`. |
|`network_response`|`request_id`, `loader_id`, `frame_id`, `method`, `url`, `status`, `headers`. Optional: `status_text`, `mime_type`, `resource_type`, `body` (truncated text body for textual MIME types). |
185
+
|`network_loading_failed`|`request_id`, `error_text`, `canceled`. Optional (absent when the request record was not found): `url`, `loader_id`, `frame_id`, `resource_type`. |
186
+
187
+
#### Page events
188
+
189
+
| Event | Unique fields |
190
+
| --- | --- |
191
+
|`page_tab_opened`|`target_id`, `target_type`, `url`, `opener_id`, `title`. Emitted before the first navigation; no nav context. |
192
+
|`page_navigation`|`session_id`, `target_id`, `target_type`, `url`, `frame_id`, `parent_frame_id` (absent for top-level frames), `loader_id`. This event establishes the nav context stamped on all subsequent events for the session. |
193
+
|`page_dom_content_loaded`| Nav context + `cdp_timestamp` (CDP monotonic seconds; not a wall-clock timestamp -- use `event.ts` for ordering). |
194
+
|`page_load`| Nav context + `cdp_timestamp` (CDP monotonic seconds). |
195
+
|`page_layout_shift`| Nav context + `source_frame_id`, `time`, `duration`. Optional `layout_shift_details` object: `score`, `had_recent_input`. Optional `lcp_details` object: `render_time`, `load_time`, `size`, `element_id`, `url`, `node_id`. Chrome multiplexes LCP candidate data through the same `PerformanceTimeline.timelineEventAdded` notification, so both may appear on a single event. |
196
+
197
+
#### Computed events
198
+
199
+
`network_idle`, `page_layout_settled`, and `page_navigation_settled` carry nav context fields only.
200
+
201
+
#### Interaction events
202
+
203
+
All interaction events include nav context plus the fields below.
204
+
205
+
| Event | Unique fields |
206
+
| --- | --- |
207
+
|`interaction_click`|`x`, `y` (viewport coords), `selector` (CSS selector of clicked element), `tag`, `text` (element text; empty for sensitive inputs). |
208
+
|`interaction_key`|`key` (key name), `selector`, `tag`. Not emitted for sensitive input fields. |
209
+
|`interaction_scroll_settled`|`from_x`, `from_y`, `to_x`, `to_y` (scroll positions in px), `target_selector`. |
210
+
211
+
#### Monitor lifecycle events
212
+
213
+
Lifecycle events use `source.kind = "local_process"` and carry no nav context, except `monitor_screenshot` which includes nav context alongside the image payload.
214
+
215
+
| Event | Fields |
216
+
| --- | --- |
217
+
|`monitor_screenshot`| Nav context + `png` (base64-encoded PNG). |
0 commit comments