API Documentación
URL base: https://glanceshot.com/v1. Todos los endpoints usan HTTP estándar. Puedes enviar los parámetros en la cadena de consulta (GET) o en el cuerpo JSON (POST).
Inicio rápido
- Regístrate gratis y crea una API Key en la página «API Key» de la consola.
- Incluye la API Key en la cabecera
X-Access-Keyy llama al endpoint de capturas:
curl "https://glanceshot.com/v1/screenshot?url=https://example.com&full_page=true" \
-H "X-Access-Key: $GLANCESHOT_KEY" \
-o screenshot.pngAutenticación
Todas las peticiones requieren una API Key. Puedes enviarla de cualquiera de estas formas:
- Cabecera
X-Access-Key: gls_…(recomendada para llamadas desde el servidor) - Parámetro de consulta
access_key=gls_…(solo para llamadas desde el servidor; no lo incluyas en páginas web) - URL firmada (para incluir la dirección en una página web sin exponer la API Key ni el secreto)
La API Key solo se muestra en texto plano una vez, al crearla. Guárdala en un lugar seguro. Si se filtra, puedes desactivarla en la consola.
Endpoint de capturas
/v1/screenshot/v1/screenshotParámetros exclusivos de las capturas:
| Parámetro | Tipo | Valor predeterminado | Descripción |
|---|---|---|---|
| format | enum | png | png, jpeg o webp. |
| device_scale_factor | number | 1 | Factor de escala, 1–3. Con 2 se obtiene nitidez Retina y un tamaño de archivo aproximadamente 4 veces mayor. |
| quality | integer | 80 | Calidad JPEG / WebP, 1–100. |
| full_page | boolean | false | Captura la página completa. Se desplaza por ella para activar la carga diferida, con un límite de altura de 20,000 píxeles. |
| selector | string | — | Captura solo el primer elemento que coincida con este selector CSS. No se puede combinar con full_page. |
Parámetros comunes a capturas y PDF:
| Parámetro | Tipo | Valor predeterminado | Descripción |
|---|---|---|---|
| url | string | — | URL de la página que quieres capturar, con http o https. Debes indicar este parámetro o html, pero no ambos. Se conserva el fragmento # de la URL, por lo que puedes capturar directamente páginas de aplicaciones de página única con rutas hash, como https://app.com/#/report/1. |
| html | string | — | HTML enviado directamente (máximo 2 MB). Solo admite POST. |
| viewport_width | integer | 1280 | Ancho del área de visualización, 320–3840. Con valores inferiores a 768, se renderiza como en un dispositivo móvil. |
| viewport_height | integer | 800 | Alto del área de visualización, 200–3840. |
| wait_until | enum | networkidle | Estrategia de espera: domcontentloaded (la más rápida, ideal para páginas estáticas), load o networkidle (supervisa todas las peticiones desde que se abre la página; tras la carga, espera hasta que no haya peticiones en curso durante 500 milisegundos, con un máximo de 8 segundos adicionales; ideal para aplicaciones de página única). |
| wait_for_selector | string | — | Tras cargar la página, espera hasta 10 segundos a que aparezca y sea visible un elemento que coincida con este selector CSS antes de capturar. Si no aparece, devuelve selector_not_found (sin coste). Ideal para aplicaciones de página única que renderizan contenido con temporizadores o animaciones, sin depender de peticiones de red, como .chart-ready. |
| delay | integer | 0 | Espera adicional en milisegundos una vez completada la espera inicial, 0–10000. Útil para animaciones o componentes con carga diferida. |
| block_ads | boolean | true | Bloquea las solicitudes a dominios de publicidad y rastreo y oculta los espacios publicitarios de la página. |
| block_cookie_banners | boolean | true | Oculta los avisos de consentimiento de cookies. |
| dark_mode | boolean | false | Emula prefers-color-scheme: dark. |
| hide_selectors | string | — | Lista de selectores CSS de los elementos que quieres ocultar, por ejemplo, .ad,#popup. |
| cache | boolean | true | Indica si se consulta la caché. Con false, fuerza un nuevo renderizado, pero el resultado se sigue guardando en caché. |
| cache_ttl | integer | 86400 | Tiempo de validez de la caché en segundos, 60–2592000. |
| response_type | enum | binary | binary devuelve el archivo directamente; json devuelve la URL del archivo y sus metadatos. |
| proxy | string | — | Opcional. Usa tu propio proxy para acceder a la página de destino (el coste del proxy corre por tu cuenta), por ejemplo, si necesitas acceder desde un país o una región específicos. Admite socks5:// y http://, con usuario y contraseña opcionales, en el formato socks5://user:pass@203.0.113.10:1080. Solo se puede incluir en el cuerpo de una solicitud POST; no está disponible para solicitudes GET, URL firmadas ni tareas por lotes. Las solicitudes que usan un proxy se almacenan en caché por separado. Si no se puede conectar con el proxy, falla la autenticación o el proxy no puede acceder al sitio de destino, se devuelve proxy_failed y no se cobra la solicitud. |
| cookies | string | object[] | — | Cookies del sitio de destino, en una sola línea como sid=abc; theme=dark o en un array como [{"name":"sid","value":"abc"}] (puede incluir domain y path). Solo se envían al sitio de destino, no a terceros presentes en la página. |
| headers | object | — | Cabeceras de solicitud que se añadirán, como Authorization: Bearer …. Solo se envían al sitio de destino; no se pueden definir las que gestiona el navegador (Host, Cookie, User-Agent, etc.). |
| local_storage | object | — | Datos que se escribirán en el localStorage del origen de la URL de destino. Tanto las claves como los valores deben ser cadenas de texto. |
| session_storage | object | — | Igual que local_storage, pero escribe en sessionStorage. |
| login_profile | string | — | Identificador del perfil de sesión guardado con la extensión del navegador (lp_8f2c…). Es más cómodo que enviar cookies directamente y también se puede usar en tareas por lotes (las tareas no almacenan credenciales). |
Capturar aplicaciones de página única (React, Vue, etc.):La página ejecuta JavaScript en un navegador real antes de capturarse. La opción predeterminada, networkidle, espera a que termine la descarga de datos. Si el contenido se renderiza después mediante temporizadores o animaciones, añade wait_for_selector para indicar un elemento que confirme que está listo. Si no hay un elemento adecuado, usa delay para esperar un poco más.
Endpoint de PDF
/v1/pdf/v1/pdfCada PDF consume 2 créditos. Antes de imprimir, se recorre la página para activar el contenido con carga diferida. Además de los parámetros comunes, admite:
| Parámetro | Tipo | Valor predeterminado | Descripción |
|---|---|---|---|
| paper | enum | a4 | Formato de papel: a4 o letter. Si la página incluye una regla @page, se da prioridad a sus ajustes. |
| print_background | boolean | true | Imprime los colores y las imágenes de fondo. |
| pdf_media | enum | print usa los estilos de impresión; screen usa los estilos de pantalla (tal como se ve en el navegador). |
curl -X POST "https://glanceshot.com/v1/pdf" \
-H "X-Access-Key: $GLANCESHOT_KEY" \
-H "Content-Type: application/json" \
-d '{"html": "<h1>Informe trimestral</h1><p>Contenido…</p>", "paper": "a4"}' \
-o report.pdfRespuestas
Por defecto (response_type=binary), se devuelve el archivo directamente, con Content-Type correspondiente a su formato. Cabeceras de respuesta:
X-Request-Id: ID de esta petición; inclúyelo al comunicar un problemaX-Glanceshot-Cache:HIToMISSX-Glanceshot-Truncated: true: la página completa se ha recortado por superar los 20,000 píxelesX-Glanceshot-Format-Changed: webp: el PNG supera los 5 MB y se ha convertido automáticamente a WebP (no se convierte si se especifica format=png de forma explícita)
Con response_type=json, se devuelven la URL del archivo y sus metadatos:
curl -X POST "https://glanceshot.com/v1/screenshot" \
-H "X-Access-Key: $GLANCESHOT_KEY" \
-H "Content-Type: application/json" \
-d '{"url": "https://example.com", "response_type": "json"}'
# Devuelve
{
"url": "https://glanceshot.com/i/3f/3f9c….png",
"cache_hit": false,
"duration_ms": 1284,
"format": "png",
"width": 1280,
"height": 800,
"request_id": "req_01j…"
}URL firmadas
¿Quieres usar la dirección de una captura directamente en <img src> sin exponer tu API Key? Las URL firmadas no incluyen la API Key, solo el identificador público key_id. La firma se calcula en tu servidor con el secreto asociado a esa clave. Puedes consultar el ID de la clave y su secreto en la sección API Key de la consola:
canonical = Ordena todos los parámetros, salvo signature, por nombre en orden lexicográfico.
Codifica cada par k=urlencode(v) según RFC 3986 (los espacios como %20) y únelos con &
signature = hex(HMAC-SHA256(secret, canonical))Una firma válida autentica la solicitud. Si falta o es incorrecta, la solicitud se rechaza. Cualquier cambio en los parámetros (por ejemplo, en url) invalida la firma. El parámetro opcional expires (tiempo Unix en segundos) se incluye en la firma; una vez caducado, se devuelve signature_expired. Para renovar la caché, basta con cambiar un parámetro sin efecto (como v=2) y volver a firmar la URL. Las URL firmadas solo admiten solicitudes GET a los endpoints de capturas y PDF, y no pueden incluir parámetros de proxy.
key_id es público y, por sí solo, no permite llamar a la API. No incluyas la API Key (access_key) en una URL firmada: si la incluyes, se devolverá invalid_params directamente. Si ya has incluido una API Key en una página web, desactívala en la consola y crea una nueva.
import crypto from "node:crypto";
// Codificación RFC 3986 (espacios como %20); debe coincidir con las reglas del servidor
const enc = (v) =>
encodeURIComponent(v).replace(/[!'()*]/g, (c) => "%" + c.charCodeAt(0).toString(16).toUpperCase());
function signedUrl(params, keyId, secret) {
const all = { ...params, key_id: keyId };
const canonical = Object.keys(all).sort().map((k) => `${k}=${enc(String(all[k]))}`).join("&");
const signature = crypto.createHmac("sha256", secret).update(canonical).digest("hex");
return `https://glanceshot.com/v1/screenshot?${canonical}&signature=${signature}`;
}
const src = signedUrl({ url: "https://example.com", viewport_width: 1200 }, KEY_ID, SECRET);
// <img src={src} alt="Vista previa de la página web" />Uso de proxies
Si necesitas acceder a una página desde un país o una región concretos (por ejemplo, para ver el idioma, el contenido y los precios locales), puedes incluir en la solicitud un proxy que hayas contratado por tu cuenta. Los costes del proxy corren a tu cargo. Tanto la página como sus imágenes, scripts y solicitudes a API se cargarán a través de ese proxy. Se admiten proxies socks5:// y http://, con usuario y contraseña opcionales.
curl -X POST "https://glanceshot.com/v1/screenshot" \
-H "X-Access-Key: $GLANCESHOT_KEY" \
-H "Content-Type: application/json" \
-d '{"url": "https://example.com", "proxy": "socks5://user:pass@203.0.113.10:1080"}' \
-o screenshot.pngproxysolo se puede incluir en el cuerpo de una solicitud POST: no se admite en solicitudes GET, URL firmadas ni tareas por lotes, para evitar que las credenciales del proxy aparezcan en la URL, el historial del navegador o una página web.- Si el usuario o la contraseña contienen caracteres especiales como
@o:, debes aplicarles codificación URL (por ejemplo,@se escribe como%40). - Las solicitudes con proxy se almacenan en una caché independiente y no comparten resultados con las solicitudes sin proxy o con otro proxy.
- Si no se puede conectar con el proxy, falla la autenticación o no se puede acceder al sitio de destino, se devuelve
proxy_failedy no se cobra la solicitud.messageindica el motivo concreto. - El proxy debe tener una dirección pública. La URL de destino está sujeta a las mismas restricciones que sin proxy: no se permite acceder a direcciones de redes privadas.
- Al acceder a sitios web a través de un proxy, respeta sus condiciones de uso y la legislación local.
Capturar páginas con sesión iniciada
Para capturar páginas que requieren iniciar sesión, puedes incluir la sesión de tu propia cuenta. Hay dos opciones: enviar cookies, headers, local_storage y session_storage directamente en la solicitud, o usar la extensión de Glanceshot para guardar la sesión como un «perfil de sesión» e incluir solo login_profile en la solicitud.
curl -X POST "https://glanceshot.com/v1/screenshot" -H "X-Access-Key: $GLANCESHOT_KEY" -H "Content-Type: application/json" -d '{
"url": "https://app.example.com/dashboard",
"cookies": "sid=YOUR_SESSION; theme=dark",
"local_storage": {"token": "YOUR_TOKEN"}
}' -o screenshot.png- La extensión puede leer credenciales de sesión a las que los scripts de la página no tienen acceso (incluidas las cookies HttpOnly), así como localStorage e IndexedDB. Es adecuada para la mayoría de los sitios. Instálala y conéctala desde la página «Perfiles de sesión» de la consola.
- Los datos de sesión solo se pueden enviar en el cuerpo de una solicitud POST (se rechazan
GETy las URL firmadas) y no se guardan en los logs ni en el historial de llamadas. Las solicitudes que incluyen una sesión se almacenan en una caché separada para esa sesión, que no se comparte con otros usuarios. - Si incluyes una sesión pero la página redirige al inicio de sesión, se devuelve
login_expiredy no se cobra la solicitud (la sesión ha caducado; vuelve a sincronizarla con la extensión). - En sitios cuya sesión está vinculada a un dispositivo o una IP y no puede reproducirse en la nube (como la banca en línea), usa «Capturar página actual» en la extensión para hacer la captura en tu propio navegador y subirla.
Caché
Las peticiones con los mismos parámetros usan la caché (omitir un parámetro equivale a enviar su valor predeterminado; los parámetros de autenticación y caché no se comparan). Si hay un resultado en caché, el modo binario devuelve una redirección 302 a la URL del archivo junto con Cache-Control; el navegador sigue la redirección y guarda el archivo en caché automáticamente. El modo JSON devuelve cache_hit: true.
Las respuestas desde caché no se facturan.Las peticiones simultáneas con los mismos parámetros solo generan un renderizado.
Límites y facturación
- Solo se facturan las peticiones correctas (2xx) que no usan la caché: 1 crédito por captura y 2 por PDF.
- No se descuenta cuota en caso de tiempo de espera agotado, fallos de renderizado, errores o bloqueos de acceso del sitio de destino, parámetros incorrectos o fallos de autenticación.
- Los créditos se renuevan cada mes natural (UTC). El plan gratuito incluye 100 créditos al mes; al agotarlos, se devuelve quota_exceeded.
- Si se supera el límite de peticiones por segundo o de concurrencia, se devuelve 429. La cabecera Retry-After indica cuántos segundos se recomienda esperar.
- Tiempo máximo de renderizado: 30 segundos; descarga máxima por página: 50 MB; tamaño máximo del archivo de salida: 50 MB.
Consulta los límites de cada plan en Precios.
Códigos de error
Todas las respuestas de error usan JSON:
{
"error": {
"code": "render_failed",
"message": "target responded with an error status",
"upstream_status": 404,
"request_id": "req_01j…"
}
}| HTTP | code | Significado | Se factura |
|---|---|---|---|
| 400 | invalid_params | Falta un parámetro o su valor está fuera de rango; message indica cuál | No |
| 400 | html_too_large | html supera los 2 MB | No |
| 401 | unauthorized | Falta la API Key, no es válida o está desactivada | No |
| 401 | signature_invalid | La firma no coincide (se han modificado los parámetros o el secreto es incorrecto) | No |
| 401 | signature_expired | La URL firmada ha caducado según expires | No |
| 403 | url_blocked | No se permite acceder a la URL de destino (por ejemplo, direcciones de red interna o localhost) | No |
| 408 | render_timeout | El renderizado ha superado los 30 segundos | No |
| 422 | render_failed | El sitio de destino devuelve 4xx/5xx, falla el DNS o hay un error de certificado; incluye upstream_status | No |
| 422 | selector_not_found | selector no coincide con ningún elemento o se ha agotado el tiempo de espera de wait_for_selector | No |
| 422 | too_many_redirects | Se han superado las 5 redirecciones | No |
| 422 | site_blocked | El sitio de destino ha mostrado una verificación de que no eres un robot, un captcha, una pantalla de inicio de sesión o una página de acceso denegado en lugar del contenido esperado; no se factura. | No |
| 422 | login_expired | Se ha incluido una sesión, pero el sitio de destino sigue mostrando la página de inicio de sesión, lo que indica que la sesión ha caducado. | No |
| 422 | proxy_failed | No se puede conectar con el proxy indicado, ha fallado la autenticación o el proxy no puede acceder al sitio de destino. message indica el motivo concreto. No se cobra la solicitud. | No |
| 429 | rate_limited | Se ha superado el límite de peticiones por segundo; vuelve a intentarlo según Retry-After | No |
| 429 | concurrency_exceeded | Se ha superado el límite de peticiones simultáneas | No |
| 429 | quota_exceeded | Se han agotado los créditos del mes (plan gratuito) | No |
| 429 | too_many_batches | Hay más de 5 tareas por lotes sin finalizar a la vez | No |
| 500 | internal | Error del servidor; contacta con nosotros e incluye request_id | No |
Lotes asíncronos
/v1/batch/v1/batch/{id}Envía entre 1 y 100 URL en una sola petición. El endpoint devuelve de inmediato un ID de tarea (HTTP 202) y las capturas se procesan una a una en segundo plano. Es ideal para capturar páginas por lotes sin mantener la conexión abierta. Puedes consultar el estado periódicamente o indicar webhook_url para recibir una notificación cuando todo haya terminado. La autenticación es la misma que en el endpoint síncrono (solo mediante cabecera o el parámetro access_key; no admite URL firmadas).
| Parámetro | Tipo | Valor predeterminado | Descripción |
|---|---|---|---|
| type | enum | screenshot | screenshot (captura) o pdf. |
| urls | string[] | — | URL que se van a procesar, entre 1 y 100. Si alguna no es válida, toda la petición devuelve 400 y message indica su posición. |
| options | object | {} | Parámetros comunes a todas las URL. Son los mismos que los de la API síncrona (como full_page, format, viewport_width y cache_ttl), pero no pueden incluir url, html, response_type ni proxy. |
| webhook_url | string | — | Opcional. URL a la que se enviará una notificación cuando todo haya terminado. Consulta «Notificación al finalizar». |
curl -X POST "https://glanceshot.com/v1/batch" \
-H "X-Access-Key: $GLANCESHOT_KEY" \
-H "Content-Type: application/json" \
-d '{
"type": "screenshot",
"urls": ["https://example.com", "https://example.org"],
"options": { "full_page": true, "format": "webp" },
"webhook_url": "https://your-app.com/hooks/glanceshot"
}'
# Devuelve 202
{
"id": "bat_01j…",
"type": "screenshot",
"status": "queued",
"total": 2, "succeeded": 0, "failed": 0,
"created_at": "2026-10-18T09:30:00Z", "completed_at": null,
"webhook": { "url": "https://your-app.com/hooks/glanceshot", "status": "none", "attempts": 0 },
"items": [
{ "index": 0, "url": "https://example.com", "status": "pending", "result": null, "error": null },
{ "index": 1, "url": "https://example.org", "status": "pending", "result": null, "error": null }
]
}Consulta del progreso: el estado de la tarea, status, pasa por queued (en cola), running (en curso) y completed (todo finalizado, con éxito o con errores). El estado de cada URL es pending, running, succeeded o failed. Si se procesa correctamente, result contiene la URL del archivo; si falla, error contiene el código de error (los mismos que en el endpoint síncrono).
curl "https://glanceshot.com/v1/batch/bat_01j…" -H "X-Access-Key: $GLANCESHOT_KEY"
{
"id": "bat_01j…",
"status": "completed",
"total": 2, "succeeded": 1, "failed": 1,
"completed_at": "2026-10-18T09:30:12Z",
"items": [
{
"index": 0, "url": "https://example.com", "status": "succeeded", "duration_ms": 1830,
"result": { "url": "https://glanceshot.com/i/3f/3f9c….webp", "mime": "image/webp", "width": 1280, "height": 2410, "cache_hit": false },
"error": null
},
{
"index": 1, "url": "https://example.org", "status": "failed", "duration_ms": 640,
"result": null,
"error": { "code": "render_failed", "message": "target responded with an error status" }
}
]
}- Se aplican las mismas reglas de facturación que en el endpoint síncrono: cada URL procesada correctamente consume 1 crédito por captura o 2 por PDF. Los resultados en caché y los fallos no consumen créditos.
- Si ya no quedan créditos al enviar la tarea, se devuelve
quota_exceededdirectamente. Si se agotan durante el procesamiento, las URL restantes fallan conquota_exceeded. - Cada cuenta puede tener como máximo 5 tareas por lotes sin finalizar a la vez. Si se supera el límite, se devuelve
too_many_batches. - La validez de los archivos resultantes depende de
options.cache_ttl(por defecto, 1 día). Descárgalos y guárdalos antes de que caduquen. - En los resultados de consulta y las notificaciones,
webhook.urlsolo se muestra hasta la ruta, sin la cadena de consulta.
Notificación al finalizar
Si indicas webhook_url, enviaremos una petición POST a esa URL cuando finalice toda la tarea. El cuerpo es JSON: { "event": "batch.completed", "batch": { … } }, donde batch es idéntico a la respuesta del endpoint de consulta. Cabeceras:
X-Glanceshot-Signature: t=1760779812,v1=5d3f…:tes la hora de envío (segundos Unix) yv1es la firmaX-Glanceshot-Event: batch.completed,X-Glanceshot-Delivery-Attempt: 1(número de intento de entrega)
v1 = hex(HMAC-SHA256(secret, t + "." + Cuerpo original de la solicitud))
secret es el secreto de firma de la API Key utilizada al enviar la tarea (disponible en la página API Key de la consola).- Devuelve una respuesta 2xx en un plazo de 10 segundos; de lo contrario, se considerará un fallo. En caso de fallo, se reintentará al cabo de 10 segundos, 1 minuto y 5 minutos (hasta 4 intentos en total).
- En casos excepcionales, puedes recibir notificaciones duplicadas de una misma tarea. Usa
batch.idpara descartar los duplicados. - Para verificar la firma, calcúlala a partir de los bytes originales recibidos y comprueba que la diferencia entre
ty la hora actual no supere unos minutos para evitar ataques de repetición. - La URL de callback debe ser una dirección http(s) accesible públicamente y no puede apuntar a una red interna.
import crypto from "node:crypto";
// rawBody debe contener los bytes originales recibidos, sin aplicar JSON.parse y volver a serializar
function verifyGlanceshotWebhook(rawBody, header, secret, toleranceSec = 300) {
const parts = Object.fromEntries(header.split(",").map((p) => p.split("=")));
const t = Number(parts.t);
if (!t || Math.abs(Date.now() / 1000 - t) > toleranceSec) return false; // Protección contra ataques de repetición
const expected = crypto.createHmac("sha256", secret).update(`${t}.${rawBody}`).digest("hex");
const got = Buffer.from(parts.v1 ?? "");
return got.length === expected.length && crypto.timingSafeEqual(Buffer.from(expected), got);
}
// verifyGlanceshotWebhook(req.rawBody, req.headers["x-glanceshot-signature"], GLANCESHOT_SECRET)Consulta de uso
/v1/usagecurl "https://glanceshot.com/v1/usage" -H "X-Access-Key: $GLANCESHOT_KEY"
{ "month": "202610", "used": 37, "limit": 100, "remaining": 63, "overage": 0, "resets_at": "2026-11-01T00:00:00Z", ... }Comprobación de estado
/v1/healthNo requiere autenticación. Devuelve el estado del nodo y del pool de navegadores (total, ocupados y libres).