extract_embedded_state
Los sitios modernos serializan los datos que muestra su interfaz directamente en el documento. Esta herramienta los recupera: una sola descarga, valores exactos y ningún modelo en la ruta de extracción.
Casos de uso
Precios exactos de páginas renderizadas con JavaScript
Los precios, las existencias y los identificadores proceden del propio estado del sitio y no de un modelo que lee el texto renderizado, así que no hay nada que inventar.
Listados que un scraping normal no ve
Los resultados de búsqueda y las cuadrículas de productos que se renderizan en el cliente suelen estar ya presentes en __NEXT_DATA__ o en una carga RSC en la primera respuesta.
Más barato que una extracción con LLM
2 credits frente a 3 de extract_with_llm o extract_structured, y sin ningún paso de inferencia que esperar.
Auditar lo que un sitio publica sobre sí mismo
found informa de todas las fuentes de estado de la página y de su tamaño, que a menudo es más de lo que muestra la interfaz visible.
Endpoint
/api/v1/tools/extract_embedded_stateParameters
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
url | string | Required | - | Página de la que se leerá el estado incrustado. Example: https://example.com/products/widget |
path | string | Optional | - | Devuelve un solo subárbol en lugar de toda la carga. Únicamente claves separadas por puntos e índices de array: esto no es JSONPath, así que no hay comodines, filtros, segmentos ni descenso recursivo. Una ruta que no se resuelve devuelve un 400 que nombra las claves disponibles en el punto donde se detuvo, y no consume credits. Example: next_data.props.pageProps |
user_agent | string | Optional | - | Sustituye el User-Agent enviado al destino. La solicitud sigue firmada como CrawlForge; la firma cubre la autoridad, no esta cabecera. Example: MyCompanyBot/1.0 |
respect_robots | boolean | Optional | true | Respeta el robots.txt del sitio de destino. Con el valor `true`, una ruta no permitida para `CrawlForge` se rechaza con 403 antes de descargar nada y no se cobran credits. Establézcalo en `false` solo para un destino con el que tenga su propio acuerdo: la respuesta incluirá entonces una entrada `warnings` y la anulación queda registrada en su API key. Example: true |
timeout | number | Optional | 20000 | Tiempo de espera de la descarga en milisegundos, entre 1000 y 60000. Las cargas de estado suelen ocupar megabytes, por lo que el valor predeterminado es mayor que en las herramientas de extracción más ligeras. Example: 20000 |
max_inline_chars | number | Optional | 40000 | Umbral de tamaño en línea, en caracteres del JSON del resultado (de 1.000 a 10.000.000). `extract_embedded_state` nunca se trunca (el estado completo llega siempre en línea), pero por encima de este tamaño la respuesta incluye además `result_handle`, `total_chars` y `truncated: false`, de modo que [read_result](/docs/api-reference/tools/read-result) puede buscar en la copia almacenada o leer de ella un solo `json_path` por 1 credit por llamada. Los resultados almacenados se conservan 1 hora. Example: 40000 |
Ejemplos de solicitud
cURL - Leer todo el estado
curl -X POST https://crawlforge.dev/api/v1/tools/extract_embedded_state \
-H "X-API-Key: cf_test_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com/products/widget"
}'TypeScript - Acotarlo con una ruta
// npm install crawlforge-sdk
import { CrawlForge, ValidationError } from 'crawlforge-sdk';
const client = new CrawlForge({ apiKey: process.env.CRAWLFORGE_API_KEY });
try {
const result = await client.extractEmbeddedState({
url: 'https://example.com/products/widget',
// Dotted keys and array indexes. Not JSONPath: no wildcards or filters.
path: 'next_data.props.pageProps',
});
// result.data is untyped in crawlforge-sdk 0.1 — its shape is the Response Example below.
const { found, data } = result.data as {
found: { name: string; variable: string; bytes: number }[];
data: { product: { price: number } };
};
// Every state source on the page, largest first, whether or not it was scoped.
for (const source of found) {
console.log(source.name, source.variable, source.bytes);
}
// The values are the site's own, so they can be used as they are.
console.log(data.product.price);
} catch (err) {
// A path that does not resolve is a 400 naming the keys that were available.
if (err instanceof ValidationError) {
console.error(err.message);
} else {
throw err;
}
}Python - Descubrir y luego acotar
# pip install crawlforge
from crawlforge import CrawlForge
client = CrawlForge() # reads CRAWLFORGE_API_KEY
# 1. Discover what the page carries. Nothing is truncated, so this can be big.
discovery = client.extract_embedded_state(
url='https://example.com/products/widget',
)
# discovery.data is a plain dict — its shape is the Response Example below.
for source in discovery.data['found']:
print(source['name'], source['variable'], source['bytes'])
# This tool's warnings live inside data, next to the state itself.
for warning in discovery.data['warnings']:
print('warning:', warning)
# 2. Ask again for just the branch you want.
scoped = client.extract_embedded_state(
url='https://example.com/products/widget',
path='next_data.props.pageProps.product',
)
print(scoped.data['bytes'], 'bytes')
print(scoped.data['data'])Ejemplo de respuesta
{ "success": true, "data": { "url": "https://example.com/products/widget", "found": [ { "name": "next_data", "variable": "__NEXT_DATA__", "bytes": 412880 } ], "path": null, "bytes": 412893, "data": { "next_data": { "buildId": "KfC_3GF1zuM", "props": { "pageProps": { "product": { "sku": "WID-9001", "price": 149.99, "currency": "USD", "inStock": true } } } } }, "warnings": [ "Result is 412893 bytes; \"next_data\" alone is 412880. Re-run with path to scope it, e.g. path:\"next_data.props\"." ] }, "credits_used": 2, "credits_remaining": 998, "processing_time": 980}data.foundTodas las fuentes de estado de la página, con el elemento del que se leyeron y su tamaño serializadodata.pathLa ruta aplicada, o null cuando se devolvió toda la cargadata.bytesTamaño serializado de lo que se devuelve, ya acotado cuando se indicó una rutadata.dataEl estado en sí, indexado por nombre de fuentedata.warningsFuentes presentes pero no analizables como JSON, y la indicación de tamaño que sugiere usar una rutaGestión de errores
La ruta no se resolvió (400 Bad Request)
El valor de path no existe en el estado extraído. El mensaje nombra el punto donde se detuvo y las claves disponibles allí, de modo que un error tipográfico se puede corregir. No se cobran credits. Ejecute la llamada una vez sin path para ver qué contiene realmente la página.
Bloqueado por robots.txt (403 Forbidden)
El robots.txt del sitio de destino no permite esta ruta a CrawlForge. Establezca respect_robots: false para anularlo si tiene su propio acuerdo con el destino: la anulación queda registrada en su API key. La anulación no alcanza a un host incluido en la lista de exclusión permanente de CrawlForge, que se rechaza sea cual sea el valor de respect_robots.
Respuesta demasiado grande (413 Payload Too Large)
El HTML de la página supera el límite de 25MB de cuerpo. El límite se aplica a la página tal como se sirve, no al estado extraído de ella. No se cobra nada.
El destino no respondió (504 Gateway Timeout)
El sitio no respondió dentro de timeout. Las páginas con mucho estado son grandes; suba timeout hacia su techo de 60000 antes de considerarlo un fallo. No se cobra nada.