How to Extract JSON-LD Structured Data From Any Website

Published July 2026 · 7 min read

JSON-LD is the invisible gold mine of the modern web. Every e-commerce product page, every news article, every recipe blog, and every business listing has structured data baked into its HTML — and most developers ignore it completely.

In this guide, I'll show you how to extract JSON-LD from any URL, what you can do with it, and why it's the fastest path from "I need website data" to "I have clean structured JSON."

In this article

  1. What is JSON-LD and where is it hiding?
  2. Why extract JSON-LD instead of parsing HTML?
  3. Manual extraction with browser DevTools
  4. Programmatic extraction with Python + Playwright
  5. Using a web scraping API (the easy way)
  6. Real-world examples: what JSON-LD looks like in the wild
  7. Common pitfalls and how to avoid them

What is JSON-LD and where is it hiding?

JSON-LD (JavaScript Object Notation for Linked Data) is a W3C standard for embedding structured data inside HTML pages. It looks like this:

<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "Product",
  "name": "Wireless Headphones Pro",
  "description": "Noise-canceling wireless headphones",
  "brand": { "@type": "Brand", "name": "AudioTech" },
  "offers": {
    "@type": "Offer",
    "price": "129.99",
    "priceCurrency": "USD",
    "availability": "https://schema.org/InStock"
  },
  "aggregateRating": {
    "@type": "AggregateRating",
    "ratingValue": "4.7",
    "reviewCount": "2,341"
  }
}
</script>

This is already structured data. No regex. No CSS selectors. No guessing which div contains the price. The website owner (or their CMS/SEO plugin) already formatted it for you.

JSON-LD powers Google's rich results — those product cards, recipe cards, FAQ accordions, and review stars you see in search results. According to BuiltWith (2026), over 68% of the top 100,000 websites use JSON-LD, and adoption grows every year.

Why extract JSON-LD instead of parsing HTML?

HTML parsing for structured data is brittle. You write a CSS selector for .product-price, the site redesigns, your scraper breaks. JSON-LD is different:

Manual extraction with browser DevTools

For one-off research, open any product page and run this in the browser console:

// Extract all JSON-LD blocks from the current page
const scripts = document.querySelectorAll('script[type="application/ld+json"]');
const jsonld = Array.from(scripts).map(s => JSON.parse(s.textContent));
console.log(JSON.stringify(jsonld, null, 2));

This works on static pages but fails on JavaScript-rendered sites where JSON-LD is injected after page load. For those, you need browser automation.

Programmatic extraction with Python + Playwright

For automated extraction at scale, Playwright (or Puppeteer) gives you a real browser environment:

from playwright.sync_api import sync_playwright

def extract_jsonld(url):
    with sync_playwright() as p:
        browser = p.chromium.launch()
        page = browser.new_page()
        page.goto(url, wait_until='networkidle')

        jsonld = page.evaluate("""() => {
            const scripts = document.querySelectorAll(
              'script[type="application/ld+json"]'
            );
            return Array.from(scripts).map(s => {
                try { return JSON.parse(s.textContent); }
                catch (e) { return null; }
            }).filter(Boolean);
        }""")

        browser.close()
        return jsonld

# Usage
data = extract_jsonld('https://example.com/product/123')
for block in data:
    print(f"{block['@type']}: {block.get('name', 'unnamed')}")
⚠️ Production warning: Running Chromium at scale means managing browser instances, memory leaks, proxies, and rate limiting. For more than a few dozen URLs, use a dedicated scraping API or queue system.

Using a web scraping API (the easy way)

ExtractAPI automatically extracts all JSON-LD blocks from any URL, along with page metadata, headings, text content, images, and links — in one API call:

curl -X POST https://extractapi.app/v1/extract \
  -H "Authorization: Bearer ***" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://example.com/product/123"}'

The response includes a jsonld array with every structured data block on the page:

{
  "url": "https://example.com/product/123",
  "data": {
    "title": "Wireless Headphones Pro — AudioTech",
    "jsonld": [
      {
        "@type": "Product",
        "name": "Wireless Headphones Pro",
        "offers": { "price": "129.99", "priceCurrency": "USD" },
        "aggregateRating": { "ratingValue": "4.7", "reviewCount": 2341 }
      },
      {
        "@type": "BreadcrumbList",
        "itemListElement": [ /* breadcrumb items */ ]
      }
    ],
    "headings": { "h1": ["Wireless Headphones Pro"] },
    "text": "Noise-canceling wireless headphones with 40-hour battery life..."
  }
}

