---
seo_title: API de Captura de Pantalla Web | Página Completa | EnConvert
meta_desc: Captura screenshots de página completa como PNG con POST /v1/convert/url-to-screenshot. Cierra banners de cookies, carga contenido lazy y devuelve URLs prefirmadas.
keywords: api de captura de pantalla de sitios web, capturar screenshot de una url, api para tomar capturas de pantalla, screenshot de página completa api, alternativa a puppeteer para capturas, capturar pantalla completa de una web por api, api captura pantalla png, tomar captura de pantalla de una web programáticamente
---

# API de Capturas de Pantalla de Sitios Web

El endpoint `POST /v1/convert/url-to-screenshot` captura una captura de pantalla de página completa de cualquier URL de acceso público como una imagen PNG de alta fidelidad. Gestiona automáticamente banners de cookies, modales, contenido de carga diferida, animaciones activadas por scroll y encabezados fijos (sticky) para producir una captura limpia y precisa. Ejecútalo de forma síncrona para obtener una URL de descarga prefirmada o los bytes PNG en bruto, o usa el modo asíncrono para capturar varias URLs en un lote (batch).

---

## Endpoint

```
POST /v1/convert/url-to-screenshot
```

**Content-Type:** `application/json`

**Formato de salida:** PNG (siempre). El formato de salida no es configurable: todas las capturas se generan como imágenes PNG de página completa.

---

## Autenticación

Este endpoint admite autenticación tanto con clave privada como con clave pública.

### Clave Privada

Incluye tu clave secreta en el header `X-API-Key`. Úsala para llamadas servidor a servidor donde la clave nunca se expone al cliente.

```
X-API-Key: sk_your_private_key
```

### Clave Pública con JWT

Para uso en el cliente, primero genera un token JWT usando tu clave pública y luego pásalo como token Bearer.

**Paso 1 -- Obtén un token:**

```
POST /v1/auth/token
X-API-Key: pk_your_public_key
```

**Paso 2 -- Usa el token:**

```
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
```

<div class="alert alert-info">
<strong>Nota:</strong> Las solicitudes con clave pública están restringidas a una sola URL, modo síncrono y descarga directa. El modo asíncrono, el procesamiento por lotes, los webhooks y los correos de notificación no están disponibles con claves públicas.
</div>

---

## Parámetros de la Solicitud

### Parámetros de Nivel Superior

| Parámetro | Tipo | Obligatorio | Predeterminado | Descripción | Restricción de Plan |
|-----------|------|----------|---------|-------------|-------------|
| `url` | `string` o `string[]` | Sí | -- | Una cadena de URL única o un array de URLs para capturar. Varias URLs requieren modo asíncrono. | -- |
| `async_mode` | `boolean` | No | `false` | Ejecuta la captura de forma asíncrona. Devuelve un `batch_id` inmediatamente. Obligatorio para lotes (múltiples URLs). | Requiere acceso asíncrono |
| `direct_download` | `boolean` | No | `false` | Devuelve los bytes PNG en bruto en el cuerpo de la respuesta en lugar de una respuesta JSON con una URL prefirmada. Se fuerza a `true` para claves públicas. Incompatible con `async_mode` y con varias URLs. | -- |
| `output_format` | `boolean` | No | `false` | Cuando es `true` con varias URLs, agrupa todos los PNG de salida en un único archivo ZIP. Requiere varias URLs. | Requiere acceso a salida ZIP |
| `output_filename` | `string` | No | Generado automáticamente | Nombre de archivo personalizado para el archivo de salida. La extensión `.png` se añade automáticamente. Formato predeterminado: `{domain}_{timestamp}.png`. | -- |
| `job_id` | `string` | No | -- | ID de job proporcionado por el cliente para recuperación ante timeout. **Solo claves públicas.** Cuando una conversión síncrona supera los límites de timeout del proxy inverso, el cliente puede sondear `GET /v1/convert/status/{job_id}` para obtener el resultado. Se ignora en claves privadas. | -- |
| `notification_email` | `string` | No | Email del propietario del proyecto | Dirección de email a notificar cuando finaliza un job asíncrono. Solo claves privadas. | -- |
| `callback_url` | `string` | No | -- | URL de webhook que recibe una solicitud POST cuando finaliza la captura. Solo claves privadas. | Requiere acceso a webhooks |

