Page scripts

Run your JavaScript in the page, then capture the result

Some pages only show what you need after something happens. This is the parameter for making that something happen.

scriptsscripts_wait_untilbypass_cspclickhover
curl --fail-with-body "https://api.pagecapture.dev/v1/take" \
  -H "X-Access-Key: $PAGECAPTURE_KEY" \
  -H "Content-Type: application/json" \
  --data '{"url":"https://example.com","format":"jpg","scripts":"document.querySelectorAll('"'"'dialog[open]'"'"').forEach((node) => node.close())"}' \
  -o capture.jpg

Verified 2026-08-13 by running the published code against a fixture.

Configure it in the playground
What you are seeing

The content exists, but only after an accordion opens, a tab is selected or a modal is dismissed — and none of that is reachable through a URL.

Why the page does that

The state you want to capture is client-side. No combination of waiting produces it, because nothing on the page is going to do it on its own.

What it does

  • Evaluates each entry in the page context, in order, wrapped in an async function so `await` works.
  • Waits for the navigation state named by `scripts_wait_until` first, so a script that touches the DOM does not race the parser.
  • Fails loudly and specifically: a script that throws returns `request_not_valid` naming the index that threw, rather than a generic capture failure.

What it does not do

  • Does not run in Node. There is no `require`, no filesystem, no environment and no CDP access — only what a page script has.
  • Does not let a script navigate away. If the URL changes, the capture stops with `script_triggers_redirect`, because the artifact would no longer be of the page you asked for.
  • Does not get its own timeout. A script that never resolves is ended by the job's `timeout`, and that failure is not billed.
The contract

Every limit on this page is the one the API enforces

These rows are read from the same parameter table that validates your request. Nothing here is transcribed, so a number cannot drift from the behaviour it describes.

ParameterTypeDefaultRangeEndpointsCache key
scripts

JavaScript executed in the page context, in order.

string[]/v1/take, /v1/animateIn
scripts_wait_until

Navigation state to reach before running scripts.

enumload/v1/take, /v1/animateIn
bypass_csp

Bypass the page Content Security Policy. Opt-in and recorded.

booleanfalse/v1/take, /v1/animateIn
click

Selector clicked before capturing.

string/v1/take, /v1/animateIn
hover

Selector hovered before capturing.

string/v1/take, /v1/animateIn
Group: Page customizationValues outside a documented range are rejected before a browser opens.

How it behaves next to the rest of the request

scripts_wait_until

Navigation state to reach before running scripts.

Defaults to `load`. Use `domcontentloaded` when your script only needs the DOM and the page has heavy assets, or `networkidle` when it depends on data that arrives by XHR.

click

Selector clicked before capturing.

For a single interaction, `click` is smaller and safer than a script — and it fails by default when the selector is missing, which a script would not.

bypass_csp

Bypass the page Content Security Policy. Opt-in and recorded.

Pages with a strict CSP can refuse injected execution. Turning this on changes the security posture of the render, so it is opt-in and recorded on the request.

Questions this raises

Where exactly does my script run?

In the page context of an isolated browser context that is destroyed when the job ends. It sees the page's `window` and `document`, and nothing of ours.

What if my script needs to navigate?

It cannot. A URL change after the script runs stops the capture with `script_triggers_redirect` — capture the second URL as its own request instead.

Is my script stored?

It is part of the request and part of the cache key, so it is stored the way any non-secret parameter is. Never put a credential in it: cookies, headers and `authorization` are the parameters that get encrypted.