Skip to main content
Tutorial

Website to JSON Extraction: Structured Data in 10 Lines

Turn any website into structured JSON in ~10 lines: define a schema, call /v1/scrape with the json output format, and get typed records. Code, costs, limits.

fastcrw
By RecepJuly 11, 20268 min readLast updated: July 12, 2026

By the fastCRW team · Credit costs and capabilities verified 2026-05-18 against the canonical fact sheet · Verify independently before building on them.

Website to JSON extraction, conceptually

Website to JSON extraction means pulling specific, typed fields — a price, a title, a list of specs — out of a page and into a structured record your code can use directly. It sits one level above plain scraping: instead of getting the whole page as Markdown and then writing parsing logic, you declare the shape you want and let the extractor fill it. This guide shows the exact 10-line happy path with fastCRW, what each request costs in credits, which LLM providers run the extraction, and the one limit most "extract anything" pitches gloss over: there is no multi-URL batch endpoint.

Why JSON beats Markdown when you need specific fields

Markdown is the right output when you want the whole page as clean context for a retrieval system or a summarizer. But when you need three fields — say title, price, and inStock — Markdown forces you to re-parse prose every time the page layout shifts. JSON extraction collapses that into one step: you get { "title": "...", "price": 49.0, "inStock": true } back, already typed, ready to validate and store. If your downstream consumer is a database row, an API response, or a typed struct, JSON is the format that survives the trip.

Schema-guided extraction vs brittle CSS selectors

The traditional approach is CSS or XPath selectors: document.querySelector(".price"). Selectors are precise until the site ships a redesign, renames a class, or A/B-tests a layout — then every selector silently returns null and your pipeline fills with empty rows. Schema-guided extraction describes what you want ("the product's sale price as a number") rather than where it lives in the DOM, so it tolerates markup changes a selector cannot. The trade is determinism for resilience: an LLM filling a schema is more robust to layout drift but introduces the usual LLM caveats — occasional misreads on ambiguous pages, which is why validation (covered below) is not optional.

Where the LLM fits: filling a schema from page content

