Authenticated pages

Screenshot pages that require a login

Dashboards, admin panels and per-customer views — captured with the same session your user would have.

authenticated page screenshot api · request and resultPAGECAPTURE / 01
TypeScript
const response = await fetch("https://api.pagecapture.dev/v1/take", {
  method: "POST", // always POST when a credential is involved
  headers: {
    "X-Access-Key": process.env.PAGECAPTURE_KEY!,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    url: "https://app.example.com/reports/42",
    cookies: ["session=abc123; Domain=.example.com; Path=/; Secure"],
    authorization: "Bearer eyJhbGciOi...",
    wait_for_selector: "[data-report-ready]",
    format: "png",
  }),
});
Capture result
succeeded
https://example.com
Noma
Shop now
NEW COLLECTION

Objects for slower mornings.

Thoughtful essentials, made in small batches from natural materials.

Explore the collection
No. 01 · Hinoki
PLANT-BASEDMADE IN SMALL BATCHESREFILLABLE
Artifact
PNG · 1440×900
Billing
1 credit
Engine
stable

Cookies, headers, Authorization

Sent exactly as you specify. Without an explicit Domain, a cookie is anchored to the URL you are capturing.

Encrypted and destroyed

Credentials are separated before storage, encrypted with AES-256-GCM, decrypted only in the worker and destroyed with the job.

Never in a log

They do not appear in the request log, the normalized options, or any error message.

Cached without leaking

The cache key includes a hash of your credentials, so two sessions never share a result — and the values stay out of the key.

Pricing

One credit per successful capture. Failures and cache hits are free.

Free
$0
100 credits
Basic
$10
2,000 credits
Growth
$47
10,000 credits
All plans

Questions this raises

Is my session token safe?

It never touches a log or the dashboard. It lives encrypted for the lifetime of the job, is decrypted only inside the worker, and its record is zeroed afterwards.

Why POST and not a signed GET?

Signed GETs deliberately reject credentials. A query string ends up in proxy logs, browser history and referrer headers.

How do I wait for data to load?

wait_for_selector on an element your app renders when the view is ready. It beats a fixed delay, which is either too short or wasteful.