Glanceshot
Documentation développeur

API Documentation

URL de base : https://glanceshot.com/v1. Tous les endpoints utilisent HTTP standard. Les paramètres peuvent être transmis dans la chaîne de requête (GET) ou dans le corps JSON (POST).

Démarrage rapide

  1. Inscrivez-vous gratuitement, puis créez une API Key sur la page « API Key » de la console.
  2. Placez votre API Key dans l’en-tête X-Access-Key, puis appelez l’endpoint de capture :
curl "https://glanceshot.com/v1/screenshot?url=https://example.com&full_page=true" \
  -H "X-Access-Key: $GLANCESHOT_KEY" \
  -o screenshot.png

Authentification

Chaque requête nécessite une API Key, à transmettre de l’une des façons suivantes :

  • En-tête X-Access-Key: gls_… (recommandé pour les appels côté serveur)
  • Paramètre de requête access_key=gls_… (uniquement pour les appels côté serveur, à ne pas inclure dans une page web)
  • URL signée (pour intégrer l’URL dans une page web sans exposer l’API Key ni le secret)

L’API Key n’est affichée en clair qu’une seule fois, lors de sa création. Conservez-la en lieu sûr. En cas de fuite, vous pouvez la désactiver dans la console.

API de capture

GET/v1/screenshot
POST/v1/screenshot

Paramètres propres aux captures :

ParamètreTypePar défautDescription
formatenumpngpng, jpeg ou webp.
device_scale_factornumber1Facteur d’échelle, 1–3. La valeur 2 offre une netteté Retina, pour un fichier environ 4 fois plus volumineux.
qualityinteger80Qualité JPEG / WebP, 1–100.
full_pagebooleanfalseCapture la page entière. Fait défiler la page écran par écran pour déclencher le chargement différé, jusqu’à une hauteur de 20,000 pixels.
selectorstring—Capture uniquement le premier élément correspondant à ce sélecteur CSS. Incompatible avec full_page.

Paramètres communs aux captures et aux PDF :

ParamètreTypePar défautDescription
urlstring—URL de la page à capturer, en http ou https. Utilisez ce paramètre ou html, mais pas les deux. Le fragment # de l’URL est conservé : vous pouvez ainsi capturer directement une page d’une application monopage utilisant le routage par fragment, comme https://app.com/#/report/1.
htmlstring—HTML fourni directement (2 MB maximum). Uniquement en POST.
viewport_widthinteger1280Largeur de la fenêtre d’affichage, 320–3840. En dessous de 768, le rendu se fait en mode mobile.
viewport_heightinteger800Hauteur de la fenêtre d’affichage, 200–3840.
wait_untilenumnetworkidleStratégie d’attente : domcontentloaded (la plus rapide, adaptée aux pages statiques), load, networkidle (suit toutes les requêtes dès l’ouverture de la page et ne lance la capture qu’après 500 millisecondes sans requête en cours une fois la page chargée, avec une attente supplémentaire de 8 secondes maximum ; adaptée aux applications monopages).
wait_for_selectorstring—Après le chargement de la page, attend qu’un élément correspondant à ce sélecteur CSS soit présent et visible avant de lancer la capture, pendant 10 secondes maximum. Sinon, renvoie selector_not_found (non facturé). Adapté aux applications monopages dont le contenu s’affiche après un délai ou une animation, sans requête réseau, comme .chart-ready.
delayinteger0Délai supplémentaire en millisecondes après la fin de l’attente, 0–10000. Utile pour les animations ou les composants chargés à la demande.
block_adsbooleantrueBloque les requêtes vers les domaines publicitaires et de suivi, et masque les emplacements publicitaires sur la page.
block_cookie_bannersbooleantrueMasque les fenêtres de consentement aux cookies.
dark_modebooleanfalseÉmule prefers-color-scheme: dark.
hide_selectorsstring—Liste de sélecteurs CSS des éléments à masquer, par exemple .ad,#popup.
cachebooleantrueIndique s’il faut consulter le cache. La valeur false force un nouveau rendu, dont le résultat est tout de même mis en cache.
cache_ttlinteger86400Durée de validité du cache en secondes, 60–2592000.
response_typeenumbinarybinary renvoie directement le fichier ; json renvoie l’URL du fichier et les métadonnées.
proxystring—Facultatif. Utilisez votre propre proxy pour accéder à la page cible (les frais du proxy restent à votre charge), par exemple pour y accéder depuis un pays ou une région spécifique. Prend en charge socks5:// et http://, avec ou sans identifiants, au format socks5://user:pass@203.0.113.10:1080. Ce paramètre doit figurer uniquement dans le corps d’une requête POST ; il n’est pas disponible pour les requêtes GET, les URL signées ni les tâches par lot. Les requêtes utilisant un proxy sont mises en cache séparément. Si la connexion au proxy ou l’authentification échoue, ou si le proxy ne peut pas accéder au site cible, le code proxy_failed est renvoyé et la requête n’est pas facturée.
cookiesstring | object[]—Cookies du site cible, sous forme d’une ligne comme sid=abc; theme=dark ou d’un tableau comme [{"name":"sid","value":"abc"}] (avec domain et path facultatifs). Ils sont envoyés uniquement au site cible, jamais aux services tiers présents sur la page.
headersobject—En-têtes de requête à ajouter, par exemple Authorization: Bearer …. Ils sont envoyés uniquement au site cible. Les en-têtes gérés par le navigateur (Host, Cookie, User-Agent, etc.) ne peuvent pas être définis.
local_storageobject—Données à écrire dans le localStorage de l’origine de l’URL cible. Les clés et les valeurs doivent être des chaînes de caractères.
session_storageobject—Comme local_storage, mais pour sessionStorage.
login_profilestring—Identifiant du profil de connexion enregistré via l’extension de navigateur (lp_8f2c…). Plus simple que de transmettre directement les cookies, il peut aussi être utilisé dans les tâches par lots (aucune donnée d’authentification n’est enregistrée dans les tâches).

