When we started domscout, the pitch was simple: send a URL, get a screenshot. That is still the fastest path to a visual proof — but the requests we watched in production were mostly not ending in an image. They were ending in a JSON response, because the caller wanted the page *content*, and they were writing code to carve it out of rendered HTML.
That code is always worse than it looks in the pull request. It is written against one site, on one day, and it breaks when a class name changes. It is impossible to test properly, because the fixture is a page you do not control. And it is duplicated: everyone consuming the same handful of sites writes their own copy, badly, and none of them share it.
For Pro+ accounts, semantic snapshots are that carving, done once, server-side, deterministically. Semantic snapshots, the capture-body extract, diagnostics, render controls, cleanup, and related DOM intelligence are included in the plan. The platform retains a deployment-wide emergency pause: if it is active, GET /credits reports FEATURE_NOT_ENABLED with a platform reason rather than suggesting that a customer needs an account-level entitlement.
Four outputs, and how to choose
A capture can return several things at once, and the most common mistake is asking for all of them when one would do. Roughly:
- `extractMarkdown` — you want a human-readable version of the page, for a model to read or an index to store. This is the right default and it is on every plan.
- `semanticSnapshot` — you want to *act* on the page: click something, assert something is visible, drive a form. You need addresses, not prose.
- `extract` — you already know the exact fields you want and where they live. Deterministic, no model involved.
- The image or PDF — you need proof of what the browser saw, for a person or a record.
They compose. A monitoring job typically wants Markdown plus an image; an agent driving a checkout wants a snapshot; a catalogue sync wants extract and nothing else.
Clean Markdown, not HTML soup
The flagship output is extractMarkdown: the rendered page, rewritten as tidy Markdown. Headings, tables, lists, links, and alt text survive; script soup, inline styles, and hydration artifacts do not.
Every extraction reports what it produced. markdownMeta comes back with an estimated token count and a content-quality assessment for that specific page, so the reduction is something you measure on your own pages rather than something we assert on a marketing page. That matters more than a headline percentage, because the ratio varies enormously: a dense documentation page and a single-product landing page are not the same problem, and an average across both tells you nothing about yours.
If you want the number for a page you care about, the playground will run it — no account needed — and print the token count next to the result.
Structure your agent can act on
Markdown is great for reading; it is thin on structure. The semantic snapshot covers that side: tags, ARIA roles, accessible names, form state, hierarchy, visibility, bounding boxes, z-index, and ranked selectors for every node.
That is the difference between "there is a button on the page" and "there is a button with the accessible name *Checkout* at coordinates 420, 180, currently clickable". Actions use the same locator language — role and name, label, placeholder, text — so what your agent inspects is what it can click.
The ranking matters more than it sounds. A node usually has several possible selectors, and they are not equally durable: an id survives a redesign, a generated class name does not, and an nth-child path survives almost nothing. The snapshot returns them scored, so a caller storing a selector for later can store the one most likely to still resolve next month.
Deterministic extraction, by design
Separately, extract defines selector-driven fields: give a field a selector and a type (text, number, boolean, attribute, URL, list) and the response reports found, missing, or invalid with source evidence. It is not prompt-based and not an LLM call — the same page yields the same fields every time, which is what you want when the result feeds a database or a contract.
The strict flag is the part worth reading twice. With strict: false a missing field is reported as missing and the rest of the extraction still succeeds; with strict: true a required field that is absent fails the whole request. The second is what you want in a pipeline, because a row that silently arrives with a null price is worse than a row that never arrives.
Cleanup hides the chrome
Consent banners, chat widgets, and sticky nav are not content. The cleanup pass is a heuristic that hides likely chrome before extraction, with preserveSelectors to keep the elements you actually need. It is deliberately conservative: hiding the wrong thing is worse than keeping a banner, because a missing section is silent and a leftover cookie notice is merely annoying.
Diagnostics, for when the page did something unexpected
When a capture comes back thinner than you expected, the usual cause is that the page did not finish doing what it was going to do. diagnostics returns the console output, the failed requests and the response codes — redacted and bounded — which turns "the extraction was empty" into "the API call behind the content returned 403". It is the difference between guessing and knowing, and it costs one flag.
Where to see it
The snapshot page shows the request shape end to end, and the API docs cover the full contract — semanticSnapshot, cleanup, extract, and the diagnostics block that explains what the browser actually did. The playground lets you build a request for a URL and inspect the response, including without an account for the basic capture.