Snapshot
Metadata, markdown, links, images, headings, colours and fonts from a fully rendered page — including everything JavaScript drew.
One API for screenshots, structured snapshots, whole-site crawls and page-reconstruction blueprints. Runs on Cloudflare's edge — no browsers to operate, no queues to babysit, no infrastructure to keep alive.
100 credits a month, free. No card required.
curl "https://api.scrinly.com/render/snapshot" \ --get \ -H "Authorization: Bearer sk_live_..." \ --data-urlencode "url=https://linear.app" \ -d "markdown=true" \ -d "links=true" \ -d "design=true" # Images, fonts and media are blocked unless # you ask for them, so a snapshot loads about # twice as fast as a screenshot.
{ "success": true, "type": "snapshot", "metadata": { "title": "Linear — Plan and build products", "description": "Linear streamlines issues...", "favicon": "https://linear.app/favicon.ico" }, "markdown": "# Plan and build products\n...", "links": [128 /* unique, absolute */], "design": { "tokens": { "count": 214 }, "breakpoints": [640, 768, 1024, 1280], "libraries": ["framer-motion"] }, "renderTime": 1412 }
Scrinly does not try to be a scraping framework. It does three things a headless browser is uniquely good at, and returns them as plain JSON you can use the same day.
Metadata, markdown, links, images, headings, colours and fonts from a fully rendered page — including everything JavaScript drew.
Full page or viewport, JPEG or PNG, device emulation, dark mode, and one flag each to hide cookie banners, ads, chat widgets and popups.
Walk a whole site from one seed URL. Scope rules, robots.txt, per-host politeness and a live page index, all handled.
Point it at a URL and get back what the page actually contains after rendering — not the empty shell an HTTP fetch returns. Markdown for models, structure for pipelines, metadata for everything else.
# Plan and build products Linear is a purpose-built tool for planning and building products. ## Made for modern product teams - Purpose-built for product development - Designed to move fast - Crafted to perfection [Get started](https://linear.app/signup)
{ "headings": [ { "level": 1, "text": "Plan and build..." }, { "level": 2, "text": "Made for modern..." } ], "ctas": [ { "text": "Get started", "y": 412 }, { "text": "Talk to sales", "y": 412 } ], "sections": 14, "wordCount": 1284 }
Real Chrome, real layout. Emulate a device, force dark mode, hide the cookie banner, click something first, then take the shot — full page or viewport, returned as bytes or stored for you.
Give it a starting point and a scope. Scrinly discovers the frontier, obeys robots.txt, stays polite to the host, and snapshots every page it finds — up to five thousand of them, without you managing a queue.
Scrinly walks the real stylesheets — including cross-origin ones and everything inside media queries — and returns the tokens, the palette, the type stack, the breakpoints and the motion vocabulary.
"customProperties": [ { "name": "--brand", "resolved": "#5E6AD2", "kind": "color" }, { "name": "--radius-md", "resolved": "8px", "kind": "length" } ], "breakpoints": [ { "px": 768, "rules": 142 }, { "px": 1024, "rules": 96 } ], "motion": { "durationsMs": [150, 250, 400], "easings": ["cubic-bezier(.22,.61,.36,1)"], "reducedMotionSupport": true }, "libraries": ["framer-motion", "lenis"]
Add blueprint=true
and the page comes back section by section: each region labelled with the
evidence behind it, every animation filed under the region it belongs to,
and the CSS generated from observed values. An agent gets what it needs to
rebuild the page, not a dump of the DOM.
{ "label": "hero", "confidence": "high", "evidence": ["contains the h1", "starts above the fold", "contains a call to action"], "motion": [{ "type": "fade-up", "trigger": { "kind": "scroll-into-view" }, "timing": { "durationMs": 600, "easing": "cubic-bezier(.4,0,.2,1)" }, "modifiers": { "stagger": { "stepMs": 100, "count": 3 }} }], "components": [{ "repeatOf": "div|card", "count": 3 }] } # Repeated siblings are reported with a count, # so an agent emits a loop instead of twelve # near-identical cards.
/* stylesheets["keyframes.css"] */ @keyframes fadeInUp { 0% { opacity: 0; transform: translateY(24px); } 100% { opacity: 1; transform: none; } } /* stylesheets["responsive.css"] */ @media (max-width: 390px) { div.grid { grid-template-columns: 1fr; } #headline { font-size: 32px; } }
Not the site's media queries read back.
Two rendered viewports are compared, so what you get is what actually
changed. Computed width and height are left
out — emitting them would pin the layout to one screen.
Add interpret=true
and the blueprint comes back as prose as well — the page described region
by region for an engineer who has to rebuild it and cannot see it. The
model never sees the page: only a sanitised projection crosses, with the
copy, selectors and URLs removed first.
observedSix regions in document order. A sticky
header landmark, a full-viewport hero carrying the
h1, then features, pricing and testimonials, each built
from three repeated cards.
observedEleven animations. The features cards
fade up on scroll at 600ms with a 100ms
stagger across three siblings; one element pulses on an infinite loop.
inferredThe single easing curve across every reveal suggests one shared transition token rather than per-component timing.
Form validation is detected and not recovered. No WebGL was observed. Region skeletons were capped for length; the caps are reported.
Every literal is checked. Each hex code, duration, easing curve and token name in the document is matched back against the projection it came from. More than five unsupported values, or a missing section, refuses the generation and refunds it rather than publishing a confident document with invented numbers in it.
Observed and inferred are labelled. Interpretation is allowed but quarantined, so you always know which claims survive if the model is wrong.
The blueprint is yours either way. A provider outage returns the full capture with the document marked as the part that failed, and only the interpretation credits come back.
Bring your own key. Use ours or your own provider credential. Either way the prompt carries no URL, no HTML and no page text.
Credits are charged before the work starts and refunded when it fails, so a request you never got is a request you never paid for. Every response carries your balance in the headers.
A snapshot or screenshot costs one credit. Design extraction costs two, a blueprint eight, and reading it back three more. Every plan includes the whole API — the only thing that changes is how many credits you get each month.
Everything, at a small scale.
Free forever
Start freeFor a first production workload.
billed monthly
Choose StartupThe plan most teams settle on.
billed monthly
Choose ProSteady, high-volume pipelines.
billed monthly
Choose BusinessCrawling at the top of the range. Everything in Business, with nine times the allowance and storage on your own bucket.
Yearly plans are billed once but the credit allowance still refreshes every month — an annual plan is not twelve months of credits handed over at once. Credits are charged before a render starts and refunded if it fails. See how credits work →
Everything here is how the API behaves today, not a roadmap. Shipping history lives in the changelog.
No. Renders run on Cloudflare Browser Rendering, so there is no Chromium to operate, no container to size and no queue to babysit. You send a URL and get bytes or JSON back.
Crawls do. They obey robots.txt including
Crawl-delay, identify themselves as
Scrinly/3.0 with a link to a bot page, and are limited to one
request a second and two at a time per host by default.
A single render is a page you asked for by URL — the same as opening a
tab — so it is fetched directly. Crawls can opt out with
robots=ignore, which is your call to make about sites you
control.
Synchronous by default: one request, one response. Pass
async=true or a webhookUrl and the job is queued
instead — you get a 202 with an id to poll, or the result
delivered to your endpoint.
Blueprints are always synchronous. Making an agent poll in the middle of a task is the one thing they exist to avoid.
Your bucket. Backblaze B2 by default, with S3 and R2 supported — you pass the credentials per request and they are never persisted. Leave storage off and screenshots come back as raw bytes instead.
You keep whatever succeeded and pay only for that. A blueprint whose interpretation fails returns the full capture with the document marked as the part that did not land, and only the interpretation credits come back.
A crawl reports per-page status rather than collapsing to one verdict, so forty good pages are not lost to one bad one.
Yes, in one request header. It cuts an interpretation to a single credit and the key is never stored or logged. Either way the prompt carries no URL, no HTML and no page text.
Charged before the work starts. Refunded when it fails. You never pay for a render you did not get.
Your keys are hashed, never stored. Every job, crawl and schedule is scoped to the account that made it.
100 credits a month. No card, no sales call.