Capturer une application monopage (React, Vue, etc.) :Le JavaScript de la page s’exécute dans un véritable navigateur avant la capture. Par défaut, networkidle attend la fin du chargement des données. Si le contenu s’affiche ensuite après un délai ou une animation, ajoutez wait_for_selector pour désigner un élément indiquant que le contenu est prêt. Si aucun élément ne convient, utilisez delay pour prolonger l’attente.

API PDF

GET/v1/pdf
POST/v1/pdf

Chaque PDF consomme 2 unités du quota. Avant l’impression, la page est parcourue pour déclencher le chargement différé. En plus des paramètres communs, les paramètres suivants sont disponibles :

ParamètreTypePar défautDescription
paperenuma4Format du papier : a4 ou letter. Si la page définit une règle @page, celle-ci est prioritaire.
print_backgroundbooleantrueImprime les couleurs et les images d’arrière-plan.
pdf_mediaenumprintprint utilise les styles d’impression ; screen utilise les styles d’affichage à l’écran (rendu identique à l’écran).
Convertir du HTML en PDF
curl -X POST "https://glanceshot.com/v1/pdf" \
  -H "X-Access-Key: $GLANCESHOT_KEY" \
  -H "Content-Type: application/json" \
  -d '{"html": "<h1>Rapport trimestriel</h1><p>Contenu…</p>", "paper": "a4"}' \
  -o report.pdf

Réponses

Par défaut (response_type=binary), le fichier est renvoyé directement, avec le Content-Type correspondant au format. En-têtes de réponse :

  • X-Request-Id : identifiant de la requête, à fournir pour le dépannage
  • X-Glanceshot-Cache : HIT ou MISS
  • X-Glanceshot-Truncated: true : la capture de la page entière a été tronquée au-delà de 20,000 pixels
  • X-Glanceshot-Format-Changed: webp : un PNG de plus de 5 MB est automatiquement converti en WebP (sauf si format=png est explicitement spécifié)

Avec response_type=json, la réponse contient l’URL du fichier et les métadonnées :

Réponse JSON
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"}'

