How to extract JSON-LD structured data from websites

JSON-LD, structured data, Web Scraper Cloud, web scraping, product data

To extract JSON-LD structured data from a website, find its script[type="application/ld+json"] elements and collect their contents. In Web Scraper, an HTML selector captures these blocks. Web Scraper Cloud can then isolate simple fields from consistent markup and automate repeat collection.

For product research or price monitoring, first check that the markup describes the product and offer you actually need. A neatly structured block can still contain a default variant, a price range or unrelated entities.


1. Find the JSON-LD that describes your target

JSON-LD is a JSON-based format for linked data. Websites often use Schema.org vocabulary to describe products, jobs, organisations and articles. In HTML, JSON-LD can appear in script elements in the head or body, and JavaScript can insert it after the page loads.

Open a representative product page and its browser Developer Tools. In Elements, search for application/ld+json and inspect each matching script.

Look for the intended product's SKU, URL or name. The first block might describe the store or breadcrumb navigation. Even "@type": "Product" is insufficient on its own if the page also includes recommendations.

Three properties help you understand the structure:

  • @context establishes how terms are interpreted.
  • @type identifies an entity's type.
  • @id identifies an entity and can connect references to it elsewhere in the data.

Compare the block in Elements with View Page Source or the main document response in Network. This helps establish whether it arrived in the initial HTML or appeared after rendering.

If the required fields are absent, use the guide to finding where a website gets its data to investigate other sources.

For this walkthrough, one output row represents one product detail page containing one product and one offer.

2. Extract JSON-LD structured data with an HTML selector

In the Web Scraper extension, open the Web Scraper tab in Developer Tools, select Create sitemap, and enter a name and the product page's URL. The Advanced Sitemap Builder guide covers this setup.

Add the following selector:

SettingValue
IDjsonld_raw
TypeHTML
Parent selector_root
Selectorscript[type="application/ld+json"]
MultipleEnabled initially to inspect every matching block

Enter the CSS selector manually because the script is not a visible page element you can click.

The HTML selector returns the selected element's inner content. Applied to a JSON-LD script, it captures the JSON without the surrounding script tags. Use HTML here: the Text selector ignores script contents.

Run a small scrape and inspect the raw values. Several matching scripts produce block-level output; objects inside an array or @graph remain inside their original block.

For the single-product workflow, narrow the selector to the intended script using a stable ID or attribute found on the website. For example:

script#product-schema[type="application/ld+json"]

This works only if the target script actually has id="product-schema". It is an illustrative ID, not a standard JSON-LD attribute.

Once the selector consistently matches exactly one intended block, disable Multiple. Disabling it on the broad selector would simply select the first match in document order.

If no stable selector isolates the relevant block, keep the blocks separate for inspection rather than assuming the first one is correct.

Put extraction under the correct parent

When starting from category pages, use a Link selector to open product detail pages and place jsonld_raw beneath it.

A child of a product-card Element selector searches within that card. It could miss a script in the document head. Use the detail-page context, or start directly from product detail URLs.

3. Turn a simple product block into separate columns

The following synthetic example represents the contents of one product script:

{
  "@context": "https://schema.org",
  "@type": "Product",
  "name": "Everyday shoulder bag",
  "sku": "BAG-24",
  "brand": {
    "@type": "Brand",
    "name": "Example Goods"
  },
  "offers": {
    "@type": "Offer",
    "price": "49.90",
    "priceCurrency": "USD",
    "availability": "https://schema.org/InStock"
  }
}

The recipe below assumes one product, one offer and exactly one occurrence of each property being extracted. It uses text matching for a known template; it does not interpret JSON-LD relationships.

Test raw extraction locally, import the sitemap into Cloud, and run a representative sample.

Then create the output fields:

  1. Open the sitemap's Parser tab and select + Add column.
  2. Name the Virtual column sku and choose jsonld_raw as its source.
  3. Save it and add a Regex match parser to that column.
  4. Enter the SKU expression below, select capture Group 1, and leave the parser's Multiple option disabled.
  5. Repeat for price and currency, using jsonld_raw as the source each time.