No browser management, no proxy rotation, no HTML parsing. One request, all the structured data.

Try ExtractAPI — Plans from $9/month

Real-world examples: what JSON-LD looks like in the wild

E-commerce product (Shopify stores, Amazon, Best Buy)

{
  "@type": "Product",
  "name": "MacBook Pro 16\"",
  "sku": "MBP16-M3-2026",
  "brand": { "@type": "Brand", "name": "Apple" },
  "offers": {
    "@type": "Offer",
    "price": "2499.00",
    "priceCurrency": "USD",
    "availability": "https://schema.org/InStock",
    "priceValidUntil": "2026-12-31"
  },
  "aggregateRating": {
    "@type": "AggregateRating",
    "ratingValue": "4.8",
    "reviewCount": "1,247"
  }
}

Recipe (food blogs, AllRecipes, NYT Cooking)

{
  "@type": "Recipe",
  "name": "Sourdough Bread",
  "prepTime": "PT30M",
  "cookTime": "PT45M",
  "totalTime": "PT15H",
  "recipeYield": "1 loaf",
  "recipeIngredient": [
    "500g bread flour",
    "350g water",
    "100g sourdough starter",
    "10g salt"
  ],
  "nutrition": {
    "@type": "NutritionInformation",
    "calories": "180 calories per slice"
  }
}

Article (news sites, blogs, Medium)

{
  "@type": "Article",
  "headline": "ExtractAPI Launches Web Scraping API From $9/month",
  "author": { "@type": "Person", "name": "Adam" },
  "datePublished": "2026-07-22",
  "publisher": { "@type": "Organization", "name": "ExtractAPI" }
}

FAQ (SaaS landing pages, documentation)

{
  "@type": "FAQPage",
  "mainEntity": [
    {
      "@type": "Question",
      "name": "What is JSON-LD?",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "JSON-LD is a method of encoding Linked Data using JSON..."
      }
    }
  ]
}

Local Business

{
  "@type": "LocalBusiness",
  "name": "Greenhouse Coffee",
  "address": {
    "@type": "PostalAddress",
    "streetAddress": "123 Main St",
    "addressLocality": "Princeton",
    "addressRegion": "NJ",
    "postalCode": "08540"
  },
  "telephone": "+1-609-555-0123",
  "openingHoursSpecification": [
    { "@type": "OpeningHoursSpecification", "dayOfWeek": "Monday", "opens": "07:00", "closes": "18:00" }
  ],
  "geo": { "@type": "GeoCoordinates", "latitude": "40.3573", "longitude": "-74.6672" }
}

Common pitfalls and how to avoid them

1. JavaScript-rendered JSON-LD

Many modern SPAs (React, Vue, Next.js) inject JSON-LD after the initial HTML load. If you're using a simple HTTP client (like requests or curl), you'll miss it. Use a browser-based approach — Playwright, Puppeteer, or a web scraping API that renders JavaScript.

2. Multiple JSON-LD blocks

Pages often have multiple JSON-LD blocks: one for the Product schema, one for BreadcrumbList, one for Organization. Don't assume the first block is the one you want — iterate through all of them.

3. Invalid or malformed JSON

Not all JSON-LD is valid JSON. A misplaced comma, unescaped quote, or broken template tag can make JSON.parse() throw. Always wrap your extraction in try/catch, and consider using a JSON repair library for production scraping.

4. Undocumented schema extensions

Some sites extend Schema.org with custom properties (e.g., Shopify's @type: "Product" often includes non-standard fields like itemCondition or category). Don't assume every field exists — check with optional chaining: offer?.price.

5. Rate limiting and blocking

Hitting the same domain too fast will get you blocked. Use a scraping API with built-in rate limiting per API key (ExtractAPI does per-key rate limiting, so one customer can't affect your entire account).

When JSON-LD beats CSS selectors

I've used both approaches extensively. CSS selectors work until the site changes a class name. JSON-LD works until the site stops using Schema.org — which almost never happens because it would tank their SEO. For e-commerce data, structured content, and business listings, JSON-LD extraction is the most reliable approach available today.

But you need a real browser to render JavaScript sites, a way to handle malformed JSON, and a system that doesn't fall over at scale. That's why we built ExtractAPI.

Start extracting JSON-LD — Free test with any plan

Read next: Web Scraping API Pricing Compared (2026) · ExtractAPI vs ScrapingBee — Honest Comparison