### Parámetros de Navegador y Renderizado

| Parámetro | Tipo | Obligatorio | Predeterminado | Descripción | Restricción de Plan |
|-----------|------|----------|---------|-------------|-------------|
| `viewport_width` | `integer` | No | `1920` | Ancho del viewport del navegador en píxeles. El ancho de la captura coincide con este valor. | -- |
| `viewport_height` | `integer` | No | `1080` | Alto del viewport del navegador en píxeles. Se usa como referencia para el renderizado y el cálculo de unidades de viewport. El alto real de la captura lo determina el alto completo del contenido de la página. | -- |
| `load_media` | `boolean` | No | `true` | Espera a que todas las imágenes y videos terminen de cargar antes de capturar. Cuando es `false`, la captura es más rápida pero los medios pueden aparecer como placeholders. | -- |
| `enable_scroll` | `boolean` | No | `true` | Recorre la página de arriba a abajo con scroll para activar el contenido de carga diferida (loaders basados en IntersectionObserver). | -- |
| `handle_sticky_header` | `boolean` | No | `true` | Detecta encabezados sticky/fijos y hace scroll hasta arriba antes de capturar para que el encabezado se renderice correctamente en la parte superior de la captura. | -- |
| `handle_cookies` | `boolean` | No | `true` | Cierra automáticamente los banners de consentimiento de cookies (OneTrust, Cookiebot, Didomi, Usercentrics y banners genéricos). | -- |
| `wait_for_images` | `boolean` | No | `true` | Espera a que todos los elementos `<img>` terminen de cargar (timeout de 5 segundos por imagen). | -- |
| `wait_for_selector` | `string` | No | `null` | Selector CSS que se espera antes de la captura. Devuelve `422` si nunca aparece dentro de `wait_for_selector_timeout`. Útil para SPAs que hidratan el contenido después de la carga. | -- |
| `wait_for_selector_timeout` | `integer` | No | `10000` | Milisegundos de espera para `wait_for_selector` (máximo `60000`). | -- |
| `block_ads` | `boolean` | No | `false` | Aborta las solicitudes a dominios conocidos de anuncios/rastreadores para que nunca se carguen, rendericen ni ralenticen la captura. | -- |
| `block_media` | `boolean` | No | `false` | Aborta por completo las solicitudes de imágenes y audio/vídeo para un renderizado más rápido y ligero. A diferencia de `load_media` (que solo controla la espera), esto evita por completo que los medios se descarguen. | -- |

### Autenticación y Solicitudes Personalizadas

| Parámetro | Tipo | Obligatorio | Predeterminado | Descripción | Restricción de Plan |
|-----------|------|----------|---------|-------------|-------------|
| `auth` | `object` | No | `null` | Credenciales de HTTP Basic Auth para la URL de destino. Formato: `{"username": "...", "password": "..."}`. No se puede usar junto con un header `Authorization` personalizado. | Requiere acceso a basic auth |
| `cookies` | `array` | No | `null` | Array de objetos de cookie a inyectar antes de la navegación. Máximo 50 cookies. Cada cookie debe tener `name`, `value` y `domain` o `url`. | Requiere acceso a basic auth |
| `headers` | `object` | No | `null` | Diccionario de headers HTTP personalizados enviados en cada solicitud a la URL de destino. Máximo 20 headers. Headers bloqueados: `host`, `content-length`, `transfer-encoding`, `connection`, `upgrade`, `te`, `trailer`. | Requiere acceso a basic auth |

<div class="alert alert-warning">
<strong>No compatible:</strong> Los parámetros <code>single_page</code> y <code>pdf_options</code> del endpoint <a href="/es/docs/endpoints/convert/web-pages/url-to-pdf">url-to-pdf</a> no son aplicables a las capturas de pantalla. Las capturas siempre capturan la página completa como una única imagen continua.
</div>

---

## Esquema del Objeto Cookie

Cada elemento del array `cookies` debe seguir esta estructura:

