API de Capturas de Pantalla de Sitios Web#

El endpoint POST /v1/convert/website-to-screenshot descubre cada página de un sitio web (mediante análisis de sitemap o un rastreo completo en anchura), captura una captura de pantalla PNG de página completa de cada página, y agrupa los resultados en un único archivo ZIP. Los trabajos siempre se ejecutan de forma asíncrona: la API devuelve HTTP 202 con un batch_id de inmediato, la finalización se señala mediante sondeo del estado del batch, un callback de webhook, o una notificación por correo electrónico, y la respuesta del estado del batch incluye una URL de descarga prefirmada para el ZIP terminado. Requiere un plan de pago y una clave de API privada.


Endpoint#

POST /v1/convert/website-to-screenshot

Content-Type: application/json

Formato de salida: Archivo ZIP que contiene una captura de pantalla PNG por cada página descubierta.

Modo: Siempre asíncrono. Devuelve HTTP 202 de inmediato.


Autenticación#

Este endpoint requiere una clave de API privada. Las claves públicas no son compatibles con la captura de sitios web.

X-API-Key: sk_your_private_key

Parámetros de la solicitud#

Parámetros de descubrimiento del sitio web#

Parámetro Tipo Requerido Predeterminado Descripción Restricción por plan
url string -- La URL base del sitio web (p. ej. https://example.com). Se usa como raíz para el descubrimiento de páginas. --
crawl_mode string No "auto" Método de descubrimiento de URLs. Uno de "auto", "sitemap", o "full". Consulta Modos de rastreo más abajo. Sitemap requiere Indie+, Full requiere Studio+
include_patterns string[] No null Patrones regex para incluir en lista blanca las URLs descubiertas. Solo se usa en el modo de rastreo full. --
exclude_patterns string[] No Valores predeterminados del sistema Patrones regex para poner en lista negra las URLs. Solo se usa en el modo de rastreo full. Cuando se omite, usa valores predeterminados integrados que excluyen recursos estáticos, páginas de login/admin/carrito, y paginación profunda. --

Parámetros de notificación#

Parámetro Tipo Requerido Predeterminado Descripción Restricción por plan
output_filename string No Generado automáticamente Nombre base personalizado para el archivo ZIP de salida. La marca de tiempo se añade automáticamente. --
notification_email string No Correo del propietario del proyecto Dirección de correo electrónico para notificar cuando el trabajo finalice. --
callback_url string No -- URL de webhook para recibir una solicitud POST al finalizar. Requiere acceso a webhooks

Parámetros del navegador y renderizado#

Estos ajustes se aplican a la captura de cada página individual dentro del sitio web.

Parámetro Tipo Requerido Predeterminado Descripción Restricción por 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. --
load_media boolean No true Espera a que todas las imágenes y videos terminen de cargar antes de la captura. --
enable_scroll boolean No true Desplaza cada página para activar contenido con carga diferida. --
handle_sticky_header boolean No true Detecta encabezados fijos (sticky/fixed) y los gestiona antes de la captura. --
handle_cookies boolean No true Cierra automáticamente los banners de consentimiento de cookies. --
wait_for_images boolean No true Espera a que todos los elementos <img> terminen de cargar. --
wait_for_selector string No null Selector CSS que se espera antes de la captura, aplicado a cada página. 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 Requerido Predeterminado Descripción Restricción por plan
auth object No null Credenciales de HTTP Basic Auth aplicadas a cada página. Formato: {"username": "...", "password": "..."}. Requiere acceso a autenticación básica
cookies array No null Array de objetos de cookies inyectados antes de cada carga de página. Máximo 50 cookies. Requiere acceso a autenticación básica
headers object No null Encabezados HTTP personalizados enviados con cada solicitud. Máximo 20 encabezados. Requiere acceso a autenticación básica
No compatible: Los parámetros single_page y pdf_options no son aplicables a las capturas de pantalla. Cada página siempre se captura como una única imagen PNG de página completa.

Modos de rastreo#

"auto" (predeterminado)#

Usa el modo de rastreo más alto que permite tu plan. Si tu plan admite rastreo completo, ejecuta un rastreo completo. Si tu plan solo admite sitemap, ejecuta descubrimiento por sitemap.

"sitemap"#

Descubre páginas analizando el sitemap.xml del sitio web:

  1. Obtiene {base_url}/sitemap.xml (tiempo límite de 30 segundos)
  2. Si el elemento raíz es <sitemapindex>, obtiene recursivamente cada sitemap hijo
  3. Extrae todas las entradas <url><loc> de los elementos <urlset>
  4. Devuelve la lista completa de URLs descubiertas

Devuelve un error si falta el sitemap, si devuelve un estado distinto de 200, si contiene XML inválido, o si no tiene URLs.

"full"#

Realiza un rastreo exhaustivo en dos fases:

Fase 1 -- Descubrimiento de semillas:

  1. Analiza robots.txt en busca de directivas de sitemap y reglas de rastreo
  2. Verifica rutas estándar de sitemap (/sitemap.xml, /wp-sitemap.xml, /sitemap_index.xml, etc.)
  3. Descubre feeds RSS/Atom a partir de etiquetas <link> y rutas de feed comunes
  4. Extrae URLs semilla de todas las fuentes descubiertas

Fase 2 -- Rastreo de enlaces en anchura:

  1. Comienza desde la URL base más todas las URLs semilla
  2. Visita cada página y encola los enlaces del mismo dominio
  3. Aplica include_patterns y exclude_patterns para filtrar enlaces
  4. Respeta las reglas de robots.txt
  5. Detecta y evita trampas de URL infinitas (páginas de calendario, filtros facetados, etc.)
  6. Deduplica URLs normalizando el esquema, el host, los parámetros de consulta, y eliminando parámetros de seguimiento (utm_*, fbclid, gclid, etc.)

Patrones de exclusión predeterminados (cuando no se proporciona exclude_patterns):

  • Recursos estáticos: *.pdf, *.zip, *.jpg, *.png, *.gif, *.svg, *.css, *.js, *.xml, *.json, *.mp4, *.webm, *.woff, *.woff2
  • Rutas protegidas: /login, /admin, /cart, /checkout
  • Paginación profunda: URLs con parámetros page= que superan los 3 dígitos

Respuesta#

202 Accepted (inmediato)#

{
    "status": "processing",
    "batch_id": "550e8400-e29b-41d4-a716-446655440000",
    "url_count": 42,
    "total_discovered": 42,
    "discovery_method": "sitemap",
    "output_format": "zip"
}
Campo Descripción
batch_id UUID para hacer seguimiento del trabajo mediante sondeo del estado del batch o webhook.
url_count Número de páginas que se capturarán.
total_discovered Total de páginas descubiertas por el rastreo.
discovery_method "sitemap" o "full_crawl" según el modo de rastreo efectivo.

Sondeo del estado del batch#

Consulta 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 una URL de descarga prefirmada para el ZIP cuando finaliza. Consulta Sondeo del estado del batch para ver el esquema completo de la respuesta.

Payload del callback de webhook#

Cuando se proporciona callback_url, EnConvert envía una solicitud POST al finalizar:

{
    "job_id": "batch-uuid",
    "status": "success",
    "batch_id": "550e8400-e29b-41d4-a716-446655440000",
    "gcs_uri": "env/files/{project_id}/url-to-screenshot/website_20260405_123456789.zip",
    "filename": "website_20260405_123456789.zip",
    "file_size": 12345678,
    "total_tasks": 42,
    "successful_tasks": 40,
    "failed_tasks": 2,
    "tasks": [
        {"url": "https://example.com/", "status": "success", "filename": "example_20260405_001.png"},
        {"url": "https://example.com/about", "status": "success", "filename": "example_20260405_002.png"},
        {"url": "https://example.com/broken", "status": "failed", "error": "Timeout"}
    ]
}

Notificación por correo electrónico#

Se envía un correo de finalización a notification_email (o al correo del propietario del proyecto por defecto) cuando el trabajo termina, independientemente de si tuvo éxito o falló.


Restricciones por plan de suscripción#

Función Founding Indie Studio Enterprise
Captura de sitio web No
Modo de rastreo por sitemap No
Modo de rastreo completo No No
Callbacks de webhook No No
HTTP Basic Auth No
Inyección de cookies No
Encabezados personalizados No
Límite de tamaño de batch 0 Según el plan Según el plan Ilimitado
Conversiones mensuales 100 Según el plan Según el plan Ilimitado
Plan Founding: La captura de sitios web no está disponible en el plan gratuito. Intentar usar este endpoint devuelve 403 Forbidden.

Ejemplos de código#

Python (clave privada)#

import requests
import time

# Start the website capture
response = requests.post(
    "https://api.enconvert.com/v1/convert/website-to-screenshot",
    headers={"X-API-Key": "sk_your_private_key"},
    json={
        "url": "https://example.com",
        "crawl_mode": "sitemap",
        "output_filename": "example-screenshots",
        "viewport_width": 1440,
        "viewport_height": 900
    }
)

data = response.json()
print(f"Batch ID: {data['batch_id']}")
print(f"Pages found: {data['url_count']}")

# Poll for completion
batch_id = data["batch_id"]
while True:
    status = requests.get(
        f"https://api.enconvert.com/v1/convert/batch/{batch_id}",
        headers={"X-API-Key": "sk_your_private_key"}
    ).json()

    print(f"Status: {status['status']} ({status['completed']}/{status['total']})")

    if status["status"] in ("completed", "partial", "failed"):
        if status.get("zip_download_url"):
            print(f"Download: {status['zip_download_url']}")
        break

    time.sleep(5)

PHP (clave privada)#

$ch = curl_init("https://api.enconvert.com/v1/convert/website-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",
        "crawl_mode" => "sitemap",
        "output_filename" => "example-screenshots",
        "viewport_width" => 1440,
        "viewport_height" => 900
    ])
]);

