---
id: cdp_save_storage_state_go_browser
name: cdp_save_storage_state
kind: function
lang: go
domain: browser
purity: impure
version: 1.1.0
tested: true
tests: ["TestIsStorageAccessDenied", "TestCookieDomainMatchesHost"]
test_file_path: "functions/browser/cdp_save_storage_state_test.go"
description: "Captura cookies, localStorage y sessionStorage de la página activa y los serializa a un archivo JSON para restaurar la sesión sin repetir el login. Distingue 'origen sin storage accesible' (vacío legítimo) de un error real de evaluación, que aborta el guardado en vez de escribir una sesión incompleta en silencio."
tags: [cdp, browser, storage, session, cookies, localStorage, auth, navegator]
signature: "func CdpSaveStorageState(c *CDPConn, outPath string) error"
uses_functions:
  - cdp_evaluate_go_browser
uses_types: []
returns: []
returns_optional: false
error_type: error_go_core
imports: []
file_path: "functions/browser/cdp_save_storage_state.go"
example: |
  conn, _ := CdpConnect(9222)
  defer CdpClose(conn)
  CdpNavigate(conn, "https://app.example.com")
  err := CdpSaveStorageState(conn, "/tmp/session.json")
params:
  - name: c
    desc: "Conexión CDP activa apuntando a la pestaña con la sesión autenticada."
  - name: outPath
    desc: "Ruta del archivo JSON de salida donde se escribirá el estado (cookies + localStorage)."
output: "nil si el archivo se escribió correctamente; error con contexto en caso de fallo de red, CDP o escritura."
---

## Ejemplo

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

// Navegar y autenticarse manualmente o con scraping
CdpNavigate(conn, "https://app.example.com/dashboard")

// Guardar estado de la sesión
if err := CdpSaveStorageState(conn, "/tmp/session.json"); err != nil {
    log.Fatal(err)
}
// /tmp/session.json contiene cookies + localStorage listos para restaurar
```

## Cuando usarla

Tras completar un login en el browser (manual o automatizado), antes de cerrar la sesión o como paso final del script de autenticación. En la próxima ejecución, llama a `CdpLoadStorageState` en vez de repetir el flujo de login.

## Gotchas

- **localStorage es por-origen**: solo captura el localStorage del origen actualmente cargado en la pestaña. Si necesitas preservar localStorage de múltiples dominios, guarda un estado por cada dominio navegado.
- **Cookies globales del perfil**: `Network.getAllCookies` devuelve todas las cookies del perfil de Chrome, no solo las del origen activo. El JSON puede ser grande si el perfil tiene muchas cookies.
- **Páginas especiales** (`about:blank`, `chrome://`, `data:`, extensiones): acceder a `window.localStorage` lanza `SecurityError`. La función lo detecta (`isStorageAccessDenied`) y devuelve `{}` legítimo, no error — el storage queda vacío en el JSON. **Pero** un error REAL (conexión caída, JS roto, JSON inválido) ahora SÍ se propaga y aborta el guardado: antes se tragaba en silencio y escribía una sesión incompleta que parecía válida.
- **Permisos**: el archivo se escribe con `0644`; asegúrate de que el directorio de destino existe antes de llamar a la función.

## Capability growth log

- v1.1.0 (2026-06-06) — `readWebStorage` distingue "origen sin storage accesible" (SecurityError → `{}`) de "error real de evaluación" (se propaga); `CdpSaveStorageState` aborta en error real en vez de guardar sesión incompleta en silencio; captura también sessionStorage; test del discriminador `isStorageAccessDenied` + del matcher `cookieDomainMatchesHost`.