| Campo | Tipo | Obligatorio | Predeterminado | Descripción |
|-------|------|----------|---------|-------------|
| `name` | `string` | Sí | -- | Nombre de la cookie. |
| `value` | `string` | Sí | -- | Valor de la cookie. |
| `domain` | `string` | Condicional | -- | Dominio de la cookie. Se debe proporcionar `domain` o `url`. |
| `url` | `string` | Condicional | -- | URL con la que asociar la cookie. Se debe proporcionar `domain` o `url`. |
| `path` | `string` | No | `"/"` | Ruta de la cookie. Por defecto es `"/"` cuando se establece `domain`. |

---

## Respuesta

### Síncrono con Descarga Directa (`direct_download=true`)

**Clave privada** -- devuelve los bytes PNG en bruto:

```
HTTP 200 OK
Content-Type: image/png
Content-Disposition: inline; filename="example_20260405_123456789.png"
X-Object-Key: env/files/{project_id}/url-to-screenshot/example_20260405_123456789.png
X-File-Size: 456789
X-Conversion-Time: 8.2
X-Filename: example_20260405_123456789.png

(binary PNG data)
```

**Clave pública** -- devuelve JSON con una URL prefirmada:

```json
{
    "presigned_url": "https://spaces.example.com/...",
    "object_key": "env/files/{project_id}/url-to-screenshot/example_20260405_123456789.png",
    "filename": "example_20260405_123456789.png",
    "file_size": 456789,
    "conversion_time_seconds": 8.2,
    "job_id": "client-provided-id"
}
```

### Síncrono sin Descarga Directa (`direct_download=false`)

Disponible solo con claves privadas.

```json
{
    "presigned_url": "https://spaces.example.com/...",
    "object_key": "env/files/{project_id}/url-to-screenshot/example_20260405_123456789.png",
    "filename": "example_20260405_123456789.png",
    "file_size": 456789,
    "conversion_time_seconds": 8.2
}
```

### Modo Asíncrono

Devuelve inmediatamente un `batch_id` para seguimiento.

```
HTTP 202 Accepted
```

```json
{
    "status": "processing",
    "batch_id": "550e8400-e29b-41d4-a716-446655440000",
    "url_count": 5,
    "output_format": "individual"
}
```

Cuando `output_format=true` (agrupación en ZIP):

```json
{
    "status": "processing",
    "batch_id": "550e8400-e29b-41d4-a716-446655440000",
    "url_count": 5,
    "output_format": "zip"
}
```

### Sondeo de Estado del Job (Solo Claves Públicas)

Para recuperación ante timeout con clave pública:

```
GET /v1/convert/status/{job_id}
Authorization: Bearer <jwt_token>
```

| Estado | Respuesta |
|--------|----------|
| Procesando | `{"status": "processing"}` |
| Éxito | `{"status": "success", "presigned_url": "...", "object_key": "..."}` |
| Fallido | `{"status": "failed", "error": "..."}` |

### Sondeo de Estado de Lote (Solo Claves Privadas)

Para jobs de lote asíncronos, sondea con el `batch_id` de la respuesta 202:

```
GET /v1/convert/batch/{batch_id}
X-API-Key: sk_your_private_key
```

