> ## Documentation Index
> Fetch the complete documentation index at: https://docs.acedata.cloud/llms.txt
> Use this file to discover all available pages before exploring further.

# WebExtrator Guía de Integración de API de Renderizado de Páginas

> WebExtrator Web Render & Extract API guide - Ace Data Cloud

`POST https://api.acedata.cloud/webextrator/render`

La API de renderizado de páginas WebExtrator es un servicio de renderizado de páginas basado en Chromium sin cabeza. Dado un URL, devuelve el HTML completamente renderizado (incluido el contenido inyectado por JS), texto plano, título de la página y URL final.

Render es la interfaz más básica de WebExtrator. Si necesitas resultados de extracción **estructurados** (cuerpo del artículo, precios de productos, ingredientes de recetas...), por favor utiliza [`/webextrator/extract`](development_webextrator_extract) — que ejecuta un conjunto completo de tuberías de extracción tipificadas sobre la misma base de renderizado.

## Proceso de Solicitud

Para utilizar la página de servicios de WebExtrator, primero ve a [la consola de Ace Data Cloud](https://platform.acedata.cloud/console/applications) para obtener tu Token de API, guárdalo para uso futuro.

![](https://cdn.acedata.cloud/5hmkdg.jpg)

Si aún no has iniciado sesión o registrado, serás redirigido automáticamente a la página de inicio de sesión que te invita a registrarte e iniciar sesión, y después volverás automáticamente a la página actual.

**Un Token de API es suficiente para acceder a todos los servicios de la plataforma, no es necesario solicitar uno por cada servicio.** La primera solicitud te otorgará un crédito gratuito para que lo pruebes; si el crédito es insuficiente, puedes recargar el saldo general en [la consola](https://platform.acedata.cloud/console/coin).

> 📘 Documentación completa: [Página de servicios de WebExtrator →](https://platform.acedata.cloud/service/webextrator)

## Autenticación

Todas las interfaces de WebExtrator utilizan autenticación estándar con Bearer Token:

```
Authorization: Bearer YOUR_API_KEY
Content-Type:  application/json
```

## Parámetros de Solicitud

| Campo               | Tipo      | Requerido | Predeterminado             | Descripción                                                                                                                             |
| ------------------- | --------- | :-------: | -------------------------- | --------------------------------------------------------------------------------------------------------------------------------------- |
| `url`               | string    |     ✅     | —                          | URL de la página a renderizar, debe ser `http(s)://`.                                                                                   |
| `user_agent`        | string    |     ❌     | Rotación de UA incorporada | User-Agent personalizado.                                                                                                               |
| `timeout`           | number    |     ❌     | `30`                       | Tiempo de espera para una navegación única (**segundos**).                                                                              |
| `wait_until`        | enum      |     ❌     | `networkidle`              | Evento de carga completada: `load` / `domcontentloaded` / `networkidle` / `commit`.                                                     |
| `delay`             | number    |     ❌     | `0`                        | **Segundos de espera adicionales** después de que se active `wait_until` (para re-renderizado de SPA).                                  |
| `wait_for_selector` | string    |     ❌     | —                          | Espera a que aparezca este selector CSS, más estable que `networkidle`.                                                                 |
| `block_resources`   | string\[] |     ❌     | `["image","font","media"]` | Tipos de recursos bloqueados, opcionales: `image` / `font` / `media` / `stylesheet` / `xhr` / `fetch`.                                  |
| `headers`           | object    |     ❌     | —                          | Encabezados HTTP adicionales (por ejemplo, `{"Accept-Language": "en-US"}`).                                                             |
| `cookies`           | array     |     ❌     | —                          | Cookies inyectadas antes de la navegación, estructura a continuación.                                                                   |
| `callback_url`      | string    |     ❌     | —                          | Dirección de callback en modo asíncrono, la plataforma `POST` los resultados completos a esta dirección cuando la tarea se complete.    |
| `bypass_cache`      | boolean   |     ❌     | `false`                    | Omitir la lectura de caché de Redis (pero aún escribirá el resultado en caché).                                                         |
| `cache_ttl_seconds` | number    |     ❌     | `3600`                     | TTL de caché personalizado para esta escritura, pasar `0` significa no almacenar en caché esta respuesta.                               |
| `async`             | boolean   |     ❌     | `false`                    | Si se establece en `true`, devuelve inmediatamente `task_id`, los resultados se recuperan a través de `callback_url` o la API de Tasks. |

> El contrato de la plataforma utiliza **snake\_case** de manera uniforme. Los servicios de renderizado internos admiten camelCase, pero todas las llamadas externas utilizan snake\_case.

### Estructura de Cookies

```json theme={null}
{
  "name":      "string",
  "value":     "string",
  "domain":    "string",
  "path":      "/",
  "expires":   1735689600,
  "httpOnly":  false,
  "secure":    true,
  "sameSite":  "Lax"
}
```

## Respuesta Sincrónica

```json theme={null}
{
  "success": true,
  "task_id": "550e8400-e29b-41d4-a716-446655440000",
  "trace_id": "550e8400-e29b-41d4-a716-446655440001",
  "started_at": 1777717800.123,
  "finished_at": 1777717801.234,
  "elapsed": 1.111,
  "data": {
    "kind": "render",
    "url": "https://example.com",
    "finalUrl": "https://example.com/",
    "title": "Example Domain",
    "status": 200,
    "html": "<!DOCTYPE html><html>...</html>",
    "text": "Example Domain\nThis domain is for use in illustrative examples...",
    "userAgent": "Mozilla/5.0 ...",
    "elapsedMs": 1108
  }
}
```

| Campo                | Tipo           | Descripción                                                                                  |
| -------------------- | -------------- | -------------------------------------------------------------------------------------------- |
| `data.kind`          | string         | Fijo `"render"`.                                                                             |
| `data.url`           | string         | El URL que enviaste.                                                                         |
| `data.finalUrl`      | string         | URL final después de seguir redirecciones.                                                   |
| `data.title`         | string         | `document.title` después de renderizar.                                                      |
| `data.status`        | number \| null | Código de estado HTTP de la navegación principal.                                            |
| `data.html`          | string         | HTML completo después de renderizar.                                                         |
| `data.text`          | string         | Instantánea de `document.body.innerText` (para un cuerpo más limpio, usa Extract).           |
| `data.userAgent`     | string         | UA realmente utilizada.                                                                      |
| `data.elapsedMs`     | number         | Solo el tiempo de renderizado del navegador.                                                 |
| `data.cached`        | boolean?       | `true` si se accedió a la caché.                                                             |
| `data.cacheStoredAt` | number?        | Marca de tiempo Unix en milisegundos cuando se escribió la entrada de caché por primera vez. |

## Respuesta Asincrónica

Cuando `async=true` (o se proporciona `callback_url`), devuelve inmediatamente (HTTP 200):

```json theme={null}
{
  "success": true,
  "task_id": "550e8400-...",
  "trace_id": "6ba7b810-...",
  "started_at": 1777717800.123
}
```

Los resultados se enviarán a `callback_url` mediante `POST` (si está configurado), o se pueden consultar activamente a través de [`/webextrator/tasks`](development_webextrator_tasks).

### Estructura de Callback

La plataforma `POST` un envelope **exactamente igual** al modo sincrónico a `callback_url`, `Content-Type: application/json`. Devolver cualquier `2xx` se considera confirmado; `5xx` se reintentará con retroceso exponencial durante aproximadamente 5 minutos.

## Respuesta de Error

| HTTP | `error.code`     | 含义                                                                                                                 |
| ---- | ---------------- | ------------------------------------------------------------------------------------------------------------------ |
| 400  | `bad_request`    | El cuerpo de la solicitud no pasó la validación de Zod (falta `url`, tipo incorrecto, …).                          |
| 401  | `unauthorized`   | Falta o es inválido el `Authorization: Bearer …`.                                                                  |
| 402  | (x402)           | Saldo insuficiente en la plataforma, devuelve x402 solicitud de pago envelope.                                     |
| 408  | `timeout`        | La navegación excedió el `timeout`.                                                                                |
| 429  | `queue_busy`     | La cola de sincronización está ocupada, por favor intente de nuevo o use `async=true`.                             |
| 500  | `internal_error` | Excepción no manejada en el servidor (como un fallo del navegador), el Worker reintentará automáticamente una vez. |

Estructura de error:

```json theme={null}
{
  "success": false,
  "task_id": "...",
  "trace_id": "...",
  "started_at": 1777717800.123,
  "finished_at": 1777717800.135,
  "elapsed": 0.012,
  "error": { "code": "bad_request", "message": "url: Invalid url" }
}
```

## Ejemplo

### cURL

```bash theme={null}
curl -X POST https://api.acedata.cloud/webextrator/render \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com",
    "wait_until": "networkidle",
    "block_resources": ["image", "media", "font"]
  }'
```

### Python (requests)

```python theme={null}
import os, requests

API_KEY = os.environ["ACEDATA_API_KEY"]

resp = requests.post(
    "https://api.acedata.cloud/webextrator/render",
    headers={
        "Authorization": f"Bearer {API_KEY}",
        "Content-Type": "application/json",
    },
    json={
        "url": "https://example.com",
        "wait_until": "networkidle",
        "block_resources": ["image", "media", "font"],
    },
    timeout=60,
)
resp.raise_for_status()
data = resp.json()["data"]
print(data["title"], data["status"], len(data["html"]))
```

### Node.js (fetch)

```js theme={null}
const apiKey = process.env.ACEDATA_API_KEY;

const res = await fetch('https://api.acedata.cloud/webextrator/render', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${apiKey}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    url: 'https://example.com',
    wait_until: 'networkidle',
    block_resources: ['image', 'media', 'font'],
  }),
});
const { data } = await res.json();
console.log(data.title, data.status, data.html.length);
```

### Asincrónico + Callback

```bash theme={null}
curl -X POST https://api.acedata.cloud/webextrator/render \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com",
    "async": true,
    "callback_url": "https://your-app.example.com/hooks/webextrator"
  }'
```

Devuelve inmediatamente `{ "success": true, "task_id": "...", "trace_id": "...", "started_at": 1777717800.123 }`; cuando la tarea se complete, la plataforma enviará los resultados completos a tu `callback_url`.

### Forzar eludir caché

```bash theme={null}
curl -X POST https://api.acedata.cloud/webextrator/render \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com",
    "bypass_cache": true
  }'
```

## Consejos y trampas

* **Es importante elegir correctamente `wait_until`.** `networkidle` es el más estable pero el más lento; `domcontentloaded` es rápido pero puede perder contenido inyectado de forma asíncrona; `load` es adecuado para páginas estáticas tradicionales.
* **La clave de caché ignora `async`.** Las solicitudes sincrónicas y asincrónicas para la misma URL golpean la misma entrada de caché, cambiar entre ellas no invalidará.
* **La clave de caché ignora `bypass_cache` y `cache_ttl_seconds`.** Estos dos son interruptores de operación, no afectan el contenido de la respuesta.
* **Las `cookies` y `headers` se almacenan en caché por separado.** Personalizar estos dos hará que la primera combinación idéntica falle.
* **Las SPA pesadas a menudo superan los 30 segundos predeterminados.** Se recomienda `timeout: 60`, `wait_until: "domcontentloaded"`, `delay: 4`, junto con `wait_for_selector` para esperar los elementos que realmente importan.
* **`block_resources` es el camino más rápido para reducir la latencia.** Por defecto, ya se bloquean imágenes / fuentes / medios; si tu extracción no depende del diseño CSS, agregar `stylesheet` puede hacerlo aún más rápido.