Output columnRegex expressionExample result
sku"sku"\s*:\s*"([A-Z0-9-]+)"BAG-24
price"price"\s*:\s*"([0-9]+(?:\.[0-9]+)?)"49.90
currency"priceCurrency"\s*:\s*"([A-Z]{3})"USD

Enter expressions without surrounding / characters. These patterns deliberately accept uppercase letters, digits and hyphens in the SKU, a quoted non-negative decimal price, and a three-letter uppercase currency code. An unquoted numeric price or a differently formatted SKU needs a separately tested rule.

The Regex match parser returns matching text. These expressions do not validate JSON, follow object paths or decode arbitrary escaped strings. CSS cannot select JSON keys either: script[type="application/ld+json"] .price looks for an HTML descendant, not a property inside the JSON text.

Keep jsonld_raw during validation. Virtual columns independently receive the raw source value, so deriving price does not remove the source needed for currency. Apply any further cleaning to the relevant Virtual column.

For the product name, a Text selector targeting the visible heading may be simpler. The example contains two name properties, belonging to the product and its brand. A broad name pattern cannot establish which entity owns the value.

4. Handle multiple entities, offers and variants

One script does not necessarily describe one product. JSON-LD supports arrays, graphs, nested objects and references. A product's offer might be embedded directly or referenced through an @id whose details appear elsewhere.

Source shapeWhat to check
Several products or an @graph in one blockKeep each field attached to the intended entity.
Several offers for a productIdentify the required seller, condition and offer.
AggregateOfferlowPrice and highPrice describe a range across offers.
ProductGroup and variantsKeep each variant's identifier with its corresponding offer.

Schema.org distinguishes aggregate offers from individual offers, and Google's variant examples show how related products can appear together. A lowest advertised price should not silently become a selected variant's price.

For these structures, extract the required fields from suitable page elements with Web Scraper, or preserve raw blocks for a separate JSON-aware processing step. Enabling Multiple in Regex match joins matching text values; it does not create related product rows. Joining every SKU and every price into two lists loses their relationships when values are missing.

5. Validate the source and derived fields together

Test contrasting pages: a normal product, a sale item, an unavailable item, a variant product and a page with an optional field missing.

Compare the raw block, derived fields and visible page in the same region and selected product state. If changing a size updates the displayed price but leaves JSON-LD unchanged, that block is unsuitable for tracking the selected size's price.

Google expects structured data to reflect the page accurately. This is a publishing requirement, not proof that every website's markup is current.

Use the failure location to guide the fix:

SymptomFirst check
jsonld_raw is emptyDoes the intended page contain the script in the extraction state, and is the parent context correct?
Raw JSON is present but price is emptyDoes the source use an unquoted number, another property or a different format?
A field is populated with the wrong valueDoes the key occur more than once or belong to another entity?

Keep missing prices distinct from zero. Retain the source page URL and a stable product identifier. Cloud's Parser also offers + Add time scraped for the collection timestamp.

Check that the output contains the expected product records, rather than merely counting captured script blocks. Inspect a downloaded sample as well as Parser preview. The preview can abbreviate long values and may omit unusual records.

6. Automate the verified sitemap and preserve the raw data

Choose the Cloud driver according to both extraction and navigation:

  • Fast reads returned HTML without executing page JavaScript.
  • FullJS executes JavaScript and supports workflows that depend on rendering or interactions.

A JSON-LD script already present in the response does not itself need JavaScript execution. However, discovering the product links might still require it. Test the intended driver and settings before scheduling recurring jobs.

Choose the export format carefully when retaining raw blocks. XLSX cells are limited to 32,767 characters, with longer content truncated. CSV supports multiline fields; Cloud's JSON output is newline-delimited JSON. Exporting JSON does not automatically expand the JSON-LD inside jsonld_raw into separate product columns. Use a format-aware reader for multiline CSV fields or escaped JSON strings.

Once the downloaded output is correct, combine the Cloud scheduler with automatic export for recurring delivery. Recheck the fields after changing selectors or Parser rules.


Go back to blog page