Devuelve el estado agregado, los estados por URL y las URLs de descarga prefirmadas. Consulta [Sondeo de Estado de Lote](/es/docs/endpoints/convert/web-pages/url-to-pdf.md#batch-status-polling-private-keys-only) para ver el esquema de respuesta completo.

### Payload del Webhook de Callback

Cuando se proporciona un `callback_url`, EnConvert envía una solicitud POST a esa URL al finalizar.

**Job de una sola URL:**

```json
{
    "job_id": "activity_id",
    "status": "success",
    "batch_id": "...",
    "gcs_uri": "object_key",
    "filename": "example_20260405_123456789.png",
    "file_size": 456789
}
```

**Job de lote:**

```json
{
    "job_id": "activity_id",
    "status": "success",
    "batch_id": "...",
    "total_tasks": 10,
    "successful_tasks": 8,
    "failed_tasks": 2,
    "tasks": [
        {"url": "https://example.com/page1", "status": "success", "filename": "page1.png"},
        {"url": "https://example.com/page2", "status": "failed", "filename": null}
    ]
}
```

---

## Funcionalidades

### Captura de Página Completa

Cada captura incluye **todo el contenido de la página**, no solo el viewport visible. El conversor:

1. Renderiza la página con los valores especificados de `viewport_width` y `viewport_height`
2. Recorre la página con scroll para activar todo el contenido de carga diferida
3. Calcula el alto real del contenido usando un recorrido del árbol DOM que mide la posición inferior máxima de todos los elementos visibles
4. Redimensiona el viewport para abarcar todo el alto del contenido
5. Captura la pantalla con `full_page=true`

El resultado es una única imagen PNG alargada de la página completa.

### Modo de Captura Limpia

EnConvert gestiona automáticamente los obstáculos habituales de las páginas web para producir capturas limpias:

- **Banners de consentimiento de cookies** -- Cierra automáticamente banners de OneTrust, Cookiebot, Didomi, Usercentrics e implementaciones genéricas. Funciona en la página principal y en iframes.
- **Cierre de modales y popups** -- Cierra overlays usando varias estrategias: tecla Escape, botones de cierre ARIA, botones de cierre basados en clase (`"Close"`, `"Not now"`, `"No thanks"`, `"Skip"`) y botones de diálogo basados en role. Elimina los efectos residuales de blur, backdrop e inert tras el cierre.
- **Revelado de animaciones por scroll** -- Fuerza la visibilidad de elementos ocultos por librerías de animación activadas por scroll, incluyendo WOW.js, AOS, ScrollReveal, GSAP ScrollTrigger y clases de animación genéricas (`.fadeIn`, `.slideIn`, etc.). También revela todos los slides de Swiper.
- **Limpieza de dropdowns** -- Cierra todos los dropdowns abiertos, convierte los elementos button de navegación en enlaces anchor reales para que se mantengan visualmente limpios, oculta los elementos `role="menu"` y reposiciona los encabezados fijos a posición static.

### Normalización de Unidades de Viewport

Las capturas requieren un manejo especial de las unidades de viewport de CSS (`vh`, `svh`, `lvh`, `dvh`) porque el viewport se redimensiona al alto completo de la página. Sin normalización, los elementos dimensionados con unidades de viewport se estirarían a tamaños enormes. El conversor:

- Convierte todas las unidades relativas al viewport en valores de píxeles fijos basados en el alto de viewport original
- Limita las imágenes y videos anormalmente altos a 1.5 veces el alto de viewport original
- Gestiona particularidades de altura específicas de Elementor (contenedores flex, efectos de movimiento, contenedores de fondo)
- Preserva las dimensiones de video durante el proceso de normalización

### HTTP Basic Auth

Pasa `auth` con `username` y `password` para capturar páginas protegidas con HTTP Basic Authentication.

```json
{
    "url": "https://staging.example.com/dashboard",
    "auth": {
        "username": "admin",
        "password": "secret"
    }
}
```

### Inyección de Cookies

Inyecta hasta 50 cookies antes de que cargue la página. Útil para capturar páginas que requieren una sesión activa.

```json
{
    "url": "https://example.com/dashboard",
    "cookies": [
        {"name": "session_id", "value": "abc123", "domain": "example.com"},
        {"name": "locale", "value": "en-US", "domain": "example.com"}
    ]
}
```

### Headers Personalizados

Envía hasta 20 headers HTTP personalizados en cada solicitud a la página de destino.

```json
{
    "url": "https://example.com/report",
    "headers": {
        "X-Custom-Token": "my-token-value",
        "Accept-Language": "en-US"
    }
}
```

### Carga Diferida de Imágenes

Cuando `load_media` y `enable_scroll` están habilitados (ambos por defecto en `true`), el conversor recorre la página lentamente con scroll (120px cada 90ms) para activar los loaders diferidos y luego espera a que todas las imágenes terminen de cargar, con un periodo de estabilización de layout de 500ms.

Establece `load_media=false` para una captura más rápida: el conversor usa scroll rápido (300px cada 30ms) con una estabilización más corta de 100ms, pero los medios pueden aparecer como placeholders.

### Manejo de Encabezados Sticky

Cuando está habilitado (por defecto `true`), el conversor detecta elementos con posición fixed y sticky que parecen ser encabezados, los reposiciona a posición static para una captura limpia, y hace scroll hasta arriba de la página antes de capturar.

### Funcionalidades Adicionales de Renderizado

- **Emulación de medio screen** -- La página se renderiza usando el medio CSS `screen` (no `print`), de modo que la captura coincide con lo que los usuarios ven en su navegador.
- **Modo stealth** -- Usa enmascaramiento de fingerprint del navegador para evitar la detección de bots en páginas protegidas.
- **Intercepción de popups** -- Cierra automáticamente cualquier pestaña nueva del navegador o popup activado por la página.
- **Bypass de CSP** -- Gestiona las restricciones de Content Security Policy y Trusted Types que de otro modo bloquearían la manipulación de la página.
- **Preservación de sombras** -- Los elementos con `box-shadow` y `text-shadow` se etiquetan para garantizar que las sombras se rendericen correctamente en la captura de salida.

---

## Restricciones por Plan de Suscripción

| Funcionalidad | Founding | Indie | Studio | Enterprise |
|---------|------|---------|-----|------------|
| Captura básica (una URL, síncrona) | Sí | Sí | Sí | Sí |
| Dimensionamiento de viewport | Sí | Sí | Sí | Sí |
| Modo asíncrono | No | Sí | Sí | Sí |
| Procesamiento por lotes (varias URLs) | No | Sí | Sí | Sí |
| Agrupación de salida en ZIP | No | No | Sí | Sí |
| Callbacks de webhook | No | No | Sí | Sí |
| HTTP Basic Auth | No | Sí | Sí | Sí |
| Inyección de cookies | No | Sí | Sí | Sí |
| Headers personalizados | No | Sí | Sí | Sí |
| Conversiones mensuales | 100 | Según el plan | Según el plan | Ilimitadas |
| Límite de tamaño de lote | 0 | Según el plan | Según el plan | Ilimitado |
| Retención de archivos | 1 hora | Según el plan | Según el plan | Según el plan |

---

## Modo Asíncrono

El modo asíncrono es útil para capturas de larga duración o al capturar varias URLs.

### Cómo Funciona

1. Envía una solicitud con `async_mode=true` (o pasa varias URLs, lo que habilita el modo asíncrono automáticamente).
2. La API devuelve HTTP 202 inmediatamente con un `batch_id` y un `url_count`.
3. Cada URL se captura en segundo plano, se sube al almacenamiento y se rastrea individualmente.
4. Supervisa la finalización mediante **sondeo de estado de lote**, **notificación por email** o **callback de webhook**.

### Notificación por Email

Por defecto, se envía un email de finalización a la dirección de correo del propietario del proyecto. Puedes anularlo con `notification_email`:

```json
{
    "url": ["https://example.com/page1", "https://example.com/page2"],
    "async_mode": true,
    "notification_email": "team@example.com"
}
```

### Callback de Webhook

Proporciona un `callback_url` para recibir una notificación POST automática al finalizar:

```json
{
    "url": ["https://example.com/page1", "https://example.com/page2"],
    "async_mode": true,
    "callback_url": "https://your-server.com/webhook/enconvert"
}
```

---

## Procesamiento por Lotes y en Volumen

Captura varias URLs en una sola solicitud. Requiere modo asíncrono y una clave privada.

### Salida Individual (predeterminado)

Cada URL genera un archivo PNG separado:

```json
{
    "url": [
        "https://example.com/page1",
        "https://example.com/page2",
        "https://example.com/page3"
    ],
    "async_mode": true
}
```

### Salida en Paquete ZIP

Agrupa todas las capturas en un único archivo ZIP:

```json
{
    "url": [
        "https://example.com/page1",
        "https://example.com/page2",
        "https://example.com/page3"
    ],
    "async_mode": true,
    "output_format": true,
    "output_filename": "monthly-screenshots"
}
```

---

## Ejemplos de Código

### Python (Clave Privada)

```python
import requests

response = requests.post(
    "https://api.enconvert.com/v1/convert/url-to-screenshot",
    headers={"X-API-Key": "sk_your_private_key"},
    json={
        "url": "https://example.com",
        "viewport_width": 1440,
        "viewport_height": 900
    }
)

data = response.json()
print(data["presigned_url"])
```

### PHP (Clave Privada)

```php
$ch = curl_init("https://api.enconvert.com/v1/convert/url-to-screenshot");
curl_setopt_array($ch, [
    CURLOPT_POST => true,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        "Content-Type: application/json",
        "X-API-Key: sk_your_private_key"
    ],
    CURLOPT_POSTFIELDS => json_encode([
        "url" => "https://example.com",
        "viewport_width" => 1440,
        "viewport_height" => 900
    ])
]);

$response = curl_exec($ch);
curl_close($ch);

$data = json_decode($response, true);
echo $data["presigned_url"];
```

### Node.js (Clave Privada)

```javascript
const response = await fetch("https://api.enconvert.com/v1/convert/url-to-screenshot", {
    method: "POST",
    headers: {
        "Content-Type": "application/json",
        "X-API-Key": "sk_your_private_key"
    },
    body: JSON.stringify({
        url: "https://example.com",
        viewport_width: 1440,
        viewport_height: 900
    })
});

const data = await response.json();
console.log(data.presigned_url);
```

### Go (Clave Privada)

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "net/http"
)