Under the hood, fastCRW first renders and cleans the page to Markdown, then hands that content plus your jsonSchema to an LLM that returns a JSON object conforming to the schema. Extraction quality is therefore downstream of extraction accuracy: if the underlying scrape misses the main content, the schema gets filled from noise. That is why we lead with the measured number — fastCRW posted the highest truth-recall of the three tools tested, 63.74% of 819 labeled URLs (diagnose_3way.py, Firecrawl's public dataset, 2026-05-08), ahead of Crawl4AI (59.95%) and Firecrawl (56.04%). Cleaner input means the schema is filled from the right text.

Website to JSON in 10 lines

The whole job is three moving parts: a schema, a /v1/scrape call with the json output format, and a target URL.

Define a jsonSchema for the fields you want

Describe the record you want as a JSON Schema. Keep it small — fewer, well-named fields extract more reliably than a sprawling schema with vague descriptions:

  • title — string, the product name
  • price — number, the current price in the listed currency
  • inStock — boolean, whether the item is purchasable now

Call /v1/scrape with the json output format

Send one POST to /v1/scrape with formats: ["json"] and your schema. A curl version of the request:

curl -X POST https://api.fastcrw.com/v1/scrape -H "Authorization: Bearer $CRW_API_KEY" -H "Content-Type: application/json" -d '{"url":"https://example.com/product/42","formats":["json"],"jsonSchema":{"type":"object","properties":{"title":{"type":"string"},"price":{"type":"number"},"inStock":{"type":"boolean"}},"required":["title","price"]}}'

The response carries your typed object under the JSON output field. That is the entire path from URL to structured record — no separate parsing service, no selector maintenance.

The same request via the Firecrawl-compatible SDK (base-URL swap)

fastCRW speaks a Firecrawl-compatible REST API, so existing Firecrawl SDK code works after a base-URL swap — point the client's api_url at your fastCRW endpoint and keep the rest. In Python with the crw SDK, CrwClient() runs a self-contained local engine, so the same jsonSchema you used in curl works from a script without standing up a server. One schema, one call, both languages. For the full schema-design reference, see structured extraction with JSON Schema.

What it costs and which providers run the extraction

What JSON extraction costs per request

Any request that includes formats: ["json"] — equivalently, anything that triggers LLM extraction — costs the 1-credit scrape plus the LLM token cost, billed as usage-metered LLM credits. That is more than a plain scrape (a flat 1 credit on any renderer) because you are paying for an LLM pass on top of the fetch and clean; how much more scales with page size and token usage, not a fixed multiple. Budget accordingly: a thousand product pages extracted to JSON is ~1,000 scrape credits plus the per-page LLM token cost, versus ~1,000 credits flat if you only needed Markdown. Live pricing per plan is on the pricing page rather than hard-coded here.

LLM extraction runs on fastCRW's managed LLM

State this plainly: fastCRW's jsonSchema extraction runs on fastCRW's managed LLM. There is no key, provider, or model to configure and no way to point it at your own model, and the path is available on paid plans only (the Free plan returns HTTP 402). The managed /v1/search answer mode runs on the same managed LLM. Knowing that up front is the kind of honesty the vague "extract anything" marketing skips.

/v1/extract is a managed single-URL convenience wrapper

On the managed cloud you will also see /v1/extract. It is a convenience wrapper over /v1/scrape with formats: ["json"] — same cost (the 1-credit scrape plus the LLM token cost), same engine, slightly different ergonomics — and it is single-URL. Self-hosters skip it entirely and call /v1/scrape + jsonSchema directly. There is no behavioral magic in /v1/extract you cannot reproduce with a scrape call; it exists for parity with the Firecrawl surface. The deep-dive lives at the extract endpoint guide.

Extracting from many URLs

There is no multi-URL batch extract: iterate /v1/scrape concurrently

Here is the limit to plan around: fastCRW has no batched multi-URL extract endpoint. There is no /v1/batch/scrape, and /v1/extract is single-URL. To extract from a list of URLs, you iterate /v1/scrape yourself, ideally with bounded concurrency (a worker pool of, say, 5–10 in-flight requests) so you do not overwhelm the target site or your own rate limits. This is more code than a single batch call, but it is also fully under your control — retries, backoff, and per-URL error handling are yours to tune.

Or crawl first, then extract per page

When the URLs are not known ahead of time — you want "every product page on this store" — start with /v1/crawl (async BFS, returns a job ID, with a maxDepth cap of 10 and maxPages cap of 1000), collect the discovered pages, then run a JSON extraction per page. Crawl is billed 1 credit per page, and each JSON extraction on top is the 1-credit scrape plus the LLM token cost, so price the two stages separately. For the crawl-and-extract pattern end to end, see list crawling for structured data.

Pagination and listing pages

Listing pages (search results, category indexes) often hold many records on one URL. Two strategies: extract an array directly from the listing page with a schema whose top level is an array of objects, or extract the per-item links from the listing and then scrape each detail page individually. The array-on-one-page approach is cheaper (one extraction — a 1-credit scrape plus its LLM token cost — per listing page) but only as complete as what the listing renders; the per-detail-page approach costs more but captures fields that only appear on the item page. Pick based on which fields you actually need.

Validating and storing the JSON

Schema validation and handling missing fields

An LLM filling a schema can still return a field as null, omit an optional property, or coerce a type loosely. Re-validate the response against your jsonSchema in your own code (with Zod, Pydantic, or a JSON Schema validator) before trusting it. Decide explicitly what a missing required field means: drop the record, retry once, or flag it for review. Treat extraction output as untrusted input that happens to be well-shaped, not as guaranteed-correct data.

Deduplication before you persist

When you extract across many URLs — especially after a crawl — you will hit the same logical record via different URLs (canonical vs. tracking-parameter variants, paginated duplicates). Deduplicate on a stable business key (a product SKU, a canonical URL, a content hash) before writing to your store, so a re-run updates rather than duplicates. This matters most for recurring extraction jobs that refresh data on a schedule. For the broader ingestion pattern that combines crawl, scrape, and extract into one pipeline, see converting a website to LLM-ready data.

Self-host the same engine for $0

The extraction engine is the same single AGPL-3.0 Rust binary whether you call the managed cloud or run it yourself. Self-hosting costs nothing in license or credits — you pay only for your own server — and because the API is Firecrawl-compatible, the exact jsonSchema request above works against your local instance after a base-URL swap. If extraction volume is high or the data is sensitive enough that it should never leave your infrastructure, self-host; if you want a hands-off path, use the credits. Either way the schema and the code are identical.

Sources

  • fastCRW canonical fact sheet — credit costs, API surface and formats: ["json"], provider and batch-extract limits. Internal to the fastCRW team.
  • Scrape benchmark of record: diagnose_3way.py on Firecrawl's public labeled dataset, 819 labeled URLs, 2026-05-08 (truth-recall 63.74%).
  • Open-core endpoint reference: github.com/us/crw · managed cloud: fastcrw.com

Related: Structured extraction with JSON Schema · The /v1/extract endpoint deep dive · List crawling for structured data · Convert a website to LLM-ready data

FAQ

Frequently asked questions

How do I extract structured JSON from a website?
Define a jsonSchema for the fields you want, then POST to /v1/scrape with formats: ["json"] and that schema plus the target URL. fastCRW renders and cleans the page, then uses an LLM to fill the schema and returns a typed JSON object. It is about 10 lines of code with no separate parsing service or CSS selectors to maintain.
What does JSON extraction cost in credits?
Any request with formats: ["json"] costs the 1-credit scrape plus the LLM token cost, billed as usage-metered LLM credits — more than a plain scrape (a flat 1 credit on any renderer) because you are paying for an LLM extraction pass on top of the fetch and clean, and how much more scales with page size and token usage. The managed /v1/extract wrapper is billed the same way. Per-plan credit allowances are on the fastCRW pricing page.
Can fastCRW extract JSON from many URLs in one call?
No. There is no batched multi-URL extract endpoint — no /v1/batch/scrape — and /v1/extract is single-URL. To extract from a list, iterate /v1/scrape concurrently with bounded concurrency, or crawl the site first with /v1/crawl and then run a per-page extraction. You compose the loop yourself, which keeps retries and error handling under your control.
Which LLM providers does fastCRW JSON extraction support?
jsonSchema extraction runs on fastCRW's managed LLM. There is no key, provider, or model to configure, and no way to point the managed cloud at your own model. The path is available on paid plans only; the Free plan returns HTTP 402. Managed /v1/search answer mode runs on the same managed LLM.
What is the difference between /v1/scrape with json and /v1/extract?
/v1/extract is a managed-cloud convenience wrapper over /v1/scrape with formats: ["json"] — same cost (the 1-credit scrape plus the LLM token cost), same engine, single-URL. Self-hosters skip it and call /v1/scrape + jsonSchema directly. There is no behavior in /v1/extract you cannot reproduce with a scrape call; it exists for parity with the Firecrawl API surface.

Get Started

Try fastCRW free

Run a live request in the playground — no signup required. Or grab a free API key with 500 credits, no credit card.

Continue exploring

More tutorial posts

View category archive