# Schema Markup Extractor — JSON-LD, Microdata, Open Graph (`nexgensignal/schema-markup-extractor`) Actor

Read the structured data on any pages or whole sites: JSON-LD, Microdata, RDFa, Open Graph, Twitter cards, Dublin Core. One row per page with every schema type and checks for broken JSON-LD, missing required properties and tags. Part of NexGen Signal — data tools and official-source data products

- **URL**: https://apify.com/nexgensignal/schema-markup-extractor.md
- **Developed by:** [NexGen Signal](https://apify.com/nexgensignal) (community)
- **Categories:** SEO tools, Automation, Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $33.50 / 1,000 page reads

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## 🧩 Schema Markup Extractor — JSON-LD, Microdata, Open Graph

Give a list of page links (or turn on sitemaps to cover whole sites) and get **every piece of structured data each page publishes**, one row per page: JSON-LD, Microdata, RDFa, Open Graph, Twitter / X card tags, Microformats and Dublin Core, plus the title, meta description, canonical link and language.

Each row lists every schema type found on the page (nested types included, such as the Offer inside a Product), and checks for common mistakes: JSON-LD blocks that are broken or not strict JSON, items with no `@context` or `@type`, schema items missing a property that Google's rich-result guides list as required (Product, Offer, BreadcrumbList, FAQPage, Event, JobPosting, Recipe, HowTo, VideoObject, LocalBusiness, Review, AggregateRating, SoftwareApplication, Course, Dataset, Article), pages with no structured data at all, Open Graph missing one of its four required tags (`og:title`, `og:type`, `og:image`, `og:url`, as set out at ogp.me), and pages with no `twitter:card`.

Give page links, read a whole site from its sitemap, or follow links from your pages up to a chosen depth.

The unit of output is one page read. Pages that answer with an error, links that are not HTML pages, and pages robots.txt disallows are not billed.

### Who buys this and for what job

- **SEO teams** auditing rich-result markup across a site, or checking competitors' schema types.
- **E-commerce teams** pulling Product, Offer and Review data that shops publish in JSON-LD.
- **Developers** checking social share tags and structured data before a release.
- **Data teams** collecting the structured facts pages publish about themselves.

Buyers usually search for this as **"schema markup extractor"**, **"JSON-LD scraper"** or **"structured data extractor"**.

### 📊 Sample Output

![Table of pages: URL, schema types found, JSON-LD count, Open Graph tags and checks.](https://api.apify.com/v2/key-value-stores/IXCaMKjxSmUTLHhmq/records/schema-markup-extractor.png)

| url | schema_types | json_ld_count | opengraph_tags | checks |
|---|---|---|---|---|
| https://www.usa.gov/ | WebSite, Organization | 2 | 7 | no twitter:card tag |
| https://www.nasa.gov/image-of-the-day/ | Organization, WebSite, ImageObject, WebPage, Person, Article | 1 | 14 | none |
| https://www.federalreserve.gov/ | — | 0 | 6 | no structured data found (json-ld) |

Rows from live run `eMQIozuhXHrruMiQp` on Apify (JSON-LD, Open Graph and Twitter cards only, from three US government home pages). Notice the Federal Reserve home page: it publishes Open Graph tags but no JSON-LD, which the checks report.

### ✅ What you get

Every field of each record:

- `record_id`, `url`, `final_url`, `status_code`, `found_via` — the page, where it was served from, its status, and whether it came from your list or a sitemap.
- `title`, `meta_description`, `canonical`, `lang` — the page's basic tags.
- `has_structured_data` — true when any JSON-LD, Microdata or RDFa item was found.
- `schema_types` — every schema type found in JSON-LD, Microdata and RDFa, in page order.
- `json_ld`, `microdata`, `rdfa` — the items themselves (Microdata and RDFa in JSON-LD form), with counts in `json_ld_count`, `microdata_count`, `rdfa_count`.
- `opengraph`, `twitter_card`, `microformats`, `dublincore` — social and other meta tags as name → value (a repeated tag becomes a list).
- `json_ld_errors`, `checks`, `check_count` — problems found on the page.
- `read_at` — when the page was read (UTC).

### ⚙️ Sample inputs

**Two pages (the Store example)**

```json
{
  "urls": ["https://www.nasa.gov/", "https://www.usa.gov/"],
  "maxPages": 10
}
```

All formats.

**A whole site from its sitemap**

```json
{
  "urls": ["https://www.nasa.gov/"],
  "useSitemaps": true,
  "maxPages": 500
}
```

Reads the pages the sitemap lists, same host only.

**Follow links from a page**

```json
{
  "urls": ["https://www.usa.gov/"],
  "followLinks": true,
  "maxDepth": 2,
  "maxPages": 200
}
```

Reads the pages it links to (same host), two clicks deep.

**Social and JSON-LD tags only**

```json
{
  "urls": ["https://www.usa.gov/", "https://www.federalreserve.gov/"],
  "syntaxes": ["json-ld", "opengraph", "twitter"],
  "maxPages": 100
}
```

Faster rows with only those formats and their checks.

Input fields:

| Field | Meaning |
|---|---|
| `urls` | pages to read (up to 10,000). |
| `syntaxes` | json-ld, microdata, rdfa, opengraph, twitter, microformat, dublincore. Empty = all. |
| `useSitemaps` | also read the pages listed in each site's sitemap (default off). |
| `followLinks`, `maxDepth` | also read same-site pages your pages link to, this many clicks deep (default off, depth 3). |
| `maxPages` | stop after this many pages are delivered (default 1,000). Each delivered page is billed. |

### 🧾 JSON sample record

```json
{
  "record_id": "66cf5a759142bc2188ee8d5a",
  "url": "https://www.usa.gov/",
  "final_url": "https://www.usa.gov/",
  "status_code": 200,
  "found_via": "given",
  "title": "Making government services easier to find | USAGov",
  "meta_description": "Find government benefits, services, agencies, and information at USA.gov. Contact elected officials. Learn about passports, Social Security, taxes, and more.",
  "canonical": "https://www.usa.gov/",
  "lang": "en",
  "has_structured_data": true,
  "schema_types": [
    "WebSite",
    "Organization"
  ],
  "json_ld_count": 2,
  "microdata_count": 0,
  "rdfa_count": 0,
  "json_ld": [
    {
      "@context": "https://schema.org",
      "@type": "WebSite",
      "name": "USA.gov",
      "url": "https://usa.gov/"
    },
    {
      "@context": "https://schema.org",
      "@type": "Organization",
      "url": "https://usa.gov/",
      "logo": "https://www.usa.gov/themes/custom/usagov/images/Logo_USAGov.png"
    }
  ],
  "microdata": [],
  "rdfa": [],
  "opengraph": {
    "og:url": "https://www.usa.gov/",
    "og:type": "website",
    "og:title": "Making government services easier to find | USAGov",
    "og:description": "Find government benefits, services, agencies, and information at USA.gov. Contact elected officials. Learn about passports, Social Security, taxes, and more.",
    "og:image": "https://www.usa.gov/themes/custom/usagov/images/Logo_USAGov.png",
    "og:image:secure_url": "https://www.usa.gov/themes/custom/usagov/images/Logo_USAGov.png",
    "fb:pages": "65369158579"
  },
  "twitter_card": null,
  "microformats": null,
  "dublincore": null,
  "json_ld_errors": [],
  "checks": [
    "no twitter:card tag"
  ],
  "check_count": 1,
  "read_at": "2026-10-18T00:06:51Z"
}
```

### 🔧 How it works

Pages are read 5 at a time. JSON-LD blocks are parsed one by one, so a broken block is reported instead of silently dropped; a block with a trailing comma is still read and flagged. Microdata, RDFa, Microformats and Dublin Core are read with the open extruct library. RDFa is cleaned so that only real vocabulary data is kept: Open Graph tags (which have their own field), XHTML role attributes and WordPress `api.w.org` links are left out.

Every run reads each host's robots.txt first: a path it disallows is skipped, listed in the run receipt and never charged. Only public internet addresses are fetched (no private, loopback or cloud-metadata addresses, checked again on every redirect). No logins, no CAPTCHA solving, no proxies.

Delivery is pushed first and charged after. The run receipt (key-value store record `RUN_RECEIPT`) lists every page with its outcome, the schema types and checks found across the run with counts, the robots.txt result per host, the sitemaps read, and the delivered and charged counts.

### 💰 Pricing example

Per page delivered, no start fee, no monthly charge:

| Apify plan | Price per page |
|---|---|
| Free | $0.05 |
| Bronze | $0.045 |
| Silver | $0.04 |
| Gold, Platinum, Diamond | $0.0335 |

- 10 pages: $0.50 on the Free plan, $0.34 on Gold.
- 1,000 pages: $50.00 on the Free plan, $33.50 on Gold.
- 10,000 pages: $500.00 on the Free plan, $335.00 on Gold.

**Coverage and size.** Proof runs on 17 Oct 2026: 40 NASA pages from its sitemap in about 61 seconds (Organization, WebSite, WebPage, ImageObject, BlogPosting, Person and VideoObject found); 8 usa.gov pages by following links in 73 seconds (usa.gov asks for a 10-second gap between requests, which is respected); the two-page Store example in about 3 seconds. It reads the HTML the server sends; markup added later by JavaScript is not seen.

### ⚖️ Legal & ToS

Pages belong to their owners. You choose the links. Make sure you have the right to download and use the content you point it at; the actor fetches only what you give it (and, where you turn it on, what those pages link to).

The rows hold the markup each page publishes about itself; the actor adds nothing.

Every run reads each host's robots.txt first: a path it disallows is skipped, listed in the run receipt and never charged. Only public internet addresses are fetched (no private, loopback or cloud-metadata addresses, checked again on every redirect). No logins, no CAPTCHA solving, no proxies.

### ❓ FAQ

**Does it validate against Google's rich-result rules?**
It checks the properties Google's guides list as required for the common types (missing `offers` on a Product, missing `startDate` on an Event, and so on). Recommended properties and Google's eligibility rules are not checked; use Google's Rich Results Test for the final word.

**Does it run JavaScript?**
No. Markup inserted by scripts after the page loads is not seen.

**Is a page with no structured data billed?**
Yes, if it was read: the row (with the 'no structured data found' check) is the answer. Error pages and non-HTML links are not billed.

### 🆘 Troubleshooting

- **A page is missing from the results** — RUN_RECEIPT shows why: robots.txt, an HTTP error, not HTML, or unreachable.
- **Sitemap added no pages** — The site may have no sitemap in robots.txt or at /sitemap.xml, or its sitemap lists another host.
- **SOURCE UNAVAILABLE** — None of your links could be reached after retries. Nothing was charged.

### 🔗 Related Actors

- [Website Performance Audit](https://apify.com/nexgensignal/website-performance-audit-api) — Lighthouse scores and web vitals per page
- [Website Tech Stack Detector](https://apify.com/nexgensignal/website-tech-stack-api) — what a site is built with
- [Website Contact Scraper](https://apify.com/nexgensignal/bulk-website-contact-extractor) — contact details from website lists

🏢 **About NexGen Signal** — data tools and official-source data products. Browse the catalog: [apify.com/nexgensignal](https://apify.com/nexgensignal)

### ⭐ Found this useful?

If this actor saved you time, a rating on its Apify Store page helps other buyers find it.

Part of NexGen Signal — data tools and official-source data products.

# Actor input Schema

## `urls` (type: `array`):

Pages to read. Up to 10,000 per run.

## `syntaxes` (type: `array`):

Empty = all formats.

## `useSitemaps` (type: `boolean`):

For each site in your list, also read pages listed in its sitemap (from robots.txt, or /sitemap.xml), same host only, up to maxPages.

## `followLinks` (type: `boolean`):

Also read the pages your pages link to (same host), up to maxDepth clicks away and maxPages in all.

## `maxDepth` (type: `integer`):

With followLinks: how many clicks away from your pages to go.

## `maxPages` (type: `integer`):

Stop after this many pages are delivered. Each delivered page is billed; error pages, non-HTML links and pages skipped by robots.txt are not.

## Actor input object example

```json
{
  "urls": [
    "https://www.nasa.gov/",
    "https://www.usa.gov/"
  ],
  "syntaxes": [],
  "useSitemaps": false,
  "followLinks": false,
  "maxDepth": 3,
  "maxPages": 10
}
```

# Actor output Schema

## `results` (type: `string`):

The delivered (and billed) records.

## `receipt` (type: `string`):

Per-link outcome, robots result, delivered and charged counts.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "urls": [
        "https://www.nasa.gov/",
        "https://www.usa.gov/"
    ],
    "maxPages": 10
};

// Run the Actor and wait for it to finish
const run = await client.actor("nexgensignal/schema-markup-extractor").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "urls": [
        "https://www.nasa.gov/",
        "https://www.usa.gov/",
    ],
    "maxPages": 10,
}

# Run the Actor and wait for it to finish
run = client.actor("nexgensignal/schema-markup-extractor").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "urls": [
    "https://www.nasa.gov/",
    "https://www.usa.gov/"
  ],
  "maxPages": 10
}' |
apify call nexgensignal/schema-markup-extractor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,nexgensignal/schema-markup-extractor"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/ybqDKwGCNS7AxXYIM/builds/7rH4KqP8PhRyxvvt8/openapi.json
