/api/v1/extractExtract
Extract structured data from raw HTML you already have. Same service as /api/v1/scrape minus the fetch step. An API key is required — there is no keyless sample path here, and the key is checked before the request body is parsed.
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| html | string | Required | The raw HTML to extract from. Keep the whole request body under 4.5 MB: the hosting platform refuses a larger body with a plain-text HTTP 413 before Contrie reads it. Contrie's own limit is 5,000,000 UTF-8 bytes, and it reads at most the first 100,000 characters of the HTML's markdown; metadata.evidenceCoverage.sourceTruncated is true when it cut. |
| url | string | Optional | Source URL, used as context and to resolve relative links. Not fetched. |
| extract | string | Optional | Natural language description of what to extract. Max 4,000 characters. |
| schema | object | Optional | JSON Schema subset to enforce the output shape. Same rules as /api/v1/scrape. Max 10 KB. |
| format | string | Optional | json (default), markdown, or both. |
Safe retries
Authenticated JSON requests support the same optional Idempotency-Key contract as Scrape: 8–200 visible ASCII characters, one account and input identity, and an encrypted response replayed for 24 hours with no new inference or credits. A changed request, an expired response or work still in progress returns HTTP 409. Use a new key only for deliberately new work, as in Scrape's example. Streaming requests do not accept this header.
Request Example
curl -X POST https://www.contrie.com/api/v1/extract \
-H "Content-Type: application/json" \
-H "Authorization: Bearer ck_live_your_key_here" \
-d '{
"html": "<html><body><h1>Hello World</h1><p>Price: $29.99</p></body></html>",
"extract": "Get the heading and price",
"url": "https://example.com/product"
}'Response
Same response shape as /api/v1/scrape, including the full metadata object and trace array contains only high-level request progress. That includes metadata.groundingFields, the per-value grounding receipts behind grounding — see Scrape for the full field shape. The scores in this abridged example are what the acceptance checks compute for this answer on this HTML: a natural-language request scores at most 80, because without a schema the requested fields are not counted. The receipt names the source as provided_html: Contrie did not fetch it. Accepted model answers from current deployments also carry metadata.binding: here the price was judged against the passages about it and none stated a different value. A conflict path marks a field as unconfirmed; see Scrape.
{
"success": true,
"data": {
"heading": "Hello World",
"price": "$29.99"
},
"metadata": {
"url": "https://example.com/product",
"qualityScore": 80,
"qualityScoreKind": "structural_and_textual",
"valid": true,
"coverageMeasured": false,
"completeness": 1,
"grounding": 1,
"latencyMs": 1820,
"trace": [
{ "stage": "loading", "detail": "Loading source" },
{ "stage": "processing", "detail": "Processing request" },
{ "stage": "complete", "detail": "Request complete" }
],
"groundingCoverage": { "total": 2, "checkable": 2, "grounded": 2 },
"binding": { "judged": 1, "conflicts": [], "truncated": false },
"source": { "mode": "provided_html", "url": "https://example.com/product" },
"cached": false,
"credits": 1
}
}Streaming
Same as /api/v1/scrape: send Accept: application/x-ndjson for high-level request progress. See Streaming.
When to Use Extract vs Scrape
| Use Case | Endpoint |
|---|---|
| You have a URL and want data from it | /api/v1/scrape |
| You already fetched the HTML yourself | /api/v1/extract |
| You need custom fetch headers or auth cookies | /api/v1/extract |
| The page is a JavaScript-only shell (server HTML has no content) | /api/v1/scrape (renders by default), or render it yourself and use /api/v1/extract |
| You want a single endpoint that handles everything | /api/v1/scrape |
/api/v1/scrape renders a JavaScript-only page in a browser by default (render: "auto", 2 extra credits when the rendered answer is accepted). Send HTML here instead when you need your own browser session, cookies or interactions, or when scrape returns RENDER_REQUIRED (see Error Codes).