$response = json_decode(curl_exec($ch), true);
curl_close($ch);

echo "Batch ID: " . $response["batch_id"] . "\n";
echo "Pages found: " . $response["url_count"] . "\n";

Node.js (clave privada)#

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

const data = await response.json();
console.log(`Batch ID: ${data.batch_id}`);
console.log(`Pages found: ${data.url_count}`);

// Poll for completion
const poll = async () => {
    const status = await fetch(
        `https://api.enconvert.com/v1/convert/batch/${data.batch_id}`,
        { headers: { "X-API-Key": "sk_your_private_key" } }
    ).then(r => r.json());

    console.log(`Status: ${status.status} (${status.completed}/${status.total})`);

    if (["completed", "partial", "failed"].includes(status.status)) {
        if (status.zip_download_url) console.log(`Download: ${status.zip_download_url}`);
        return;
    }
    setTimeout(poll, 5000);
};
poll();

Go (clave privada)#

package main

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

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

    req, _ := http.NewRequest("POST", "https://api.enconvert.com/v1/convert/website-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))
}

Con callback de webhook#

{
    "url": "https://example.com",
    "crawl_mode": "full",
    "callback_url": "https://your-server.com/webhook/enconvert",
    "output_filename": "example-full-site-screenshots",
    "include_patterns": [".*\\/blog\\/.*", ".*\\/docs\\/.*"]
}

