CrawlVolt
<- Field Notes
Guide / Structured extraction

Extract typed JSON from a web page.

Choose CSS selectors for a name, price, availability and link. Validate the result and catch missing fields before they reach your application.

Use fields that actually exist.

CrawlVolt's structured extraction evaluates CSS selectors against rendered HTML. It converts matched values into declared types; it does not ask a language model to infer missing data. Choose this mode when your application needs a predictable object instead of an entire Markdown document.

Open the product demonstration page. It contains a fictional notebook priced at 12.50 EUR, a boolean availability attribute and a relative link. There is no checkout or real inventory. You can download its HTML to inspect the selectors.

Create a CrawlVolt API key. Give it a name for this project and copy the secret when it appears. It is shown once.

Already registered? Sign in and continue to API keys. Keep the secret in your local environment or credential store.

Extract the demonstration product.

With Node.js 24, save extract_product.mjs and page_to_markdown.mjs in the same folder. The second file supplies the shared request helper.

Terminal
export CRAWLVOLT_API_KEY="your_api_key"
node extract_product.mjs https://www.crawlvolt.com/examples/product-demo.html

The script prints the validated data object. For the supplied fixture, the expected object is:

JSON
{
  "name": "Sample notebook",
  "price": 12.5,
  "currency": "EUR",
  "in_stock": true,
  "details_url": "https://www.crawlvolt.com/blog/extract-structured-json"
}

This is a fixture expectation, not a measurement from a third-party store. Compare the values against the page and inspect the full response in Activity when debugging.

Declare selectors, sources and types.

The name and price use element text. Currency, availability and the link use attributes. type: "url" resolves the relative link against the final page URL. Required fields make missing data visible.

Node.js · extract_product.mjs
import { pathToFileURL } from 'node:url';
import { request } from './page_to_markdown.mjs';

export const productSchema = {
  fields: {
    name: { selector: 'main h1', required: true },
    price: { selector: '[itemprop=price]', type: 'number', required: true },
    currency: { selector: '[itemprop=priceCurrency]', source: 'attribute', attribute: 'content', required: true },
    in_stock: { selector: '[data-available]', source: 'attribute', attribute: 'data-available', type: 'boolean', required: true },
    details_url: { selector: 'a[data-details]', source: 'attribute', attribute: 'href', type: 'url', required: true },
  },
};

export function requireProduct(result) {
  const structured = result?.outputs?.structured;
  if (structured?.valid !== true) {
    throw new Error(`Extraction failed validation: ${JSON.stringify(structured?.errors ?? [])}`);
  }
  const data = structured.data;
  if (typeof data?.name !== 'string' || !data.name.trim() ||
      typeof data.price !== 'number' || !Number.isFinite(data.price) ||
      typeof data.currency !== 'string' || typeof data.in_stock !== 'boolean' ||
      typeof data.details_url !== 'string') {
    throw new Error('Unexpected product types. Inspect outputs.structured.');
  }
  return data;
}

if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
  try {
    const url = process.argv[2] || 'https://www.crawlvolt.com/examples/product-demo.html';
    const result = await request('scrape', { url, formats: ['structured'], extract: productSchema });
    console.log(JSON.stringify(requireProduct(result), null, 2));
  } catch (error) {
    console.error(error.message);
    process.exitCode = 1;
  }
}

The API returns validation details under outputs.structured. Its valid flag must be true before this example accepts the data, and the application checks the returned JavaScript types again. HTTP 200 alone is not sufficient.

Make a required field disappear.

In your local script, change the price selector from [itemprop=price] to [data-missing-price], then run the same command. The fixture has no matching element, so the structured result should be invalid with a required_missing error for the price field. The script exits with an error instead of treating the price as zero.

Restore the selector before continuing. If the selected value exists but cannot be converted to a number, the API reports type_conversion_failed. Optional missing fields can leave valid true while reducing confidence.

Here, confidence is the fraction of schema fields that produced correctly typed values. It is not a probability that a price is current or that the page is trustworthy. Your application still needs business checks, such as the expected currency and an acceptable price range.

Adapt the schema to a real page.

Inspect a public page you may collect and replace each selector with a stable attribute or semantic element from that page. Keep the first version small and test both a complete page and one missing a required field. Do not reuse the demo's selectors and assume every store has the same HTML.

If fields appear only after interaction, use the same extraction schema with Browse and an explicit wait. See the structured extraction reference for multiple matches, supported types, presets and limits.