# How caveman-browse Captures Accessibility Snapshots via Chrome DevTools Protocol

> Discover how caveman-browse captures accessibility snapshots using the Chrome DevTools Protocol and the chromedp Go library to analyze your web page's accessibility tree.

- Repository: [Julius Brussee/caveman](https://github.com/JuliusBrussee/caveman)
- Tags: how-to-guide
- Published: 2026-09-04

---

**caveman-browse leverages the chromedp Go library to execute the `Accessibility.getFullAXTree` Chrome DevTools Protocol command, retrieving a slice of `*accessibility.Node` structs that represent the page's complete accessibility hierarchy.**

The `caveman` repository provides a headless browsing utility designed to extract semantic page structures for AI agents. To obtain accurate, up-to-date accessibility data, the project implements a CDP client in [`browse/cdp.go`](https://github.com/JuliusBrussee/caveman/blob/main/browse/cdp.go) that queries the browser's internal accessibility engine directly via the Chrome DevTools Protocol.

## CDP Integration Architecture

caveman-browse relies on the **chromedp** library to manage a headless Chrome instance. The library establishes a CDP session over WebSocket, allowing Go code to send commands and receive events from the browser's DevTools API. This architecture separates the high-level browsing logic from the low-level protocol serialization, ensuring reliable communication with Chromium-based browsers.

### Context Management

Every CDP operation requires a valid context. The code constructs an **actionCtx** (`context.Context`) that carries deadlines and cancellation signals. This context is passed to the accessibility query to ensure the snapshot request respects timeout limits and can be interrupted if the page becomes unresponsive.

## The Accessibility Snapshot Implementation in [`browse/cdp.go`](https://github.com/JuliusBrussee/caveman/blob/main/browse/cdp.go)

The core snapshot logic resides in [`browse/cdp.go`](https://github.com/JuliusBrussee/caveman/blob/main/browse/cdp.go), where the package imports the CDP accessibility domain and executes the full tree retrieval.

### Importing the Accessibility Domain

At line 13, the file imports the protocol definitions:

```go
import "github.com/chromedp/cdproto/accessibility"

```

This import provides Go structs that map 1:1 to the CDP `Accessibility` domain types, ensuring type-safe interaction with the browser's native accessibility data. By using these generated types, caveman-browse avoids manual JSON unmarshaling and gains compile-time verification of protocol structures.

### Retrieving the Full Accessibility Tree

At line 151, the code executes the snapshot:

```go
nodes, err = accessibility.GetFullAXTree().Do(actionCtx)

```

The `GetFullAXTree()` function constructs a CDP command that maps to the `Accessibility.getFullAXTree` protocol method. Calling `.Do(actionCtx)` dispatches the command over the CDP WebSocket and blocks until the browser returns the complete accessibility tree or an error occurs.

### Handling the Node Slice

Before the call at line 141, the code declares a variable to receive the result:

```go
var nodes []*accessibility.Node

```

Each `*accessibility.Node` contains fields such as `NodeID`, `Role`, `Name`, and `Children`, representing a single accessible element in the DOM. The resulting slice captures every accessible object on the page, from the root document down to individual controls, providing a comprehensive semantic map.

## Practical Example: Capturing an Accessibility Snapshot

Below is a runnable example that mirrors caveman-browse's approach. It launches a headless Chrome instance, navigates to a target, and extracts the accessibility tree.

```go
package main

import (
    "context"
    "log"
    "time"

    "github.com/chromedp/cdproto/accessibility"
    "github.com/chromedp/chromedp"
)

func main() {
    ctx, cancel := chromedp.NewContext(
        context.Background(),
        chromedp.WithHeadless(true),
    )
    defer cancel()

    // Set a 30-second timeout for the entire operation
    ctx, cancel = context.WithTimeout(ctx, 30*time.Second)
    defer cancel()

    var axNodes []*accessibility.Node

    err := chromedp.Run(ctx,
        chromedp.Navigate("https://example.com"),
        chromedp.ActionFunc(func(actionCtx context.Context) error {
            var err error
            // Capture the full accessibility tree via CDP
            axNodes, err = accessibility.GetFullAXTree().Do(actionCtx)
            return err
        }),
    )
    if err != nil {
        log.Fatalf("failed to capture accessibility snapshot: %v", err)
    }

    log.Printf("Captured %d accessibility nodes", len(axNodes))
    // Process axNodes further...
}

```

This code demonstrates the exact pattern used in [`browse/cdp.go`](https://github.com/JuliusBrussee/caveman/blob/main/browse/cdp.go): creating an action function that receives the CDP context, invoking `accessibility.GetFullAXTree().Do(actionCtx)`, and handling the returned slice.

## Error Handling and Timeouts

Any failure during the CDP call—such as a disconnected browser, timeout, or internal accessibility engine error—is returned from the `.Do()` method. The calling code in caveman-browse checks `err` immediately after line 151 and propagates it upward, allowing the session manager to retry the navigation or terminate the browsing task gracefully.

## Summary

- **caveman-browse** uses the **chromedp** Go library to communicate with Chrome via the Chrome DevTools Protocol.
- In [`browse/cdp.go`](https://github.com/JuliusBrussee/caveman/blob/main/browse/cdp.go), the code imports `github.com/chromedp/cdproto/accessibility` to access the CDP Accessibility domain.
- The snapshot is captured by calling `accessibility.GetFullAXTree().Do(actionCtx)`, which returns a slice of `*accessibility.Node` structs.
- This approach yields a complete, accurate accessibility tree directly from the browser's rendering engine, enabling precise semantic analysis of web content.

## Frequently Asked Questions

### What is the Chrome DevTools Protocol (CDP) used for in caveman-browse?

The Chrome DevTools Protocol is a set of APIs that allow external tools to inspect, debug, and control Chromium-based browsers. caveman-browse uses CDP to programmatically query the browser's internal accessibility tree, bypassing the need for HTML parsing and instead retrieving the semantic structure that assistive technologies use.

### Why does caveman-browse use `GetFullAXTree` instead of scraping the DOM?

`GetFullAXTree` returns the computed accessibility tree, which includes semantic information that raw DOM elements lack, such as ARIA role mappings, accessible names, and visibility states. This provides a more accurate representation of how screen readers perceive the page compared to raw HTML scraping.

### How does chromedp differ from Puppeteer or Playwright?

chromedp is a native Go library that communicates directly with Chrome via the CDP WebSocket without requiring Node.js or external browser drivers. Puppeteer and Playwright are Node.js-based alternatives that offer similar CDP access but require a JavaScript runtime, making chromedp preferable for Go-based systems like caveman.

### Can the accessibility snapshot capture hidden or off-screen elements?

Yes. The `GetFullAXTree` command returns all nodes in the accessibility tree, including elements with CSS `visibility: hidden` or positioned off-screen, as long as they are part of the accessibility hierarchy. The browser's accessibility engine determines inclusion based on semantic relevance rather than visual viewport presence.