---
id: cdp_get_ax_outline_go_browser
name: cdp_get_ax_outline
kind: function
lang: go
domain: browser
version: "1.0.0"
purity: impure
signature: "func CdpGetAXOutline(c *CDPConn, frameID string, maxChars int) (string, error)"
description: "Percibe la pagina (o un iframe via frameID) como outline accesible indentado y accionable reusando la conexion CDP viva del pool. Envia Accessibility.enable + getFullAXTree, poda el arbol y lo renderiza con #ref=backendDOMNodeId en roles accionables. Replica al caracter el pipeline Python cdp_get_ax_tree -> trim_ax_tree -> render_ax_outline pero nativo en Go, sin subprocess ni venv."
tags: [browser, cdp, ax, accessibility, perceive, iframe, navegator]
uses_functions: []
uses_types: []
returns: []
returns_optional: false
error_type: "error_go_core"
imports: []
tested: true
tests: ["TestRenderAXOutline_ActionableRoleCarriesRef", "TestRenderAXOutline_InputShowsValue", "TestRenderAXOutline_SkipRoleElevatesChildren", "TestRenderAXOutline_IndentationPerLevel", "TestRenderAXOutline_TruncationAddsSuffix", "TestTrimAXTree_DiscardsIgnored", "TestTrimAXTree_CollapsesSameRoleSingleChild", "TestAxoPyRepr", "TestAxoParseNodes"]
test_file_path: "functions/browser/cdp_get_ax_outline_test.go"
file_path: "functions/browser/cdp_get_ax_outline.go"
params:
  - name: c
    desc: "Conexion CDP viva (*CDPConn) del pool, ya conectada al tab/target objetivo. No abre WebSocket nuevo: reusa la del pool. Nil devuelve error."
  - name: frameID
    desc: "frameId CDP del iframe a percibir. Cadena vacia ('') percibe el arbol completo de la pagina (depth -1). Con valor, obtiene el AX tree DENTRO de ese iframe."
  - name: maxChars
    desc: "Limite de caracteres del outline. >0 trunca y añade '\\n…[outline truncado]'. <=0 = sin limite."
output: "Outline accesible multi-linea: 2 espacios de indentacion por nivel, 'role \"name\"' por nodo, ' = '\\''value'\\''' en inputs, y marcador '  #ref=<backendDOMNodeId>' en roles accionables. Cadena vacia si no hay nodos utiles."
---

## Ejemplo

```go
// c es una *CDPConn viva del pool (la misma que usa el browser_mcp).
// Percibir la pagina entera, truncando a 8000 chars:
outline, err := CdpGetAXOutline(c, "", 8000)
if err != nil {
    log.Fatal(err)
}
fmt.Println(outline)
// WebArea "Example Domain"
//   heading "Example Domain"
//   link "More information..."  #ref=128

// Percibir DENTRO de un iframe concreto (frameId del frame tree):
inner, err := CdpGetAXOutline(c, "F1A2B3C4D5E6", 0) // 0 = sin limite
```

## Cuando usarla

- Cuando necesites **percibir la pagina (o un iframe) como outline accionable** para que un LLM decida sobre `#ref` sin reventar el contexto.
- **Reemplaza el subprocess Python** `fn run cdp_perceive_outline`: es nativo Go, reusa la conexion CDP viva del pool y no arranca el venv en cada percepcion (mas rapido y sin dependencia de runtime `fn`/venv).
- Pasa `frameID` cuando el contenido objetivo vive dentro de un iframe; deja `frameID=""` para la pagina top-level.
- El `#ref` que devuelve (backendDOMNodeId) se pasa luego a `cdp_click_ref` / `cdp_type_ref` / `cdp_hover_ref`.

## Gotchas

- **Impura**: requiere un Chrome vivo con CDP accesible y el dominio `Accessibility` disponible. `Accessibility.enable` se envia siempre (idempotente).
- **Conexion nula** devuelve error inmediato; no intenta reconectar.
- **OOPIF cross-origin**: un iframe de distinto origen corre en un target (proceso) separado. Si `Accessibility.getFullAXTree` con ese `frameId` no devuelve nodos, probablemente necesites una `*CDPConn` adjunta al target del frame, no el `frameId` desde el target padre.
- **`#ref` = backendDOMNodeId**: estable mientras el nodo DOM viva, pero si la pagina re-renderiza ese subarbol el ref puede invalidarse. Percibe de nuevo tras una mutacion grande antes de actuar.
- El outline omite roles `none`/`presentation`/`ignored` y nodos `ignored=true`, y eleva sus hijos al nivel actual; un arbol con todo ignorado devuelve cadena vacia.
- Guard de profundidad 60 y guard de ciclo: arboles patologicos no cuelgan, pero pueden quedar recortados a partir de la profundidad 60.
