Glanceshot
开发者文档

API 文档

基础地址 https://glanceshot.com/v1。所有接口都是标准 HTTP,参数可以放在查询串(GET)或 JSON body(POST)里。

快速开始

  1. 免费注册,在控制台的「API Key」页面创建一个 Key。
  2. 把 Key 放进 X-Access-Key 请求头,调用截图接口:
curl "https://glanceshot.com/v1/screenshot?url=https://example.com&full_page=true" \
  -H "X-Access-Key: $GLANCESHOT_KEY" \
  -o screenshot.png

鉴权

每个请求都需要 API Key,可以用下面任一方式传递:

  • 请求头 X-Access-Key: gls_…(推荐,服务端调用使用)
  • 查询参数 access_key=gls_…(只在服务端调用时使用,不要写进网页)
  • 签名 URL(需要把地址放进网页时使用,API Key 和 secret 都不会暴露)

API Key 的明文只在创建时显示一次,请妥善保存。泄露后可以在控制台停用。

截图接口

GET/v1/screenshot
POST/v1/screenshot

截图专用参数:

参数类型默认值说明
formatenumpngpng、jpeg 或 webp。
device_scale_factornumber1缩放比 1–3。设为 2 可获得 Retina 清晰度,体积约为 4 倍。
qualityinteger80JPEG / WebP 质量,1–100。
full_pagebooleanfalse截取整页。会逐屏滚动触发懒加载,高度上限 20,000 像素。
selectorstring—只截取匹配该 CSS 选择器的第一个元素。不能与 full_page 同时使用。

截图和 PDF 共用的参数:

参数类型默认值说明
urlstring—要截取的网页地址,http 或 https。与 html 二选一。网址里的 #片段会保留,hash 路由的单页应用(如 https://app.com/#/report/1)可以直接截取对应页面。
htmlstring—直接传入 HTML(最大 2 MB),仅支持 POST。
viewport_widthinteger1280视口宽度,320–3840。小于 768 时按移动设备渲染。
viewport_heightinteger800视口高度,200–3840。
wait_untilenumnetworkidle等待策略:domcontentloaded(最快,适合静态页)、load、networkidle(从打开页面起跟踪所有请求,页面加载完后连续 500 毫秒没有进行中的请求才截图,最多再等 8 秒,适合单页应用)。
wait_for_selectorstring—页面加载完后,等匹配这个 CSS 选择器的元素出现并且可见再截图,最多等 10 秒;等不到返回 selector_not_found(不计费)。适合不靠网络请求、用定时器或动画延迟渲染内容的单页应用,例如 .chart-ready。
delayinteger0等待完成后再延迟的毫秒数,0–10000。用于等动画或懒加载组件。
block_adsbooleantrue拦截广告与跟踪域名的请求,并隐藏页面上的广告位。
block_cookie_bannersbooleantrue隐藏 Cookie 同意弹窗。
dark_modebooleanfalse模拟 prefers-color-scheme: dark。
hide_selectorsstring—要隐藏的元素,CSS 选择器列表,例如 .ad,#popup。
cachebooleantrue是否查找缓存。设为 false 时强制重新渲染,结果仍会写入缓存。
cache_ttlinteger86400缓存有效期(秒),60–2592000。
response_typeenumbinarybinary 直接返回文件;json 返回文件地址和元数据。
proxystring—可选,用你自己购买的代理访问目标网页(代理费用由你承担),例如需要从指定国家或地区访问时。支持 socks5:// 和 http://,可以带账号密码,格式如 socks5://user:pass@203.0.113.10:1080。只能放在 POST 请求体里,不能用于 GET 请求、签名 URL 和批量任务。用了代理的请求单独缓存;代理连不上、认证失败或无法访问目标网站时返回 proxy_failed,不计费。
cookiesstring | object[]—目标网站的 Cookie,可以是 sid=abc; theme=dark 这样的一行,也可以是 [{"name":"sid","value":"abc"}] 这样的数组(可带 domain、path)。只会发给目标网站,不发给页面里的第三方。
headersobject—要附加的请求头,如 Authorization: Bearer …。只发给目标网站;浏览器自己管理的头(Host、Cookie、User-Agent 等)不能设。
local_storageobject—要写入目标网址所在源的 localStorage,键值都是字符串。
session_storageobject—同 local_storage,写入 sessionStorage。
login_profilestring—用浏览器插件保存的登录档案编号(lp_8f2c…)。比直接传 cookies 更省事,也能用在批量任务里(任务里不保存任何凭据)。

截取单页应用(React、Vue 等):页面会在真实浏览器里执行完 JavaScript 再截图。默认的 networkidle 会等页面拉完数据;如果内容是请求结束后再用定时器或动画渲染的,加上 wait_for_selector 指定一个“内容已就绪”的元素;实在没有合适的元素,再用 delay 多等一会儿。

PDF 接口

GET/v1/pdf
POST/v1/pdf

PDF 每次计 2 次额度。打印前会先滚动一遍页面触发懒加载内容。除共用参数外,还支持:

参数类型默认值说明
paperenuma4纸张:a4 或 letter。页面自带 @page 规则时优先使用页面的设置。
print_backgroundbooleantrue打印背景色和背景图。
pdf_mediaenumprintprint 使用打印样式;screen 使用屏幕样式(所见即所得)。
HTML 转 PDF
curl -X POST "https://glanceshot.com/v1/pdf" \
  -H "X-Access-Key: $GLANCESHOT_KEY" \
  -H "Content-Type: application/json" \
  -d '{"html": "<h1>季度报告</h1><p>正文……</p>", "paper": "a4"}' \
  -o report.pdf

返回结果

默认(response_type=binary)直接返回文件,Content-Type 为对应格式。响应头:

  • X-Request-Id:本次请求 ID,排查问题时请提供
  • X-Glanceshot-Cache:HIT 或 MISS
  • X-Glanceshot-Truncated: true:整页超过 20,000 像素被截断
  • X-Glanceshot-Format-Changed: webp:PNG 超过 5 MB 自动转为 WebP(显式指定 format=png 时不会转换)

设置 response_type=json 时返回文件地址和元数据:

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"}'

# 返回
{
  "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

想把截图地址直接写进 <img src>,又不想暴露 API Key?签名 URL 里不放 API Key,只放公开的 key_id,再在你自己的服务端用 Key 对应的 secret 计算签名。Key ID 和 secret 都在控制台的 API Key 页面查看:

签名规则
canonical = 除 signature 外的全部参数,按参数名字典序排序,
            每项 k=urlencode(v)(RFC 3986,空格编码为 %20),用 & 连接
signature = hex(HMAC-SHA256(secret, canonical))

签名正确即视为已鉴权,缺少签名或签名不对都会被拒绝。任何参数被改动(比如换了 url),签名都会失效。可选参数 expires(Unix 秒)参与签名,过期后返回 signature_expired。想刷新缓存时,改一个无意义的参数(如 v=2)重新签名即可。签名 URL 只支持 GET 方式调用截图和 PDF 接口,也不能带代理参数。

key_id 是公开的,单独拿到它不能调用接口。不要把 API Key(access_key)放进签名 URL,带了会直接返回 invalid_params。如果之前把 API Key 写进过网页,请在控制台停用这把 Key,再新建一把。

import crypto from "node:crypto";

// RFC 3986 编码(空格为 %20),必须和服务端规则一致
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="网页预览" />

使用代理

需要从指定国家或地区访问网页时(例如查看当地的语言、内容和价格),可以在请求里带上你自己购买的代理,代理费用由你承担。页面和页面上的图片、脚本、接口请求都会经这个代理加载。支持 socks5:// 和 http:// 两种代理,可以带用户名和密码。

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 只能放在 POST 请求体里:GET 请求、签名 URL 和批量任务都不能带,避免代理的账号密码出现在网址、浏览器历史或网页里。
  • 用户名或密码里有 @、: 等特殊字符时,要先做 URL 编码(例如 @ 写成 %40)。
  • 用了代理的请求单独缓存,不会和不带代理、或带其他代理的请求共用结果。
  • 代理连不上、认证失败或无法访问目标网站时返回 proxy_failed,不计费,message 说明具体原因。
  • 代理必须是公网地址。目标网址的限制和不带代理时一样,不能访问内网地址。
  • 经代理访问网站时,请遵守目标网站的使用条款和当地法律。

截登录后的页面

要截取需要登录才能看到的页面,可以带上你自己账号的登录状态。有两种方式:直接在请求里传 cookies、headers、local_storage、session_storage,或者用 Glanceshot 浏览器插件把登录状态保存成“登录档案”、请求里只放 login_profile。

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
  • 插件能读出网页脚本读不到的登录凭据(包括 HttpOnly Cookie),以及 localStorage、IndexedDB,适合大多数网站。到控制台的“登录档案”页安装并连接插件。
  • 登录状态只能通过 POST 请求体传(GET、签名 URL 都会被拒绝),不会写进日志和调用记录;带了登录状态的请求按它单独缓存,不会和别人共享。
  • 如果带了登录状态、页面却跳回了登录页,返回 login_expired、不计费(说明登录已失效,用插件重新同步)。
  • 对于会话绑定了设备或 IP、无法在云端重现登录的网站(如网银),用插件的“截取当前页面”在你自己的浏览器里截图后上传。

缓存

参数完全相同的请求会命中缓存(省略参数和显式传默认值视为相同;鉴权参数和缓存参数不参与比较)。命中时二进制模式返回 302 跳转到文件地址,并带 Cache-Control,浏览器会自动跟随跳转并缓存;JSON 模式返回 cache_hit: true。

命中缓存不计费。同一参数的并发请求只会渲染一次。

限额与计费

  • 只对成功(2xx)且未命中缓存的请求计费:截图 1 次,PDF 2 次。
  • 超时、渲染失败、目标站报错或拦截访问、参数错误、鉴权失败都不扣额度。
  • 额度按自然月(UTC)重置。免费套餐每月 100 次,用完后返回 quota_exceeded。
  • 超过每秒请求数或并发数返回 429,响应头 Retry-After 给出建议的等待秒数。
  • 单次渲染最长 30 秒;单页下载量上限 50 MB;输出文件上限 50 MB。

查看各套餐的具体限额:价格。

错误码

错误响应统一为 JSON:

错误格式
{
  "error": {
    "code": "render_failed",
    "message": "target responded with an error status",
    "upstream_status": 404,
    "request_id": "req_01j…"
  }
}
HTTPcode含义计费
400invalid_params参数缺失或超出范围,message 说明具体是哪个参数否
400html_too_largehtml 超过 2 MB否
401unauthorized缺少 API Key,或 Key 无效 / 已停用否
401signature_invalid签名不匹配(参数被改动或 secret 错误)否
401signature_expired签名 URL 已超过 expires 时间否
403url_blocked目标地址不允许访问(例如内网地址、localhost)否
408render_timeout渲染超过 30 秒否
422render_failed目标站返回 4xx/5xx、DNS 失败或证书错误;带 upstream_status否
422selector_not_foundselector 没有匹配到元素,或 wait_for_selector 等待超时否
422too_many_redirects重定向超过 5 次否
422site_blocked目标网站没有显示正常内容,而是显示了人机验证、验证码、登录墙或拒绝访问的页面;不计费否
422login_expired带了登录状态,但目标网站显示的还是登录页,说明登录状态已失效。否
422proxy_failed你传入的代理连不上、认证失败,或代理无法访问目标网站;message 说明具体原因,不计费否
429rate_limited超过每秒请求数,按 Retry-After 重试否
429concurrency_exceeded超过并发数否
429quota_exceeded当月额度已用完(免费套餐)否
429too_many_batches同时未完成的批量任务超过 5 个否
500internal服务端错误,请带上 request_id 联系我们否

异步批量

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

一次提交 1–100 个网址,接口立即返回任务 ID(HTTP 202),截图在后台逐个完成。适合批量截图、不想一直等待连接的场景。可以轮询查询接口,也可以填 webhook_url,全部完成后我们会主动通知你。鉴权方式和同步接口相同(只支持请求头或 access_key 参数,不支持签名 URL)。

参数类型默认值说明
typeenumscreenshotscreenshot(截图)或 pdf。
urlsstring[]—要处理的网址,1–100 个。任何一个不合法时整个请求返回 400,message 指出是第几个。
optionsobject{}所有网址共用的参数,和同步接口的参数相同(如 full_page、format、viewport_width、cache_ttl),不能包含 url、html、response_type、proxy。
webhook_urlstring—可选。全部完成后通知的地址,见「完成回调」。
提交批量任务
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"
  }'

