> ## 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 Guia de Integração da API de Renderização de Páginas

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

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

A API de Renderização de Páginas WebExtrator é um serviço de renderização de páginas baseado em Chromium sem cabeça. Dado um URL, retorna o HTML completamente renderizado (incluindo conteúdo injetado por JS), texto puro, título da página e URL final.

Render é a interface mais básica do WebExtrator. Se você precisar de resultados de extração **estruturados** (corpo do artigo, preço do produto, ingredientes da receita...), use [`/webextrator/extract`](development_webextrator_extract) — que executa um pipeline de extração tipificada sobre a mesma base de renderização.

## Processo de Solicitação

Para usar a página de serviços do WebExtrator, primeiro acesse o [Console da Ace Data Cloud](https://platform.acedata.cloud/console/applications) para obter seu Token de API, que deve ser guardado para uso futuro.

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

Se você ainda não estiver logado ou registrado, será redirecionado automaticamente para a página de login, onde será convidado a se registrar e logar; após a conclusão, você será redirecionado de volta para a página atual.

**Um Token de API é suficiente para acessar todos os serviços da plataforma, não sendo necessário solicitar um para cada serviço individualmente.** A primeira solicitação oferece um crédito gratuito, permitindo uma experiência sem custo; quando o crédito acabar, você pode recarregar o saldo geral no [console](https://platform.acedata.cloud/console/coin).

> 📘 Documentação completa: [Página de serviços do WebExtrator →](https://platform.acedata.cloud/service/webextrator)

## Autenticação

Todas as interfaces do WebExtrator utilizam autenticação padrão com Bearer Token:

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

## Parâmetros de Solicitação

| Campo               | Tipo      | Obrigatório | Padrão                     | Descrição                                                                                                                                 |
| ------------------- | --------- | :---------: | -------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- |
| `url`               | string    |      ✅      | —                          | URL da página a ser renderizada, deve ser `http(s)://`.                                                                                   |
| `user_agent`        | string    |      ❌      | Pool de UA embutido        | User-Agent personalizado.                                                                                                                 |
| `timeout`           | number    |      ❌      | `30`                       | Tempo limite de navegação (em **segundos**).                                                                                              |
| `wait_until`        | enum      |      ❌      | `networkidle`              | Evento de carregamento concluído: `load` / `domcontentloaded` / `networkidle` / `commit`.                                                 |
| `delay`             | number    |      ❌      | `0`                        | **Tempo extra de espera em segundos** após o gatilho de `wait_until` (para re-renderização de SPA).                                       |
| `wait_for_selector` | string    |      ❌      | —                          | Aguarde a aparição deste seletor CSS, mais estável que `networkidle`.                                                                     |
| `block_resources`   | string\[] |      ❌      | `["image","font","media"]` | Tipos de recursos a serem bloqueados, opções: `image` / `font` / `media` / `stylesheet` / `xhr` / `fetch`.                                |
| `headers`           | object    |      ❌      | —                          | Cabeçalhos HTTP adicionais (por exemplo, `{"Accept-Language": "en-US"}`).                                                                 |
| `cookies`           | array     |      ❌      | —                          | Cookies injetados antes da navegação, estrutura conforme abaixo.                                                                          |
| `callback_url`      | string    |      ❌      | —                          | Endereço de callback no modo assíncrono, a plataforma `POST` os resultados completos para este endereço quando a tarefa for concluída.    |
| `bypass_cache`      | boolean   |      ❌      | `false`                    | Ignorar leitura do cache Redis (mas ainda gravará o resultado atual no cache).                                                            |
| `cache_ttl_seconds` | number    |      ❌      | `3600`                     | TTL de cache personalizado para esta gravação, passar `0` indica que não deve ser armazenada a resposta atual.                            |
| `async`             | boolean   |      ❌      | `false`                    | Defina como `true` para retornar imediatamente `task_id`, o resultado pode ser recuperado através de `callback_url` ou da API de Tarefas. |

> O contrato da plataforma utiliza uniformemente **snake\_case**. O serviço de renderização interno suporta camelCase, mas todas as chamadas externas utilizam snake\_case.

### Estrutura do Cookie

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

## Resposta Sincrona

```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           | Descrição                                                                     |
| -------------------- | -------------- | ----------------------------------------------------------------------------- |
| `data.kind`          | string         | Fixo `"render"`.                                                              |
| `data.url`           | string         | O URL que você enviou.                                                        |
| `data.finalUrl`      | string         | URL final após seguir redirecionamentos.                                      |
| `data.title`         | string         | `document.title` após a renderização.                                         |
| `data.status`        | number \| null | Código de status HTTP da navegação principal.                                 |
| `data.html`          | string         | HTML completo após a renderização.                                            |
| `data.text`          | string         | Captura de `document.body.innerText` (para um corpo mais limpo, use Extract). |
| `data.userAgent`     | string         | UA realmente utilizado.                                                       |
| `data.elapsedMs`     | number         | Tempo gasto apenas na renderização do navegador.                              |
| `data.cached`        | boolean?       | `true` se o cache foi atingido.                                               |
| `data.cacheStoredAt` | number?        | Timestamp Unix em milissegundos da primeira gravação da entrada de cache.     |

## Resposta Assíncrona

Quando `async=true` (ou fornecendo `callback_url`), retorna imediatamente (HTTP 200):

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

Os resultados serão enviados via `POST` para `callback_url` (se configurado), ou consultados ativamente através de [`/webextrator/tasks`](development_webextrator_tasks).

### Estrutura de Callback

A plataforma `POST` um envelope **exatamente igual** ao modo síncrono para `callback_url`, `Content-Type: application/json`. Retornar qualquer `2xx` é considerado uma confirmação; `5xx` será refeito com um backoff exponencial por cerca de 5 minutos.

## Resposta de Erro

| HTTP | `error.code`     | Significado                                                                                  |
| ---- | ---------------- | -------------------------------------------------------------------------------------------- |
| 400  | `bad_request`    | O corpo da solicitação não passou na validação do Zod (falta `url`, tipo incorreto …).       |
| 401  | `unauthorized`   | `Authorization: Bearer …` ausente ou inválido.                                               |
| 402  | (x402)           | Saldo da plataforma insuficiente, retorna envelope de pagamento x402.                        |
| 408  | `timeout`        | Navegação excedeu o `timeout`.                                                               |
| 429  | `queue_busy`     | Fila de sincronização congestionada, por favor, tente novamente ou use `async=true`.         |
| 500  | `internal_error` | Exceção não tratada no servidor (como falha do navegador), o Worker tenta novamente uma vez. |

Estrutura de erro:

```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: URL inválido" }
}
```

## Exemplo

### 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);
```

### Assíncrono + 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"
  }'
```

Retorna imediatamente `{ "success": true, "task_id": "...", "trace_id": "...", "started_at": 1777717800.123 }`;
Quando a tarefa for concluída, a plataforma fará um POST com o resultado completo para o seu `callback_url`.

### Forçar Bypass de Cache

```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
  }'
```

## Dicas e Armadilhas

* **Escolher corretamente `wait_until` é muito importante.** `networkidle` é o mais estável, mas o mais lento; `domcontentloaded` é rápido, mas pode perder conteúdo injetado assíncrono; `load` é adequado para páginas estáticas tradicionais.
* **A chave de cache ignora `async`.** Solicitações síncronas e assíncronas para a mesma URL atingem a mesma entrada de cache, alternar aleatoriamente não invalidará.
* **A chave de cache ignora `bypass_cache` e `cache_ttl_seconds`.** Esses dois são interruptores de operação, não afetam o conteúdo da resposta.
* **`cookies` e `headers` terão cache em buckets separados.** Personalizar esses dois fará com que a primeira combinação idêntica falhe.
* **SPAs pesadas frequentemente excedem os 30 segundos padrão.** Recomenda-se `timeout: 60`, `wait_until: "domcontentloaded"`, `delay: 4`, e usar `wait_for_selector` para esperar os elementos realmente importantes.
* **`block_resources` é o caminho mais rápido para reduzir a latência.** Por padrão, imagens / fontes / mídias já estão bloqueadas; se você extrair sem depender do layout CSS, adicionar `stylesheet` pode acelerar ainda mais.