Con autenticación (sitio protegido con contraseña)#

{
    "url": "https://staging.example.com",
    "crawl_mode": "sitemap",
    "auth": {
        "username": "admin",
        "password": "staging-password"
    },
    "cookies": [
        {"name": "session_token", "value": "abc123", "domain": "staging.example.com"}
    ]
}

Respuestas de error#

Estado Condición
400 Bad Request Falta el parámetro url o está vacío
400 Bad Request No se encontraron URLs en el sitemap
400 Bad Request Tiempo de espera agotado al obtener el sitemap (límite de 30 segundos)
400 Bad Request Respuesta distinta de 200 desde la URL del sitemap
400 Bad Request XML inválido en el sitemap
400 Bad Request Formato de sitemap no reconocido
400 Bad Request No se descubrieron páginas (el rastreo completo encontró cero URLs)
400 Bad Request Estructura inválida de auth, cookies, o headers
402 Payment Required El número de páginas descubiertas supera la cuota mensual de ops
402 Payment Required Se alcanzó el límite de almacenamiento
403 Forbidden El rastreo de sitios web no está disponible en el plan actual (plan Founding)
403 Forbidden El modo de rastreo completo requiere el plan Studio o superior
403 Forbidden El número de páginas descubiertas supera el límite de tamaño del batch
403 Forbidden Función no disponible en el plan (webhook, autenticación básica)
500 Internal Server Error Fallo de rastreo o de captura

Límites#

Límite Valor
Tiempo límite para obtener el sitemap 30 segundos
Tiempo límite global de rastreo (modo full) 10 minutos
Profundidad máxima de rastreo (modo full) 10 niveles
Tiempo límite de rastreo por página (modo full) 30 segundos
Límite de memoria del rastreador 512 MB
Umbral de trampa infinita 20 URLs por patrón de URL
Tiempo límite para obtener robots.txt 10 segundos
Máximo de páginas por rastreo Límite de tamaño de batch del plan
Máximo de cookies por solicitud 50
Máximo de encabezados personalizados por solicitud 20
Tiempo límite de entrega de webhook 30 segundos
Conversiones mensuales Según el plan
Retención de archivos Según el plan

Preguntas frecuentes#

¿Cómo capturo cada página de un sitio web con una API?#

Envía una solicitud POST a /v1/convert/website-to-screenshot con la url base del sitio y tu clave privada en el encabezado X-API-Key. La API descubre cada página (sitemap o rastreo completo), captura un PNG de página completa de cada una, las agrupa en un archivo ZIP, y devuelve HTTP 202 con un batch_id que puedes sondear para obtener el enlace de descarga.

¿Puedo controlar el tamaño o el formato de las capturas de pantalla?#

El ancho de la captura coincide con viewport_width (predeterminado 1920), y viewport_height se usa como referencia de renderizado. Cada página siempre se captura como un único PNG de página completa. Los parámetros single_page y pdf_options no se aplican a las capturas de pantalla.

¿Cómo descargo las capturas de pantalla cuando el trabajo finaliza?#

Sondea GET /v1/convert/batch/{batch_id} con tu clave privada para obtener el estado agregado, los estados por URL, y una URL de descarga prefirmada del ZIP, o pasa un callback_url para recibir un POST de webhook al finalizar. También se envía un correo de finalización a notification_email (o al propietario del proyecto por defecto).

¿Puedo capturar un sitio protegido con contraseña o en staging?#

Sí, en planes con acceso a autenticación básica: pasa auth con username y password para aplicar HTTP Basic Auth a cada página, inyecta hasta 50 cookies de sesión, o envía hasta 20 headers personalizados.

¿Por qué el endpoint de captura de pantalla de sitios web devuelve 403 Forbidden?#

Las causas más comunes: la captura de sitios web no está disponible en el plan Founding, crawl_mode: "full" requiere Studio o superior, el número de páginas descubiertas supera el límite de tamaño de batch de tu plan, o una función solicitada (webhook, autenticación básica) no está incluida en tu plan.