Kernel Browser Telemetry API

Stream live telemetry events from a browser session.

Operations 2

GET /browsers/{id}/telemetry/stream Stream telemetry events via SSE #
GET /browsers/{id}/telemetry/events Read telemetry events for a browser session #

Work with this as data

Every API here is available over the APIs.io API and to AI agents over MCP.

MCP server

One button, every client — Claude, Cursor, VS Code and the rest.

https://apis.io/mcp

Tools for apis

7 MCP tools reach this
  • find_apisBrowse and filter every API in the catalog.
  • get_api_artifactsOne API's artifacts, grouped by type.
  • get_openapiThe primary OpenAPI for this API.
  • find_similar_apisAPIs that look like this one.
  • apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.
  • resolveTurn a domain, URL or GitHub org into the provider it belongs to.
  • find_cohortsEvery scored population of providers in the catalog.
All 92 tools →

Call it yourself

curl for this page
This API
curl "https://apis.io/api/v1/apis/kernel-browser-telemetry-api"
All apis
curl "https://apis.io/api/v1/apis?limit=25"

Discovery needs no key. Ratings and market analysis are Pro.

Get an API key

Free tier, no form to fill in. Signing in shares your email address with us — we store it to create your key and to recognise you if you sign in with another provider. See our Privacy Policy and Terms.

A second provider on the same verified email joins the account you already have.

OpenAPI Specification

kernel-browser-telemetry-api-openapi.yml Raw ↑
openapi: 3.2.0
info:
  title: Kernel API Keys Browser Telemetry API
  description: Developer tools and cloud infrastructure for AI agents to use web browsers
  version: 0.1.0
servers:
- url: https://api.onkernel.com
  description: API Server
security:
- bearerAuth: []
tags:
- name: Browser Telemetry
  description: Stream live telemetry events from a browser session.