# 返回 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 }
  ]
}

查询进度:任务状态 status 依次是 queued(排队中)、running(处理中)、completed(全部完成,无论成功还是失败)。每个网址的状态是 pending、running、succeeded 或 failed;成功的在 result 里给出文件地址,失败的在 error 里给出错误码(和同步接口的错误码一致)。

查询批量任务
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" }
    }
  ]
}
  • 计费规则和同步接口相同:每个成功的网址截图计 1 次、PDF 计 2 次,命中缓存和失败的不扣额度。
  • 提交时额度已经用完会直接返回 quota_exceeded;处理过程中额度用完,剩下的网址会以 quota_exceeded 失败。
  • 每个账号同时最多 5 个未完成的批量任务,超过返回 too_many_batches。
  • 结果文件的有效期由 options.cache_ttl 决定(默认 1 天),请及时下载保存。
  • 查询结果和回调里的 webhook.url 只显示到路径,不回显查询串。

完成回调

填了 webhook_url 时,任务全部完成后我们会向它发送一个 POST,请求体是 JSON:{ "event": "batch.completed", "batch": { … } },其中 batch 和查询接口的返回完全相同。请求头:

  • X-Glanceshot-Signature: t=1760779812,v1=5d3f…:t 是发送时间(Unix 秒),v1 是签名
  • X-Glanceshot-Event: batch.completed、X-Glanceshot-Delivery-Attempt: 1(第几次投递)
签名规则
v1 = hex(HMAC-SHA256(secret, t + "." + 原始请求体))
secret 是提交任务时所用 API Key 对应的签名 secret(控制台 API Key 页面查看)
  • 请在 10 秒内返回 2xx,否则视为失败。失败后会在 10 秒、1 分钟、5 分钟后各重试一次(共最多 4 次)。
  • 极少数情况下同一个任务可能收到重复通知,请按 batch.id 去重。
  • 验签时用收到的原始字节计算,并检查 t 与当前时间相差不超过几分钟,防止重放。
  • 回调地址必须是公网可访问的 http(s) 地址,不能指向内网。
import crypto from "node:crypto";

// rawBody 必须是收到的原始字节,不能先 JSON.parse 再序列化
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; // 防重放
  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)

用量查询

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", ... }

健康检查

GET/v1/health

无需鉴权,返回节点状态和浏览器池状态(总数、忙碌、空闲)。