func main() {
    body, _ := json.Marshal(map[string]interface{}{
        "url":             "https://example.com",
        "viewport_width":  1440,
        "viewport_height": 900,
    })

    req, _ := http.NewRequest("POST", "https://api.enconvert.com/v1/convert/url-to-screenshot", bytes.NewBuffer(body))
    req.Header.Set("Content-Type", "application/json")
    req.Header.Set("X-API-Key", "sk_your_private_key")

    resp, _ := http.DefaultClient.Do(req)
    defer resp.Body.Close()

    respBody, _ := io.ReadAll(resp.Body)
    fmt.Println(string(respBody))
}
```

### JavaScript -- Navegador (Clave Pública)

```javascript
// Step 1: Get a JWT token
const tokenRes = await fetch("https://api.enconvert.com/v1/auth/token", {
    method: "POST",
    headers: { "X-API-Key": "pk_your_public_key" }
});
const { token } = await tokenRes.json();

// Step 2: Capture screenshot
const convertRes = await fetch("https://api.enconvert.com/v1/convert/url-to-screenshot", {
    method: "POST",
    headers: {
        "Content-Type": "application/json",
        "Authorization": `Bearer ${token}`
    },
    body: JSON.stringify({
        url: "https://example.com"
    })
});

const data = await convertRes.json();
// Display the screenshot
const img = document.createElement("img");
img.src = data.presigned_url;
document.body.appendChild(img);
```

### React (Clave Pública)

```jsx
import { useState } from "react";

