API Documentação
URL base: https://glanceshot.com/v1. Todos os endpoints usam HTTP padrão. Os parâmetros podem ser enviados na cadeia de consulta (GET) ou no corpo JSON (POST).
Início rápido
- Registe-se gratuitamente e crie uma API Key na página «API Key» da consola.
- Inclua a API Key no cabeçalho
X-Access-Keye faça um pedido ao endpoint de captura:
curl "https://glanceshot.com/v1/screenshot?url=https://example.com&full_page=true" \
-H "X-Access-Key: $GLANCESHOT_KEY" \
-o screenshot.pngAutenticação
Todos os pedidos exigem uma API Key, que pode ser enviada de uma das seguintes formas:
- Cabeçalho
X-Access-Key: gls_…(recomendado para pedidos a partir do servidor) - Parâmetro de consulta
access_key=gls_…(apenas para chamadas do lado do servidor; não o inclua em páginas web) - URL assinado (para incluir o endereço numa página web, sem expor a API Key nem o segredo)
A API Key só é apresentada em texto simples uma vez, no momento da criação. Guarde-a em segurança. Se for exposta, pode desativá-la na consola.
Capturas de ecrã
/v1/screenshot/v1/screenshotParâmetros exclusivos das capturas de ecrã:
| Parâmetro | Tipo | Valor predefinido | Descrição |
|---|---|---|---|
| format | enum | png | png, jpeg ou webp. |
| device_scale_factor | number | 1 | Fator de escala de 1–3. O valor 2 oferece nitidez Retina, com um ficheiro cerca de 4 vezes maior. |
| quality | integer | 80 | Qualidade JPEG / WebP, 1–100. |
| full_page | boolean | false | Captura a página inteira. Percorre a página ecrã a ecrã para ativar o carregamento diferido, até uma altura máxima de 20,000 píxeis. |
| selector | string | — | Captura apenas o primeiro elemento correspondente a este seletor CSS. Não pode ser usado com full_page. |
Parâmetros comuns às capturas de ecrã e aos PDF:
| Parâmetro | Tipo | Valor predefinido | Descrição |
|---|---|---|---|
| url | string | — | Endereço da página a capturar, com http ou https. Use este parâmetro ou html, não ambos. O fragmento # do URL é preservado, permitindo capturar diretamente a página correspondente em aplicações de página única com encaminhamento por hash (como https://app.com/#/report/1). |
| html | string | — | Envie HTML diretamente (máximo de 2 MB). Apenas POST. |
| viewport_width | integer | 1280 | Largura da área de visualização, 320–3840. Abaixo de 768, a página é renderizada como num dispositivo móvel. |
| viewport_height | integer | 800 | Altura da área de visualização, 200–3840. |
| wait_until | enum | networkidle | Estratégia de espera: domcontentloaded (a mais rápida, ideal para páginas estáticas), load ou networkidle (acompanha todos os pedidos desde a abertura da página e, após o carregamento, só captura quando não houver pedidos em curso durante 500 milissegundos consecutivos; espera até mais 8 segundos, ideal para aplicações de página única). |
| wait_for_selector | string | — | Após carregar a página, espera que um elemento correspondente a este seletor CSS apareça e fique visível antes de capturar, até 10 segundos. Se não aparecer, devolve selector_not_found (sem cobrança). Ideal para aplicações de página única que renderizam conteúdo com atraso através de temporizadores ou animações, sem depender de pedidos de rede, como .chart-ready. |
| delay | integer | 0 | Atraso adicional em milissegundos após a espera, 0–10000. Útil para aguardar animações ou componentes com carregamento diferido. |
| block_ads | boolean | true | Bloqueia pedidos a domínios de publicidade e rastreamento e oculta os espaços publicitários na página. |
| block_cookie_banners | boolean | true | Oculta as janelas de consentimento de cookies. |
| dark_mode | boolean | false | Simula prefers-color-scheme: dark. |
| hide_selectors | string | — | Lista de seletores CSS dos elementos a ocultar, por exemplo .ad,#popup. |
| cache | boolean | true | Define se deve procurar na cache. Com false, força uma nova renderização, mas o resultado continua a ser guardado na cache. |
| cache_ttl | integer | 86400 | Prazo de validade da cache em segundos, 60–2592000. |
| response_type | enum | binary | binary devolve o ficheiro diretamente; json devolve o endereço do ficheiro e os metadados. |
| proxy | string | — | Opcional. Usa um proxy que adquiriste para aceder à página de destino (os custos do proxy ficam a teu cargo), por exemplo, quando precisas de aceder a partir de um país ou região específicos. Suporta socks5:// e http://, com nome de utilizador e palavra-passe opcionais, no formato socks5://user:pass@203.0.113.10:1080. Só pode ser enviado no corpo de um pedido POST; não está disponível para pedidos GET, URL assinados nem tarefas em lote. Os pedidos com proxy têm uma cache separada. Se não for possível ligar ao proxy, a autenticação falhar ou o proxy não conseguir aceder ao site de destino, é devolvido proxy_failed e o pedido não é cobrado. |
| cookies | string | object[] | — | Cookies do site de destino, numa única linha como sid=abc; theme=dark ou num array como [{"name":"sid","value":"abc"}] (com domain e path opcionais). Só são enviados para o site de destino, não para terceiros presentes na página. |
| headers | object | — | Cabeçalhos a adicionar ao pedido, como Authorization: Bearer …. Só são enviados para o site de destino; não é possível definir cabeçalhos geridos pelo navegador (Host, Cookie, User-Agent, etc.). |
| local_storage | object | — | Dados a gravar no localStorage da origem do URL de destino. As chaves e os valores têm de ser strings. |
| session_storage | object | — | Igual a local_storage, mas grava em sessionStorage. |
| login_profile | string | — | Identificador do perfil de sessão guardado com a extensão do navegador (lp_8f2c…). É mais prático do que enviar cookies diretamente e também pode ser usado em tarefas em lote (não são guardadas credenciais nas tarefas). |
Capturar aplicações de página única (React, Vue, etc.):A página é capturada num navegador real, após a execução do JavaScript. A opção predefinida networkidle espera que a página termine de obter os dados. Se o conteúdo só for renderizado depois, através de temporizadores ou animações, use wait_for_selector para indicar um elemento que sinalize que o conteúdo está pronto. Se não houver um elemento adequado, use delay para esperar mais um pouco.
/v1/pdf/v1/pdfCada PDF consome 2 unidades da quota. Antes da impressão, a página é percorrida para ativar o carregamento diferido. Além dos parâmetros comuns, são suportados:
| Parâmetro | Tipo | Valor predefinido | Descrição |
|---|---|---|---|
| paper | enum | a4 | Formato do papel: a4 ou letter. Se a página definir uma regra @page, essa configuração tem prioridade. |
| print_background | boolean | true | Imprime cores e imagens de fundo. |
| pdf_media | enum | print usa os estilos de impressão; screen usa os estilos de ecrã (o resultado corresponde ao que vê). |
curl -X POST "https://glanceshot.com/v1/pdf" \
-H "X-Access-Key: $GLANCESHOT_KEY" \
-H "Content-Type: application/json" \
-d '{"html": "<h1>Relatório trimestral</h1><p>Corpo do texto…</p>", "paper": "a4"}' \
-o report.pdfRespostas
Por predefinição (response_type=binary), o ficheiro é devolvido diretamente, com Content-Type correspondente ao formato. Cabeçalhos de resposta:
X-Request-Id: ID do pedido, a indicar ao comunicar um problemaX-Glanceshot-Cache:HITouMISSX-Glanceshot-Truncated: true: a página inteira foi cortada por exceder 20,000 píxeisX-Glanceshot-Format-Changed: webp: PNG convertido automaticamente em WebP por exceder 5 MB (não há conversão se format=png for especificado explicitamente)
Com response_type=json, são devolvidos o endereço do ficheiro e os metadados:
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"}'
# Devolve
{
"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 assinados
Quer incluir o endereço da captura de ecrã diretamente em <img src> sem expor a API Key? O URL assinado contém apenas o identificador público key_id, nunca a API Key. A assinatura é calculada no seu servidor com o segredo associado à chave. Pode consultar o ID da chave e o segredo na página API Key da consola:
canonical = Ordene todos os parâmetros, exceto signature, por ordem lexicográfica dos nomes,
formate cada entrada como k=urlencode(v) (RFC 3986, com os espaços codificados como %20) e una-as com &
signature = hex(HMAC-SHA256(secret, canonical))Uma assinatura válida autentica o pedido. Os pedidos sem assinatura ou com uma assinatura inválida são rejeitados. Qualquer alteração aos parâmetros (por exemplo, mudar url) invalida a assinatura. O parâmetro opcional expires (tempo Unix em segundos) é incluído no cálculo da assinatura; após a expiração, é devolvido signature_expired. Para atualizar a cache, basta alterar um parâmetro sem efeito (como v=2) e gerar uma nova assinatura. Os URL assinados só permitem chamadas GET aos endpoints de captura de ecrã e PDF e não aceitam parâmetros de proxy.
key_id é público e, por si só, não permite chamar a API. Não inclua a API Key (access_key) num URL assinado: se o fizer, será devolvido invalid_params. Se já incluiu a API Key numa página web, desative essa chave na consola e crie uma nova.
import crypto from "node:crypto";
// Codificação RFC 3986 (espaços como %20), de acordo com as regras do 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="Pré-visualização da página web" />Usar um proxy
Se precisar de aceder a uma página a partir de um país ou região específicos (por exemplo, para ver o idioma, o conteúdo e os preços locais), pode incluir no pedido um proxy contratado por si, cujos custos ficam a seu cargo. A página e todas as imagens, scripts e chamadas a API nela incluídas serão carregados através desse proxy. São suportados proxies socks5:// e http://, com nome de utilizador e palavra-passe opcionais.
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.pngproxysó pode ser incluído no corpo de um pedido POST: não é permitido em pedidos GET, URL assinados ou tarefas em lote, para evitar que as credenciais do proxy fiquem expostas no URL, no histórico do navegador ou em páginas web.- Se o nome de utilizador ou a palavra-passe contiverem caracteres especiais como
@ou:, aplique primeiro a codificação de URL (por exemplo, substitua@por%40). - Os pedidos com proxy têm uma cache separada e não partilham resultados com pedidos sem proxy ou com outros proxies.
- Se não for possível ligar ao proxy, se a autenticação falhar ou se o site de destino estiver inacessível, é devolvido
proxy_failede o pedido não é cobrado. O campomessageindica o motivo específico. - O proxy tem de ter um endereço público. Aplicam-se ao URL de destino as mesmas restrições dos pedidos sem proxy: não é permitido aceder a endereços de redes privadas.
- Ao aceder a sites através de um proxy, respeite os termos de utilização do site de destino e a legislação local.
Capturar páginas com sessão iniciada
Para capturar páginas que exigem autenticação, pode enviar o estado de sessão da sua própria conta. Há duas opções: enviar cookies, headers, local_storage e session_storage diretamente no pedido, ou usar a extensão Glanceshot para guardar o estado de sessão num «perfil de sessão» e enviar apenas login_profile no pedido.
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- A extensão consegue ler credenciais de sessão às quais os scripts da página não têm acesso (incluindo cookies HttpOnly), bem como localStorage e IndexedDB, e é adequada para a maioria dos sites. Instale e ligue a extensão na página «Perfis de sessão» da consola.
- O estado de sessão só pode ser enviado no corpo de um pedido POST (
GETe URLs assinados são rejeitados) e não é guardado nos logs nem no histórico de chamadas. Os pedidos com estado de sessão têm uma cache separada, específica desse estado, que não é partilhada com outros utilizadores. - Se enviar um estado de sessão, mas a página redirecionar para o início de sessão, é devolvido
login_expirede o pedido não é cobrado (a sessão expirou; volte a sincronizá-la com a extensão). - Nos sites cuja sessão está associada ao dispositivo ou ao IP e não pode ser reproduzida na nuvem (como os de banca online), use a opção «Capturar página atual» da extensão para tirar a captura no seu próprio navegador e enviá-la.
Cache
Os pedidos com parâmetros idênticos usam a cache (omitir um parâmetro equivale a enviar explicitamente o valor predefinido; os parâmetros de autenticação e de cache não entram na comparação). Quando há um resultado em cache, o modo binário devolve um redirecionamento 302 para o endereço do ficheiro, com Cache-Control; o navegador segue o redirecionamento e guarda o ficheiro em cache automaticamente. O modo JSON devolve cache_hit: true.
Os resultados obtidos da cache não são faturados.Pedidos simultâneos com os mesmos parâmetros geram apenas uma renderização.
Limites e faturação
- Só são faturados os pedidos bem-sucedidos (2xx) que não usem a cache: 1 unidade por captura de ecrã e 2 por PDF.
- Os pedidos com tempo limite excedido, falhas de renderização, erros ou bloqueios de acesso no site de destino, parâmetros inválidos ou falhas de autenticação não consomem quota.
- A quota é reposta no início de cada mês (UTC). O plano gratuito inclui 100 unidades por mês; após esgotá-las, é devolvido quota_exceeded.
- Exceder o limite de pedidos por segundo ou de pedidos simultâneos devolve 429. O cabeçalho de resposta Retry-After indica o tempo de espera recomendado em segundos.
- Tempo máximo de renderização: 30 segundos; volume máximo de transferência por página: 50 MB; tamanho máximo do ficheiro gerado: 50 MB.
Consulte os limites de cada plano: Preços.
Códigos de erro
Todas as respostas de erro usam JSON:
{
"error": {
"code": "render_failed",
"message": "target responded with an error status",
"upstream_status": 404,
"request_id": "req_01j…"
}
}| HTTP | code | Significado | Faturado |
|---|---|---|---|
| 400 | invalid_params | Parâmetro em falta ou fora do intervalo permitido; message indica qual | Não |
| 400 | html_too_large | html excede 2 MB | Não |
| 401 | unauthorized | API Key em falta, inválida ou desativada | Não |
| 401 | signature_invalid | A assinatura não corresponde (parâmetros alterados ou segredo incorreto) | Não |
| 401 | signature_expired | O prazo expires do URL assinado já expirou | Não |
| 403 | url_blocked | O acesso ao endereço de destino não é permitido (por exemplo, endereços de rede privada ou localhost) | Não |
| 408 | render_timeout | A renderização excedeu 30 segundos | Não |
| 422 | render_failed | O site de destino devolveu 4xx/5xx, houve uma falha de DNS ou um erro de certificado; inclui upstream_status | Não |
| 422 | selector_not_found | selector não corresponde a nenhum elemento ou a espera por wait_for_selector excedeu o tempo limite | Não |
| 422 | too_many_redirects | Mais de 5 redirecionamentos | Não |
| 422 | site_blocked | O site de destino apresentou uma verificação de segurança, um CAPTCHA, uma página de início de sessão obrigatório ou de acesso recusado, em vez do conteúdo normal; o pedido não é cobrado | Não |
| 422 | login_expired | Foi enviado um estado de sessão, mas o site de destino continua a mostrar a página de início de sessão, o que indica que a sessão expirou. | Não |
| 422 | proxy_failed | Não foi possível ligar ao proxy indicado, a autenticação falhou ou o proxy não conseguiu aceder ao site de destino. message indica o motivo específico. O pedido não é cobrado. | Não |
| 429 | rate_limited | Limite de pedidos por segundo excedido; tente novamente de acordo com Retry-After | Não |
| 429 | concurrency_exceeded | Limite de pedidos simultâneos excedido | Não |
| 429 | quota_exceeded | Quota mensal esgotada (plano gratuito) | Não |
| 429 | too_many_batches | Mais de 5 tarefas em lote por concluir em simultâneo | Não |
| 500 | internal | Erro do servidor; contacte-nos e indique request_id | Não |
Lotes assíncronos
/v1/batch/v1/batch/{id}Envie 1–100 URL de uma só vez. O endpoint devolve imediatamente um ID de tarefa (HTTP 202) e as capturas são processadas uma a uma em segundo plano. Ideal para capturas em lote sem manter a ligação aberta. Pode consultar periodicamente o estado ou definir webhook_url para receber uma notificação quando tudo estiver concluído. A autenticação é igual à do endpoint síncrono (apenas por cabeçalho ou pelo parâmetro access_key; não suporta URL assinados).
| Parâmetro | Tipo | Valor predefinido | Descrição |
|---|---|---|---|
| type | enum | screenshot | screenshot (captura de ecrã) ou pdf. |
| urls | string[] | — | URL a processar, de 1–100. Se algum for inválido, o pedido inteiro devolve 400 e message indica a posição do URL. |
| options | object | {} | Parâmetros comuns a todos os URL, iguais aos da API síncrona (por exemplo, full_page, format, viewport_width, cache_ttl). Não podem incluir url, html, response_type, proxy. |
| webhook_url | string | — | Opcional. Endereço a notificar quando tudo estiver concluído. Consulte «Notificação de conclusão». |
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"
}'
# Devolve 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 }
]
}Consultar o progresso: o estado da tarefa, status, passa por queued (em fila), running (em processamento) e completed (tudo concluído, com ou sem sucesso). O estado de cada URL é pending, running, succeeded ou failed. Em caso de sucesso, result contém o endereço do ficheiro; em caso de falha, error contém o código de erro (igual ao do 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" }
}
]
}- Aplicam-se as mesmas regras de faturação do endpoint síncrono: cada URL processado com sucesso consome 1 unidade por captura de ecrã ou 2 por PDF. Os resultados da cache e as falhas não consomem quota.
- Se a quota já estiver esgotada ao submeter o pedido, é devolvido
quota_exceededde imediato. Se se esgotar durante o processamento, os URL restantes falham comquota_exceeded. - Cada conta pode ter até 5 tarefas em lote por concluir em simultâneo. Acima desse limite, é devolvido
too_many_batches. - A validade dos ficheiros gerados é definida por
options.cache_ttl(por predefinição, 1 dia). Transfira-os e guarde-os antes de expirarem. - Nos resultados da consulta e nas notificações,
webhook.urlé apresentado apenas até ao caminho, sem a cadeia de consulta.
Notificação de conclusão
Se definir webhook_url, enviaremos um pedido POST para esse endereço quando a tarefa estiver totalmente concluída. O corpo do pedido é JSON: { "event": "batch.completed", "batch": { … } }, em que batch é exatamente igual à resposta do endpoint de consulta. Cabeçalhos do pedido:
X-Glanceshot-Signature: t=1760779812,v1=5d3f…:té a hora de envio (segundos Unix) ev1é a assinaturaX-Glanceshot-Event: batch.completed,X-Glanceshot-Delivery-Attempt: 1(número da tentativa de entrega)
v1 = hex(HMAC-SHA256(secret, t + "." + Corpo original do pedido))
secret é o segredo de assinatura associado à API Key usada para submeter a tarefa (disponível na página API Key da consola).- Devolva uma resposta 2xx no prazo de 10 segundos; caso contrário, a entrega será considerada falhada. Em caso de falha, serão feitas novas tentativas após 10 segundos, 1 minuto e 5 minutos (até 4 tentativas no total).
- Em casos muito raros, pode receber notificações duplicadas para a mesma tarefa. Use
batch.idpara eliminar duplicados. - Para verificar a assinatura, faça o cálculo com os bytes originais recebidos e confirme que a diferença entre
te a hora atual não excede alguns minutos, para evitar ataques de repetição. - O URL de callback deve ser um endereço http(s) acessível publicamente e não pode apontar para uma rede interna.
import crypto from "node:crypto";
// rawBody tem de conter os bytes originais recebidos, sem aplicar JSON.parse e voltar 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; // Proteção contra ataques de repetição
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)Consultar utilização
/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", ... }Verificação de estado
/v1/healthNão requer autenticação. Devolve o estado do nó e do conjunto de navegadores (total, ocupados e disponíveis).