paths:
  /browsers/{id}/telemetry/stream:
    get:
      summary: Stream telemetry events via SSE
      description: 'Streams browser telemetry events as a server-sent events (SSE) stream. The stream closes when the browser session terminates. Each event frame includes an id: field containing a monotonically increasing sequence number; pass it as Last-Event-ID on reconnect to resume without gaps. The event: field is never set; all frames carry JSON in the data: field. A keepalive comment frame is sent every 15 seconds when no events arrive. Returns 404 if the browser session does not exist. If telemetry was not enabled on the session, the stream opens but no events are delivered. Fresh connections only see new events; pass replay=all to start from the oldest retained event instead.

        '
      operationId: streamBrowserTelemetry
      tags:
      - Browser Telemetry
      security:
      - bearerAuth: []
      parameters:
      - name: id
        in: path
        required: true
        schema:
          type: string
        description: Browser session ID
      - name: Last-Event-ID
        in: header
        schema:
          type: string
        description: Last event sequence number for SSE reconnection (sent by SSE clients on reconnect). Takes precedence over replay when both are present, so reconnect resumes instead of re-replaying.
      - name: replay
        in: query
        schema:
          type: string
        description: Pass `all` to start from the oldest retained event instead of only new events; any other value is treated as from-now. The buffer is bounded, so the first event id may be greater than 1 if older events were evicted.
      responses:
        '200':
          description: SSE stream of telemetry events
          headers:
            X-SSE-Content-Type:
              description: Media type of SSE data events (always application/json).
              schema:
                type: string
                const: application/json
          content:
            text/event-stream:
              schema:
                $ref: '#/components/schemas/BrowserTelemetryEventEnvelope'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalError'
      x-codeSamples:
      - lang: JavaScript
        source: "import Kernel from '@onkernel/sdk';\n\nconst client = new Kernel({\n  apiKey: process.env['KERNEL_API_KEY'], // This is the default and can be omitted\n});\n\nconst response = await client.browsers.telemetry.stream('id');\n\nconsole.log(response.event);"
      - lang: Python
        source: "import os\nfrom kernel import Kernel\n\nclient = Kernel(\n    api_key=os.environ.get(\"KERNEL_API_KEY\"),  # This is the default and can be omitted\n)\nfor telemetry in client.browsers.telemetry.stream(\n    id=\"id\",\n):\n  print(telemetry)"
      - lang: Go
        source: "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/kernel/kernel-go-sdk\"\n\t\"github.com/kernel/kernel-go-sdk/option\"\n)\n\nfunc main() {\n\tclient := kernel.NewClient(\n\t\toption.WithAPIKey(\"My API Key\"),\n\t)\n\tstream := client.Browsers.Telemetry.StreamStreaming(\n\t\tcontext.TODO(),\n\t\t\"id\",\n\t\tkernel.BrowserTelemetryStreamParams{},\n\t)\n\tfor stream.Next() {\n\t\tfmt.Printf(\"%+v\\n\", stream.Current())\n\t}\n\terr := stream.Err()\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n}\n"
  /browsers/{id}/telemetry/events:
    get:
      summary: Read telemetry events for a browser session
      description: 'Reads a page of telemetry events for the browser session. To page through results, pass the X-Next-Offset value from the previous response as offset and repeat while X-Has-More is true. Returns an empty list when telemetry data is unavailable.

        '
      operationId: readBrowserTelemetryEvents
      tags:
      - Browser Telemetry
      security:
      - bearerAuth: []
      parameters:
      - name: id
        in: path
        required: true
        schema:
          type: string
        description: Browser session ID
      - name: offset
        in: query
        required: false
        description: 'Opaque pagination cursor: pass the X-Next-Offset value from the previous response to fetch the next page. When set, paging continues from this cursor and since is ignored, while until still bounds the page. It is not an event''s seq field, so do not derive it from the response body.

          '
        schema:
          type: integer
          minimum: 0
      - name: since
        in: query
        required: false
        description: 'Start of the window: an RFC-3339 timestamp, or a duration like 5m meaning that long ago. Defaults to 5m. Ignored when offset is set.

          '
        schema:
          type: string
      - name: until
        in: query
        required: false
        description: 'End of the window (exclusive): an RFC-3339 timestamp, or a duration like 5m meaning that long ago.

          '
        schema:
          type: string
      - name: limit
        in: query
        required: false
        description: Maximum number of events per page. Defaults to 20.
        schema:
          type: integer
          minimum: 1
          maximum: 100
          default: 20
      - name: category
        in: query
        required: false
        description: Restrict results to these event categories. Repeat the parameter for multiple values.
        schema:
          type: array
          items:
            type: string
            enum:
            - console
            - network
            - page
            - interaction
            - control
            - connection
            - system
            - screenshot
            - captcha
            - monitor
      - name: order
        in: query
        required: false
        description: 'Read direction. asc (default) reads oldest first, starting from since or the offset cursor. desc reads newest first: each request returns one page of up to limit records ending at the offset cursor (or until, or the newest archived event); combining desc with since is rejected with a 400. In either direction the category filter applies within the page, so a filtered page may be empty while X-Has-More is true.

          '
        schema:
          type: string
          default: asc
      responses:
        '200':
          description: A page of telemetry events.
          headers:
            X-Has-More:
              description: Whether more results are available
              schema:
                type: boolean
            X-Next-Offset:
              description: The offset where the next page starts. 0 when there are no more results.
              schema:
                type: integer
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/BrowserTelemetryEventEnvelope'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalError'
      x-codeSamples:
      - lang: JavaScript
        source: "import Kernel from '@onkernel/sdk';\n\nconst client = new Kernel({\n  apiKey: process.env['KERNEL_API_KEY'], // This is the default and can be omitted\n});\n\n// Automatically fetches more pages as needed.\nfor await (const telemetryEventsResponse of client.browsers.telemetry.events('id')) {\n  console.log(telemetryEventsResponse.event);\n}"
      - lang: Python
        source: "import os\nfrom kernel import Kernel\n\nclient = Kernel(\n    api_key=os.environ.get(\"KERNEL_API_KEY\"),  # This is the default and can be omitted\n)\npage = client.browsers.telemetry.events(\n    id=\"id\",\n)\npage = page.items[0]\nprint(page.event)"
      - lang: Go
        source: "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/kernel/kernel-go-sdk\"\n\t\"github.com/kernel/kernel-go-sdk/option\"\n)\n\nfunc main() {\n\tclient := kernel.NewClient(\n\t\toption.WithAPIKey(\"My API Key\"),\n\t)\n\tpage, err := client.Browsers.Telemetry.Events(\n\t\tcontext.TODO(),\n\t\t\"id\",\n\t\tkernel.BrowserTelemetryEventsParams{},\n\t)\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf(\"%+v\\n\", page)\n}\n"
