Injected CSS

Inject your own CSS into a page you do not control

The page belongs to someone else. The stylesheet you add to it, for the length of one capture, belongs to you.

styleshide_selectorsreduced_motionmedia_type
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","styles":"* { animation: none !important; transition: none !important; }"}' \
  -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 capture is correct and unusable: a sticky header covers the heading, an animation is caught mid-frame, or a transparent block picks up whatever is behind it.

Why the page does that

You are capturing production CSS written for a human scrolling, not for a single-frame render of the first viewport.

What it does

  • Injects each stylesheet into the page context, in the order given, immediately after the navigation and waits — before hiding, before your scripts, before any click.
  • Accepts up to 128 KiB of CSS across all entries, checked at validation so an oversized payload fails before a browser is opened.
  • Is part of the cache key, so two different stylesheets never share a cached result.

What it does not do

  • Does not run JavaScript. A style tag cannot expand a section that only opens on click — that is `click` or `scripts`.
  • Does not fail the capture when the injection is refused. A page with a restrictive Content Security Policy can reject the tag, and the capture continues without it unless you set `bypass_csp`.
  • Does not persist. The stylesheet exists for the length of one capture and is gone with the browser context.
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
styles

CSS injected into the page.

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

Selectors to hide before capturing.

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

Emulate `prefers-reduced-motion: reduce`.

booleanfalse/v1/take, /v1/animateIn
media_type

CSS media type to emulate.

enumscreen/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

bypass_csp

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

A page whose CSP forbids inline styles will drop the injected tag. `bypass_csp` disables that enforcement for the capture — it is opt-in and recorded, because it changes the security posture of the render.

hide_selectors

Selectors to hide before capturing.

Hiding is the same mechanism with a fixed rule: `visibility: hidden !important` on the selectors you name. Use it for removal and `styles` for anything else.

reduced_motion

Emulate `prefers-reduced-motion: reduce`.

For animations, emulating `prefers-reduced-motion: reduce` is usually cleaner than overriding every transition by hand — the page's own reduced-motion styles do the work.

Errors this option can produce

None of them is billable. No error code in the catalog is.

Questions this raises

How do I know the CSS was applied?

Compare a capture with and without it. There is no per-rule report — the injection is one style tag, and a page that rejects it under CSP does so silently, which is why `bypass_csp` exists as an explicit escape.

Is there a size limit?

128 KiB across all entries. The check runs during validation, so an oversized stylesheet costs nothing: no browser is opened and no credit is consumed.

Can I load a stylesheet from a URL instead?

Not through this parameter — it takes CSS text. A remote stylesheet would be a second network dependency inside a capture, and one that the egress policy would have to clear anyway.