---
id: cdp_eval_in_frame_go_browser
name: cdp_eval_in_frame
kind: function
lang: go
domain: browser
purity: impure
version: 1.1.0
tested: true
tests: ["TestCdpEvalInFrame_guards", "TestFrameCtxCache", "TestIsStaleContextError"]
test_file_path: "functions/browser/cdp_eval_in_frame_test.go"
description: "Ejecuta una expresión JavaScript en el contexto aislado de un iframe concreto usando Page.createIsolatedWorld + Runtime.evaluate con el contextId del frame. Cachea el executionContextId por frameID en la conexión para no recrear el isolated world en cada llamada; si el contexto caduca (frame recargó) lo recrea una vez y reintenta."
tags: [cdp, browser, iframe, javascript, eval, navegator]
signature: "func CdpEvalInFrame(c *CDPConn, frameID string, expression string) (string, error)"
uses_functions: []
uses_types: []
returns: []
returns_optional: false
error_type: error_go_core
imports: []
file_path: "functions/browser/cdp_eval_in_frame.go"
example: |
  conn, _ := CdpConnect("localhost", 9222, "")
  frames, _ := CdpListFrames(conn)
  // Tomar el primer iframe (índice 1, el 0 es el frame raíz)
  result, err := CdpEvalInFrame(conn, frames[1].ID, "document.title")
  fmt.Println(result) // "Título del iframe"
params:
  - name: c
    desc: "Conexión CDP activa obtenida con CdpConnect."
  - name: frameID
    desc: "ID del frame donde ejecutar el JS; obtenido de CdpListFrames (campo CdpFrame.ID)."
  - name: expression
    desc: "Expresión JavaScript a evaluar en el contexto del frame; puede ser una expresión simple o una Promise."
output: "Resultado de la expresión serializado como string (fmt.Sprintf del valor CDP); error si la conexión es nula, el frameID está vacío, la comunicación CDP falla o la expresión lanza una excepción JS."
---

## Ejemplo

```go
conn, err := CdpConnect("localhost", 9222, "")
if err != nil {
    log.Fatal(err)
}
defer conn.Close()

frames, err := CdpListFrames(conn)
if err != nil {
    log.Fatal(err)
}

// frames[0] es el frame raíz; frames[1] sería el primer iframe
iframeID := frames[1].ID
title, err := CdpEvalInFrame(conn, iframeID, "document.title")
if err != nil {
    log.Fatal(err)
}
fmt.Println("Título del iframe:", title)

// Leer un elemento del DOM del iframe
text, _ := CdpEvalInFrame(conn, iframeID, "document.querySelector('h1').innerText")
fmt.Println("H1 del iframe:", text)
```

## Cuando usarla

Cuando necesites leer o manipular el DOM de un iframe específico sin afectar el contexto JS de la página principal. Útil para extraer datos de iframes de terceros, formularios embebidos o widgets. Obtén el `frameID` con `CdpListFrames` antes de llamar a esta función.

## Gotchas

- El mundo aislado (`fn_registry_isolated`) puede leer el DOM del iframe pero NO accede a variables JS definidas en el page-world del iframe (ej. `window.miVariable`). Para acceder a variables JS del frame, evalúa sin `createIsolatedWorld` usando el `contextId` principal del frame (no expuesto por esta función).
- Requiere `Page.enable` (se llama internamente, idempotente).
- Si el iframe tiene `sandbox` attribute sin `allow-scripts`, el CDP puede crear el mundo aislado pero las evaluaciones fallarán con excepción de seguridad.
- Cross-origin iframes en Chrome permiten evaluación CDP siempre que la conexión tenga acceso al target; no aplican las restricciones CORS de JS normal.
- El `frameID` debe obtenerse con `CdpListFrames`; si se pasa un ID obsoleto (frame recargado o destruido), `createIsolatedWorld` retorna error.
- **Cache de contexto por frameID**: la primera llamada crea el isolated world; las siguientes reutilizan su `executionContextId` (más rápido). Si el frame navega/recarga, el contexto cacheado caduca; la función detecta el error ("Cannot find context", "Execution context was destroyed") y recrea el mundo una vez automáticamente. El cache vive en la conexión: persiste entre llamadas mientras la conexión esté viva.

## Capability growth log

- v1.1.0 (2026-06-06) — corrige typo `grantUniveralAccess` → `grantUniversalAccess` (la opción nunca se aplicaba); cachea executionContextId por frameID en CDPConn (vía `frameCtxCache`) para no crear un isolated world por llamada; recrea+reintenta una vez si el contexto cacheado caducó.