components:
  schemas:
    BrowserSystemOomKillEvent:
      type: object
      description: The Linux kernel OOM-killer terminated a process inside the VM. Fires for any process killed by the kernel due to memory exhaustion, including Chrome renderer subprocesses that are not supervised.
      required:
      - ts
      - type
      - category
      - source
      properties:
        ts:
          type: integer
          format: int64
          description: Event timestamp in Unix microseconds.
        type:
          type: string
          const: system_oom_kill
        category:
          type: string
          const: system
        source:
          $ref: '#/components/schemas/BrowserEventSource'
        data:
          type: object
          additionalProperties: false
          required:
          - process_name
          - pid
          - rss_kb
          properties:
            process_name:
              type: string
              description: Comm of the killed process as reported by the kernel (max 15 chars, truncated by the kernel).
            pid:
              type: integer
              description: PID of the killed process.
            rss_kb:
              type: integer
              description: Resident set size of the killed process in KiB (sum of anon-rss, file-rss, and shmem-rss).
            trigger_process_name:
              type: string
              description: Comm of the process whose allocation request caused the kernel to invoke the OOM-killer. Often the same as process_name but can differ. Max 15 chars.
            trigger_pid:
              type: integer
              description: PID of the triggering process. Absent if the kernel did not emit the standard header line.
            constraint:
              type: string
              x-go-type: string
              description: Why the kernel decided to OOM-kill. none means global memory exhaustion; memcg means a cgroup memory limit was hit; cpuset / memory_policy are NUMA/policy-driven kills. Absent on kernels older than 5.0.
              enum:
              - none
              - memcg
              - cpuset
              - memory_policy
            mem_total_kb:
              type: integer
              description: Total system memory in KiB at the time of the kill. Assumes a 4 KiB page size. Absent if the kernel did not emit a parseable Mem-Info section.
            mem_free_kb:
              type: integer
              description: Free system memory in KiB at the time of the kill. Assumes a 4 KiB page size. Does not include reclaimable caches. Absent if the kernel did not emit a parseable Mem-Info section.
            top_tasks:
              type: array
              maxItems: 5
              description: Top processes by resident-set-size at the moment of the kill, sorted descending. Empty if the kernel did not emit the Tasks state table. Capped at 5 entries.
              items:
                type: object
                additionalProperties: false
                required:
                - pid
                - name
                - rss_kb
                properties:
                  pid:
                    type: integer
                    description: PID of the process.
                  name:
                    type: string
                    description: Comm of the process (max 15 chars, truncated by the kernel).
                  rss_kb:
                    type: integer
                    description: Resident set size in KiB at the moment of the kill.
        truncated:
          type: boolean
          description: True if the data field was truncated due to size limits.
    BrowserPageLayoutShiftEvent:
      type: object
      title: page_layout_shift
      description: A browser cumulative layout shift (CLS) event from the Performance Timeline API.
      required:
      - ts
      - type
      - category
      - source
      properties:
        ts:
          type: integer
          format: int64
          description: Event timestamp in Unix microseconds.
        type:
          type: string
          const: page_layout_shift
        category:
          type: string
          const: page
        source:
          $ref: '#/components/schemas/BrowserEventSource'
        data:
          allOf:
          - $ref: '#/components/schemas/BrowserEventContext'
          - type: object
            properties:
              source_frame_id:
                type: string
                description: CDP frame identifier of the frame where the layout shift occurred.
              time:
                type: number
                description: Performance Timeline timestamp of the layout shift in milliseconds.
              duration:
                type: number
                description: Duration of the layout shift entry in milliseconds (always 0 for layout shifts per spec).
              layout_shift_details:
                type: object
                additionalProperties: false
                description: PerformanceLayoutShift attributes from the Performance Timeline entry.
                properties:
                  value:
                    type: number
                    description: Layout shift score for this entry (contribution to CLS).
                  had_recent_input:
                    type: boolean
                    description: True if the layout shift was preceded by user input within 500ms, excluding it from CLS.
        truncated:
          type: boolean
          description: True if the data field was truncated due to size limits.
    BrowserInteractionScrollSettledEvent:
      type: object
      title: interaction_scroll_settled
      description: A browser scroll settled event emitted after scroll position stops changing, captured via injected page script.
      required:
      - ts
      - type
      - category
      - source
      properties:
        ts:
          type: integer
          format: int64
          description: Event timestamp in Unix microseconds.
        type:
          type: string
          const: interaction_scroll_settled
        category:
          type: string
          const: interaction
        source:
          $ref: '#/components/schemas/BrowserEventSource'
        data:
          allOf:
          - $ref: '#/components/schemas/BrowserEventContext'
          - type: object
            properties:
              from_x:
                type: integer
                description: Scroll x-position at the start of the scroll gesture in CSS pixels.
              from_y:
                type: integer
                description: Scroll y-position at the start of the scroll gesture in CSS pixels.
              to_x:
                type: integer
                description: Final scroll x-position after the gesture settled in CSS pixels.
              to_y:
                type: integer
                description: Final scroll y-position after the gesture settled in CSS pixels.
              target_selector:
                type: string
                description: CSS selector path to the scrolled element.
        truncated:
          type: boolean
          description: True if the data field was truncated due to size limits.
    BrowserLiveViewConnectEvent:
      type: object
      description: A live view client connected to the headful browser's WebRTC server. Headful only; not emitted for headless images.
      required:
      - ts
      - type
      - category
      - source
      properties:
        ts:
          type: integer
          format: int64
          description: Event timestamp in Unix microseconds.
        type:
          type: string
          const: live_view_connect
        category:
          type: string
          const: connection
        source:
          $ref: '#/components/schemas/BrowserEventSource'
        data:
          type: object
          additionalProperties: false
          required:
          - session_id
          properties:
            session_id:
              type: string
              description: Live view session identifier. Stable across reconnects, so a transient network blip can emit two events with the same session_id.
        truncated:
          type: boolean
          description: True if the data field was truncated due to size limits.
    BrowserInteractionClickEvent:
      type: object
      title: interaction_click
      description: A browser user click event captured via injected page script.
      required:
      - ts
      - type
      - category
      - source
      properties:
        ts:
          type: integer
          format: int64
          description: Event timestamp in Unix microseconds.
        type:
          type: string
          const: interaction_click
        category:
          type: string
          const: interaction
        source:
          $ref: '#/components/schemas/BrowserEventSource'
        data:
          allOf:
          - $ref: '#/components/schemas/BrowserEventContext'
          - type: object
            properties:
              x:
                type: integer
                description: Viewport x-coordinate of the click in CSS pixels.
              y:
                type: integer
                description: Viewport y-coordinate of the click in CSS pixels.
              selector:
                type: string
                description: CSS selector path to the clicked element.
              tag:
                type: string
                description: HTML tag name of the clicked element in uppercase (e.g. BUTTON, A, DIV).
              text:
                type: string
                description: Visible text content of the clicked element, trimmed.
        truncated:
          type: boolean
          description: True if the data field was truncated due to size limits.
    ErrorDetail:
      type: object
      properties:
        code:
          type: string
          description: Lower-level error code providing more specific detail
          example: invalid_input
        message:
          type: string
          description: Further detail about the error
          example: Provided version string is not semver compliant
    BrowserPageNavigationSettledEvent:
      type: object
      title: page_navigation_settled
      description: Emitted when page_dom_content_loaded and page_layout_settled have both fired for the same navigation, indicating the page is loaded and visually stable. Independent of network_idle; a single pending request does not block it.
      required:
      - ts
      - type
      - category
      - source
      properties:
        ts:
          type: integer
          format: int64
          description: Event timestamp in Unix microseconds.
        type:
          type: string
          const: page_navigation_settled
        category:
          type: string
          const: page
        source:
          $ref: '#/components/schemas/BrowserEventSource'
        data:
          $ref: '#/components/schemas/BrowserEventContext'
        truncated:
          type: boolean
          description: True if the data field was truncated due to size limits.
    BrowserLiveViewDisconnectEvent:
      type: object
      description: A live view client disconnected from the headful browser's WebRTC server. Pair with live_view_connect by session_id.
      required:
      - ts
      - type
      - category
      - source
      properties:
        ts:
          type: integer
          format: int64
          description: Event timestamp in Unix microseconds.
        type:
          type: string
          const: live_view_disconnect
        category:
          type: string
          const: connection
        source:
          $ref: '#/components/schemas/BrowserEventSource'
        data:
          type: object
          additionalProperties: false
          required:
          - session_id
          - duration_ms
          properties:
            session_id:
              type: string
              description: Live view session identifier; matches the corresponding live_view_connect event.
            duration_ms:
              type: number
              description: Wall-clock duration of the connection in milliseconds.
        truncated:
          type: boolean
          description: True if the data field was truncated due to size limits.
    BrowserCaptchaSolveResultEvent:
      type: object
      description: A captcha solve attempt reached a terminal outcome.
      required:
      - ts
      - type
      - category
      - source
      properties:
        ts:
          type: integer
          format: int64
          description: Event timestamp in Unix microseconds.
        type:
          type: string
          const: captcha_solve_result
        category:
          type: string
          const: captcha
        source:
          $ref: '#/components/schemas/BrowserEventSource'
        data:
          type: object
          additionalProperties: false
          required:
          - captcha_type
          - status
          - duration_ms
          properties:
            captcha_type:
              type: string
              x-go-type: string
              description: Captcha vendor family. Provider-specific task names are normalized into this set; anything not covered is reported as other.
              enum:
              - hcaptcha
              - recaptcha_v2
              - recaptcha_v3
              - turnstile
              - geetest
              - other
            status:
              type: string
              x-go-type: string
              description: 'Terminal outcome. success: solver returned a usable solution. failure: solver returned an error (see error_code). timeout: solver did not return within the caller''s wait budget. abandoned: caller cancelled or the page navigated away mid-solve.'
              enum:
              - success
              - failure
              - timeout
              - abandoned
            duration_ms:
              type: number
              description: Wall-clock duration from solve start to terminal outcome.
            task_id:
              type: string
              description: Solver-assigned identifier. Opaque, useful for support cross-references.
            website_host:
              type: string
              description: Host of the page where the captcha was solved.
            website_path:
              type: string
              description: Path of the page where the captcha was solved. Query string excluded.
            error_code:
              type: string
              description: Solver-specific error code on failure (e.g. ERROR_CAPTCHA_UNSOLVABLE). Absent on success.
        truncated:
          type: boolean
          description: True if the data field was truncated due to size limits.
    BrowserPageTabOpenedEvent:
      type: object
      title: page_tab_opened
      description: A new browser tab or target was opened (CDP Target.attachedToTarget for page targets). Fires before a CDP session is attached to the new target, so session_id, frame_id, loader_id, and nav_seq are absent; this event does not compose BrowserEventContext. Consumers reading context fields generically should treat it as a special case.
      required:
      - ts
      - type
      - category
      - source
      properties:
        ts:
          type: integer
          format: int64
          description: Event timestamp in Unix microseconds.
        type:
          type: string
          const: page_tab_opened
        category:
          type: string
          const: page
        source:
          $ref: '#/components/schemas/BrowserEventSource'
        data:
          type: object
          additionalProperties: false
          properties:
            target_id:
              type: string
              description: CDP target identifier for the newly opened tab.
            target_type:
              $ref: '#/components/schemas/BrowserTargetType'
            url:
              type: string
              description: Initial URL of the new tab.
            title:
              type: string
              description: Initial page title of the new tab.
            opener_id:
              type: string
              description: Target identifier of the tab that opened this one, if any.
        truncated:
          type: boolean
          description: True if the data field was truncated due to size limits.
    BrowserConsoleLogEvent:
      type: object
      title: console_log
      description: A browser console log event (console.log, console.info, console.warn, etc.).
      required:
      - ts
      - type
      - category
      - source
      properties:
        ts:
          type: integer
          format: int64
          description: Event timestamp in Unix microseconds.
        type:
          type: string
          const: console_log
        category:
          type: string
          const: console
        source:
          $ref: '#/components/schemas/BrowserEventSource'
        data:
          allOf:
          - $ref: '#/components/schemas/BrowserEventContext'
          - type: object
            properties:
              level:
                type: string
                description: CDP Runtime.consoleAPICalled type, passed through unfiltered from Chrome. error is routed to console_error events instead; all other CDP console types appear here. See CDP spec for the full enum.
              text:
                type: string
                description: First console argument coerced to string.
              args:
                type: array
                description: All console arguments coerced to strings.
                items:
                  type: string
              stack_trace:
                $ref: '#/components/schemas/BrowserCallStack'
        truncated:
          type: boolean
          description: True if the data field was truncated due to size limits.
    BrowserServiceCrashedEvent:
      type: object
      description: A managed service exited unexpectedly. Intentional stops do not produce this event; only unexpected exits and terminal restart-give-up transitions do.
      required:
      - ts
      - type
      - category
      - source
      properties:
        ts:
          type: integer
          format: int64
          description: Event timestamp in Unix microseconds.
        type:
          type: string
          const: service_crashed
        category:
          type: string
          const: system
        source:
          $ref: '#/components/schemas/BrowserEventSource'
        data:
          type: object
          additionalProperties: false
          required:
          - service_name
          - phase
          properties:
            service_name:
              type: string
              description: Program name of the crashed service (e.g. chromium, mutter, kernel-images-api).
            pid:
              type: integer
              description: PID of the crashed process. Absent when the process manager gave up after exhausting restart attempts.
            phase:
              type: string
              x-go-type: string
              description: 'Lifecycle phase the crash occurred in. startup: the process died before reaching a healthy running state. running: a previously healthy process died unexpectedly. gave_up: the process manager exhausted its restart attempts and stopped trying.'
              enum:
              - startup
              - running
              - gave_up
        truncated:
          type: boolean
          description: True if the data field was truncated due to size limits.
    BrowserMonitorReconnectedEvent:
      type: object
      title: monitor_reconnected
      description: The CDP connection to Chrome was successfully re-established after a disconnection. Events emitted during the gap are lost. Computed state is reset, so navigation and network tracking restart fresh from this point.
      required:
      - ts
      - type
      - category
      - source
      properties:
        ts:
          type: integer
          format: int64
          description: Event timestamp in Unix microseconds.
        type:
          type: string
          const: monitor_reconnected
        category:
          type: string
          const: monitor
        source:
          $ref: '#/components/schemas/BrowserEventSource'
        data:
          type: object
          additionalProperties: false
          properties:
            reconnect_duration_ms:
              type: integer
              format: int64
              description: Wall-clock time in milliseconds taken to reconnect after the disconnection.
        truncated:
          type: boolean
          description: True if the data field was truncated due to size limits.
    BrowserMonitorReconnectFailedEvent:
      type: object
      title: monitor_reconnect_failed
      description: The CDP connection to Chrome could not be re-established after exhausting all reconnection attempts. No further telemetry events will arrive on this session.
      required:
      - ts
      - type
      - category
      - source
      properties:
        ts:
          type: integer
          format: int64
          description: Event timestamp in Unix microseconds.
        type:
          type: string
          const: monitor_reconnect_failed
        category:
          type: string
          const: monitor
        source:
          $ref: '#/components/schemas/BrowserEventSource'
        data:
          type: object
          additionalProperties: false
          properties:
            reason:
              type: string
              description: 'Reason for the reconnection failure. reconnect_exhausted: all retry attempts were used up without successfully restoring the CDP connection.'
              enum:
              - reconnect_exhausted
        truncated:
          type: boolean
          description: True if the data field was truncated due to size limits.
    BrowserApiCallEvent:
      type: object
      description: An agent-driven HTTP call handled by the in-VM API server.
      required:
      - ts
      - type
      - category
      - source
      properties:
        ts:
          type: integer
          format: int64
          description: Event timestamp in Unix microseconds.
        type:
          type: string
          const: api_call
        category:
          type: string
          const: control
        source:
          $ref: '#/components/schemas/BrowserEventSource'
        data:
          type: object
          additionalProperties: false
          required:
          - request_id
          - operation_id
          - status
          - duration_ms
          properties:
            request_id:
              type: string
              description: Per-request identifier from the in-VM API request middleware.
            operation_id:
              type: string
              description: OpenAPI operationId of the matched route (e.g. processExec, takeScreenshot).
            status:
              type: integer
              description: HTTP response status code.
            duration_ms:
              type: number
              description: Wall-clock duration of the handler in milliseconds.
        truncated:
          type: boolean
          description: True if the data field was truncated due to size limits.
    BrowserPageLoadEvent:
      type: object
      title: page_load
      description: A browser page load event (CDP Page.loadEventFired).
      required:
      - ts
      - type
      - category
      - source
      properties:
        ts:
          type: integer
          format: int64
          description: Event timestamp in Unix microseconds.
        type:
          typ

# --- truncated at 32 KB (66 KB total) ---
# Full source: https://raw.githubusercontent.com/api-evangelist/kernel/refs/heads/main/openapi/kernel-browser-telemetry-api-openapi.yml