# Renvoie
{
  "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 signées

Vous souhaitez intégrer directement l’URL d’une capture dans <img src> sans exposer votre API Key ? L’URL signée ne contient pas l’API Key, mais uniquement l’identifiant public key_id. Vous calculez ensuite la signature sur votre propre serveur à l’aide du secret associé à la clé. L’identifiant de la clé et son secret sont disponibles sur la page API Key de la console :

Règles de signature
canonical = Triez tous les paramètres, sauf signature, par ordre lexicographique de leur nom,
            formatez chaque entrée en k=urlencode(v) (RFC 3986, espaces encodés en %20), puis reliez-les avec &
signature = hex(HMAC-SHA256(secret, canonical))

Une signature valide suffit à authentifier la requête. Toute signature manquante ou incorrecte entraîne son rejet. La modification d’un paramètre (par exemple url) invalide la signature. Le paramètre facultatif expires (horodatage Unix en secondes) est inclus dans le calcul de la signature ; une fois ce délai expiré, l’API renvoie signature_expired. Pour rafraîchir le cache, modifiez un paramètre sans effet sur le résultat (comme v=2), puis recalculez la signature. Les URL signées ne prennent en charge que les appels GET aux endpoints de capture d’écran et de PDF, et n’acceptent pas les paramètres de proxy.

key_id est public et ne permet pas, à lui seul, d’appeler l’API. N’incluez pas l’API Key (access_key) dans une URL signée : sa présence entraîne immédiatement une réponse invalid_params. Si vous avez déjà intégré une API Key dans une page web, désactivez-la dans la console et créez-en une nouvelle.

import crypto from "node:crypto";

// Encodage RFC 3986 (espaces encodés en %20), identique à celui utilisé côté serveur
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="Aperçu de la page web" />

Utiliser un proxy

Pour accéder à une page depuis un pays ou une région spécifique (par exemple pour consulter la langue, le contenu et les prix locaux), vous pouvez fournir votre propre proxy dans la requête. Les frais de proxy restent à votre charge. La page, ses images, ses scripts et ses appels API passent tous par ce proxy. Les proxys socks5:// et http:// sont pris en charge, avec ou sans nom d’utilisateur et mot de passe.

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.png
  • proxy doit figurer uniquement dans le corps d’une requête POST. Il n’est pas accepté dans les requêtes GET, les URL signées ni les tâches par lots, afin d’éviter d’exposer les identifiants du proxy dans une URL, l’historique du navigateur ou une page web.
  • Si le nom d’utilisateur ou le mot de passe contient des caractères spéciaux comme @ ou :, appliquez-leur un encodage URL (par exemple, remplacez @ par %40).
  • Les requêtes utilisant un proxy disposent d’un cache distinct : leurs résultats ne sont partagés ni avec les requêtes sans proxy ni avec celles utilisant un autre proxy.
  • Si la connexion au proxy échoue, si l’authentification échoue ou si le site cible est inaccessible, l’API renvoie proxy_failed. La requête n’est pas facturée et message précise la cause.
  • Le proxy doit avoir une adresse publique. Les restrictions sur l’URL cible sont les mêmes qu’en l’absence de proxy : les adresses de réseau privé restent inaccessibles.
  • Lorsque vous accédez à un site via un proxy, veuillez respecter ses conditions d’utilisation et la législation locale.

Pages nécessitant une connexion

Pour capturer une page nécessitant une connexion, vous pouvez fournir l’état de connexion de votre propre compte. Deux possibilités : transmettre directement cookies, headers, local_storage et session_storage dans la requête, ou enregistrer cet état dans un « profil de connexion » via l’extension de navigateur Glanceshot et ne transmettre que login_profile dans la requête.

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
  • L’extension peut lire les données d’authentification inaccessibles aux scripts de la page (y compris les cookies HttpOnly), ainsi que localStorage et IndexedDB. Elle convient à la plupart des sites. Pour l’installer et la connecter, rendez-vous sur la page « Profils de connexion » de la console.
  • L’état de connexion ne peut être transmis que dans le corps d’une requête POST (GET et les URL signées sont refusés). Il n’est enregistré ni dans les journaux ni dans l’historique des appels. Les requêtes contenant un état de connexion disposent d’un cache propre à cet état, qui n’est pas partagé avec d’autres utilisateurs.
  • Si un état de connexion est fourni mais que la page redirige vers la page de connexion, l’API renvoie login_expired et la requête n’est pas facturée (la connexion a expiré ; synchronisez-la à nouveau avec l’extension).
  • Pour les sites dont la session est liée à un appareil ou à une IP et dont la connexion ne peut pas être reproduite dans le cloud (par exemple, les services bancaires en ligne), utilisez « Capturer la page actuelle » dans l’extension pour effectuer la capture dans votre propre navigateur, puis la téléverser.

Cache

Les requêtes dont les paramètres sont identiques utilisent le cache (un paramètre omis équivaut à sa valeur par défaut explicite ; les paramètres d’authentification et de cache sont exclus de la comparaison). En cas de résultat en cache, le mode binaire renvoie une redirection 302 vers l’URL du fichier, avec Cache-Control ; le navigateur suit automatiquement la redirection et met le fichier en cache. Le mode JSON renvoie cache_hit: true.

Les résultats servis depuis le cache ne sont pas facturés.Les requêtes simultanées avec les mêmes paramètres ne déclenchent qu’un seul rendu.

Limites et facturation

  • Seules les requêtes réussies (2xx) non servies depuis le cache sont facturées : 1 unité pour une capture, 2 pour un PDF.
  • Aucun crédit n’est décompté en cas de délai d’attente dépassé, d’échec du rendu, d’erreur ou de blocage d’accès par le site cible, de paramètres invalides ou d’échec de l’authentification.
  • Le quota est réinitialisé chaque mois civil (UTC). L’offre gratuite inclut 100 unités par mois ; une fois le quota épuisé, les requêtes renvoient quota_exceeded.
  • Tout dépassement du nombre de requêtes par seconde ou de requêtes simultanées renvoie 429. L’en-tête Retry-After indique le délai d’attente conseillé en secondes.
  • Durée maximale de rendu : 30 secondes ; volume téléchargé par page : 50 MB maximum ; taille du fichier de sortie : 50 MB maximum.

Consultez les limites de chaque offre : Tarifs.

Codes d’erreur

Toutes les réponses d’erreur sont au format JSON :

Format des erreurs
{
  "error": {
    "code": "render_failed",
    "message": "target responded with an error status",
    "upstream_status": 404,
    "request_id": "req_01j…"
  }
}
HTTPcodeSignificationFacturé
400invalid_paramsParamètre manquant ou hors limites ; message précise lequelNon
400html_too_largehtml dépasse 2 MBNon
401unauthorizedAPI Key manquante, invalide ou désactivéeNon
401signature_invalidSignature incorrecte (paramètres modifiés ou secret incorrect)Non
401signature_expiredL’URL signée a dépassé la date d’expiration expiresNon
403url_blockedAccès interdit à l’URL cible (par exemple une adresse réseau privée ou localhost)Non
408render_timeoutLe rendu a dépassé 30 secondesNon
422render_failedLe site cible a renvoyé une erreur 4xx/5xx, une erreur DNS ou une erreur de certificat ; inclut upstream_statusNon
422selector_not_foundAucun élément ne correspond à selector, ou le délai d’attente de wait_for_selector est dépasséNon
422too_many_redirectsPlus de 5 redirectionsNon
422site_blockedLe site cible affiche une vérification anti-robot, un CAPTCHA, une page de connexion obligatoire ou un refus d’accès au lieu du contenu attendu ; la requête n’est pas facturée.Non
422login_expiredUn état de connexion a été fourni, mais le site cible affiche toujours la page de connexion : cet état a expiré.Non
422proxy_failedImpossible de se connecter au proxy fourni, échec de l’authentification ou site cible inaccessible via ce proxy. Le champ message précise la cause. La requête n’est pas facturée.Non
429rate_limitedLimite de requêtes par seconde dépassée ; réessayez en suivant Retry-AfterNon
429concurrency_exceededLimite de requêtes simultanées dépasséeNon
429quota_exceededQuota mensuel épuisé (offre gratuite)Non
429too_many_batchesPlus de 5 lots en coursNon
500internalErreur serveur ; contactez-nous en joignant request_idNon

Lots asynchrones

POST/v1/batch
GET/v1/batch/{id}

Envoyez de 1 à 100 URL en une requête. L’endpoint renvoie immédiatement un identifiant de tâche (HTTP 202), puis les captures sont réalisées une par une en arrière-plan. Idéal pour les captures par lots sans garder la connexion ouverte. Vous pouvez interroger régulièrement l’endpoint de suivi ou renseigner webhook_url pour recevoir une notification une fois le traitement terminé. L’authentification est identique à celle des endpoints synchrones (uniquement par en-tête ou paramètre access_key, sans prise en charge des URL signées).

ParamètreTypePar défautDescription
typeenumscreenshotscreenshot (capture d’écran) ou pdf.
urlsstring[]—URL à traiter, de 1 à 100. Si l’une d’elles est invalide, la requête entière renvoie 400 ; message indique sa position.
optionsobject{}Paramètres communs à toutes les URL, identiques à ceux de l’API synchrone (par exemple full_page, format, viewport_width, cache_ttl). Ne doivent pas inclure url, html, response_type, proxy.
webhook_urlstring—Facultatif. URL à notifier une fois le traitement terminé. Voir « Notification de fin ».
Envoyer un lot
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"
  }'

