Schema Markup
Extract every schema.org JSON-LD entity from a live URL, including entities nested inside @graph arrays.
GET
/v1/schema-markup2 credits (refunded on failure)API keyFetches a public URL at request time and extracts every <script type="application/ld+json"> block into a flat list of schema.org entities. Use it to verify structured data (Organization, Product, FAQPage, Article and so on) after a deploy, or to compare a competitor's markup. Malformed blocks never fail the request: they are skipped and reported individually. This is a live fetch, not Common Crawl data.
Request
Parameters
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
url | string | Yes | none | Full http:// or https:// URL of the page. Same rules and limits as Page SEO: no fragment, public hosts only, 8 second timeout, 2 MB body cap. |
Example
curl "https://api.rankparse.com/v1/schema-markup?url=https://stripe.com/about" \
-H "X-API-Key: rp_your_key"import requests
resp = requests.get(
"https://api.rankparse.com/v1/schema-markup",
params={"url": "https://stripe.com/about"},
headers={"X-API-Key": "rp_your_key"},
timeout=30,
)
resp.raise_for_status()
body = resp.json()
print(body["types"], body["invalid_block_count"])const res = await fetch(
"https://api.rankparse.com/v1/schema-markup?" +
new URLSearchParams({ url: "https://stripe.com/about" }),
{ headers: { "X-API-Key": process.env.RANKPARSE_API_KEY } }
);
if (!res.ok) throw new Error(`${res.status}: ${await res.text()}`);
const body = await res.json();
console.log(body.types, body.invalid_block_count);Response
{
"url": "https://stripe.com/about",
"data": [
{
"type": ["Organization"],
"id": "https://stripe.com/#organization",
"block_index": 0,
"source": "graph",
"properties": {
"@context": "https://schema.org",
"@type": "Organization",
"@id": "https://stripe.com/#organization",
"name": "Stripe",
"url": "https://stripe.com",
"logo": "https://stripe.com/img/logo.png"
}
},
{
"type": ["WebPage"],
"id": null,
"block_index": 0,
"source": "graph",
"properties": {
"@type": "WebPage",
"name": "About Us",
"url": "https://stripe.com/about"
}
}
],
"total": 2,
"credits_used": 2,
"credits_remaining": 998,
"final_url": "https://stripe.com/about",
"status_code": 200,
"response_time_ms": 287,
"has_schema_markup": true,
"types": ["Organization", "WebPage"],
"block_count": 1,
"valid_block_count": 1,
"invalid_block_count": 0,
"invalid_blocks": []
}Response fields
| Field | Type | Description |
|---|---|---|
data | array | One entry per schema.org entity, flattened across blocks and @graph arrays. Empty when the page has no usable JSON-LD. |
data[].type | string[] | The entity's @type, normalized to an array even when the block declared a single string. |
data[].id | string or null | The entity's @id, or null. |
data[].block_index | integer | 0-based index of the <script> block the entity came from, counting every JSON-LD block on the page including malformed ones. |
data[].source | string | top_level for a block's own object or array item, graph for an entity nested inside @graph. |
data[].properties | object | The complete parsed JSON-LD object, including @context, @type, @id and every other property. |
total | integer | Number of entities in data. |
final_url | string | URL after redirects. |
status_code | integer | HTTP status the target returned. |
response_time_ms | integer | Fetch time in milliseconds. |
has_schema_markup | boolean | true when at least one entity was extracted. |
types | string[] | Unique types across all entities, sorted alphabetically. |
block_count | integer | JSON-LD blocks found on the page. |
valid_block_count | integer | Blocks that parsed as JSON. |
invalid_block_count | integer | Blocks that failed to parse. |
invalid_blocks | array | { index, error } for each malformed block, where error is the JSON parse message. |
Behavior and limits
- What counts as an entity. An object counts only if it has an
@type. A top-level array is expanded item by item. An object that has both its own@typeand an@graphyields the object itself (source: "top_level") and every graph member (source: "graph"). - Nesting depth. Arrays and
@graphnesting are followed up to 6 levels deep. Entities nested as property values (for example anauthorobject inside anArticle) stay insidepropertiesand are not listed separately. - Valid JSON with no entities. A block that parses but is not an object or array (for example a bare string), or an object with neither an
@typenor an@graph, counts as valid but adds nothing todata. - No JSON-LD. A page without structured data returns
200withdata: [],has_schema_markup: falseandblock_count: 0, not an error. - Static HTML only. JSON-LD injected by client-side JavaScript after load is not seen.
- Billing. Costs 2 credits. Failures after the charge (for example
503 fetch_failed) are refunded automatically; malformed or private URLs are rejected before billing. Subject to the standard 60 requests per minute limit.
Errors
| Status | Code | When |
|---|---|---|
400 | invalid_url | Missing, malformed or non-http(s) URL; credentials, whitespace or a fragment in the URL. |
400 | private_ip | Host is private, reserved or local. |
400 | response_too_large | The page body exceeded 2 MB. |
401 | invalid_api_key | Missing, invalid or revoked key. |
402 | insufficient_credits | Balance below 2 credits. |
402 | spend_cap_reached | Monthly spend cap reached. |
429 | rate_limited | More than 60 requests per minute. |
503 | fetch_failed | Target unreachable or redirected too many times. |
503 | timeout | Target did not respond within 8 seconds. |
See Errors for the shared error format.
Related
MCP tool: get_schema_markup.