function UrlToScreenshot() {
    const [loading, setLoading] = useState(false);
    const [imageUrl, setImageUrl] = useState(null);

    async function captureScreenshot() {
        setLoading(true);
        try {
            // Get JWT token
            const tokenRes = await fetch("https://api.enconvert.com/v1/auth/token", {
                method: "POST",
                headers: { "X-API-Key": "pk_your_public_key" }
            });
            const { token } = await tokenRes.json();

            // Capture screenshot
            const convertRes = await fetch("https://api.enconvert.com/v1/convert/url-to-screenshot", {
                method: "POST",
                headers: {
                    "Content-Type": "application/json",
                    "Authorization": `Bearer ${token}`
                },
                body: JSON.stringify({ url: "https://example.com" })
            });

            const data = await convertRes.json();
            setImageUrl(data.presigned_url);
        } finally {
            setLoading(false);
        }
    }

    return (
        <div>
            <button onClick={captureScreenshot} disabled={loading}>
                {loading ? "Capturing..." : "Take Screenshot"}
            </button>
            {imageUrl && <img src={imageUrl} alt="Screenshot" style={{ maxWidth: "100%" }} />}
        </div>
    );
}

export default UrlToScreenshot;
```

---

## Respuestas de Error

| Estado | Condición |
|--------|-----------|
| `400 Bad Request` | Parámetro `url` faltante o vacío |
| `400 Bad Request` | `output_format=true` con una sola URL (requiere varias URLs) |
| `400 Bad Request` | `direct_download=true` con varias URLs |
| `400 Bad Request` | `direct_download=true` con `async_mode=true` |
| `400 Bad Request` | Objeto `auth` inválido (falta `username` o `password`) |
| `400 Bad Request` | `cookies` inválido (no es un array, supera las 50 entradas, faltan campos obligatorios) |
| `400 Bad Request` | `headers` inválido (no es un objeto, supera las 20 entradas, nombres de header bloqueados, valores no string) |
| `400 Bad Request` | Conflicto entre `auth` y el header `Authorization` personalizado |
| `400 Bad Request` | Clave pública intentando usar varias URLs |
| `401 Unauthorized` | Clave de API o token JWT faltante o inválido |
| `402 Payment Required` | Cuota mensual de ops agotada |
| `402 Payment Required` | El lote superaría la cuota mensual de ops restante |
| `402 Payment Required` | Límite de almacenamiento alcanzado |
| `403 Forbidden` | El endpoint no está entre los endpoints permitidos de la clave de API |
| `403 Forbidden` | Funcionalidad no disponible en el plan actual (async, webhook, ZIP, basic auth) |
| `403 Forbidden` | El tamaño del lote supera el límite de lote del plan |
| `404 Not Found` | ID de job no encontrado (al sondear el estado) |
| `500 Internal Server Error` | Fallo en la captura (crash del navegador, error de renderizado) |

---

## Límites

| Límite | Valor |
|-------|-------|
| Timeout de navegación de página | 60 segundos |
| Timeout de carga por imagen | 5 segundos |
| Timeout de cierre de banner de cookies | 3 segundos |
| Máximo de cookies por solicitud | 50 |
| Máximo de headers personalizados por solicitud | 20 |
| Operaciones mensuales | Según el plan (Founding: 500) |
| Tamaño de lote | Según el plan (Founding: deshabilitado) |
| Retención de archivos | Según el plan (Founding: 1 hora) |
| Timeout de entrega de webhook | 30 segundos |

---

## Preguntas frecuentes

### ¿Cómo tomo una captura de pantalla de página completa de un sitio web con una API?

Envía una solicitud `POST` a `/v1/convert/url-to-screenshot` con un cuerpo JSON que contenga `url`, autenticándote con tu clave privada en el header `X-API-Key` (o un token Bearer JWT de una clave pública). Cada captura incluye todo el contenido de la página, no solo el viewport visible: el conversor redimensiona el viewport al alto completo del contenido y captura con `full_page=true`.

### ¿Puedo cambiar el formato de salida de la captura a JPEG o WebP?

No. El formato de salida no es configurable: todas las capturas se generan como imágenes PNG de página completa.

### ¿Cómo controlo el ancho y el tamaño de la captura?

Establece `viewport_width` (por defecto `1920`): el ancho de la captura coincide con este valor. El alto de la captura lo determina el alto completo del contenido de la página, usando `viewport_height` (por defecto `1080`) como referencia para el renderizado y el cálculo de unidades de viewport.

### ¿Puedo capturar una página protegida por login?

Sí. Usa el parámetro `auth` para HTTP Basic Auth, inyecta hasta 50 cookies de sesión con `cookies`, o envía hasta 20 headers HTTP personalizados con `headers`. Estas opciones requieren acceso a basic auth en tu plan.

### ¿Cómo elimina la API los banners de cookies y popups de las capturas?

Con `handle_cookies` habilitado (por defecto `true`), el conversor cierra automáticamente los banners de consentimiento de OneTrust, Cookiebot, Didomi, Usercentrics e implementaciones genéricas, funcionando tanto en la página principal como en iframes. Los modales y popups se cierran usando la tecla Escape, botones de cierre ARIA, botones de cierre basados en clase y botones de diálogo basados en role, eliminando los efectos residuales de blur y backdrop.