# Renvoie 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 }
  ]
}

Suivi de la progression : le statut status du lot passe par queued (en attente), running (en cours), puis completed (traitement terminé, avec ou sans erreurs). Chaque URL a pour statut pending, running, succeeded ou failed. En cas de réussite, result contient l’URL du fichier ; en cas d’échec, error contient le code d’erreur (identique à ceux des endpoints synchrones).

Consulter un lot
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" }
    }
  ]
}
  • La facturation est identique à celle des endpoints synchrones : chaque URL traitée avec succès consomme 1 unité pour une capture ou 2 pour un PDF. Les résultats en cache et les échecs ne consomment pas de quota.
  • Si le quota est déjà épuisé lors de l’envoi, la requête renvoie immédiatement quota_exceeded. S’il s’épuise pendant le traitement, les URL restantes échouent avec quota_exceeded.
  • Chaque compte peut avoir au maximum 5 lots en cours. Au-delà, la requête renvoie too_many_batches.
  • La durée de validité des fichiers est définie par options.cache_ttl (1 jour par défaut). Téléchargez-les et enregistrez-les avant leur expiration.
  • Dans les résultats de consultation et les notifications, webhook.url n’affiche que le chemin, sans la chaîne de requête.

Notification de fin

Si vous renseignez webhook_url, nous y envoyons une requête POST une fois le lot entièrement traité. Le corps JSON est { "event": "batch.completed", "batch": { … } }, où batch est strictement identique à la réponse de l’endpoint de suivi. En-têtes :

  • X-Glanceshot-Signature: t=1760779812,v1=5d3f… : t est l’heure d’envoi (horodatage Unix en secondes) et v1 la signature
  • X-Glanceshot-Event: batch.completed, X-Glanceshot-Delivery-Attempt: 1 (numéro de la tentative d’envoi)
Règles de signature
v1 = hex(HMAC-SHA256(secret, t + "." + Corps brut de la requête))
secret est le secret de signature associé à l’API Key utilisée pour soumettre la tâche (disponible sur la page API Key de la console).
  • Renvoyez une réponse 2xx sous 10 secondes, sinon l’envoi est considéré comme ayant échoué. En cas d’échec, trois nouvelles tentatives sont effectuées après 10 secondes, 1 minute et 5 minutes (4 tentatives au maximum au total).
  • Dans de très rares cas, vous pouvez recevoir plusieurs notifications pour une même tâche. Dédupliquez-les à l’aide de batch.id.
  • Pour vérifier la signature, utilisez les octets bruts reçus et assurez-vous que t ne diffère pas de l’heure actuelle de plus de quelques minutes afin d’éviter les attaques par rejeu.
  • L’URL de callback doit être une adresse http(s) accessible publiquement et ne doit pas pointer vers un réseau privé.
import crypto from "node:crypto";

// rawBody doit contenir les octets bruts reçus, sans passer par JSON.parse puis une nouvelle sérialisation.
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; // Protection contre le rejeu
  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)

Suivi de l’utilisation

GET/v1/usage
shell
curl "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", ... }

État du service

GET/v1/health

Sans authentification. Renvoie l’état du nœud et du pool de navigateurs (nombre total, occupés et disponibles).