Page SEO
Real-time SEO audit of any public URL, covering title, meta, canonical, Open Graph, hreflang, headings, images and links.
GET
/v1/page-seo3 credits (refunded on failure)API keyFetches a public URL at request time and returns a structured on-page SEO audit. Use it to check a single page's title and description lengths, canonical, robots directives, social tags and link counts. This is a live fetch, not Common Crawl data, so it reflects the page as it is right now.
Request
Parameters
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
url | string | Yes | none | Full http:// or https:// URL of the page to analyze. See URL rules. |
Example
curl "https://api.rankparse.com/v1/page-seo?url=https://stripe.com/about" \
-H "X-API-Key: rp_your_key"import requests
resp = requests.get(
"https://api.rankparse.com/v1/page-seo",
params={"url": "https://stripe.com/about"},
headers={"X-API-Key": "rp_your_key"},
timeout=30,
)
resp.raise_for_status()
audit = resp.json()["data"]
print(audit["title"]["text"], audit["title"]["optimal"])const res = await fetch(
"https://api.rankparse.com/v1/page-seo?" +
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 { data } = await res.json();
console.log(data.title.text, data.title.optimal);Response
{
"url": "https://stripe.com/about",
"data": {
"url": "https://stripe.com/about",
"final_url": "https://stripe.com/about",
"status_code": 200,
"response_time_ms": 312,
"title": { "text": "About Us - Example", "length": 18, "optimal": false },
"description": { "text": "Learn about Example Inc.", "length": 24, "optimal": false },
"canonical": { "url": "https://stripe.com/about", "self_referential": true },
"robots": { "index": true, "follow": true, "raw": "index,follow" },
"viewport": "width=device-width, initial-scale=1",
"language": { "primary": "en", "tag": "en-US", "source": "html_lang" },
"hreflang": [
{ "lang": "en", "url": "https://stripe.com/about" },
{ "lang": "fr", "url": "https://fr.stripe.com/about" }
],
"headings": {
"h1": ["About Us"],
"h2": ["Our Story", "Our Team"],
"h3_count": 4
},
"og": {
"title": "About Us - Example",
"description": "Learn about Example Inc.",
"image": "https://stripe.com/og-image.jpg",
"type": "website",
"url": "https://stripe.com/about"
},
"twitter": {
"card": "summary_large_image",
"title": "About Us - Example"
},
"json_ld": [{ "@type": "Organization", "name": "Example Inc." }],
"images": { "total": 8, "missing_alt": 2 },
"links": { "internal": 24, "external": 3 },
"word_count": 412,
"favicon": "https://stripe.com/favicon.ico"
},
"credits_used": 3,
"credits_remaining": 997
}Response fields
| Field | Type | Description |
|---|---|---|
url | string | The URL you sent (top level and inside data). |
final_url | string | The URL after following redirects. |
status_code | integer | HTTP status the target returned. The API still answers 200 and bills you when the target returns 404 or 500, so check this field. |
response_time_ms | integer | Time taken to fetch the page, including redirects. |
title | object | text (string or null), length (characters), optimal (true when length is 30 to 60). |
description | object | Meta description: text (string or null), length, optimal (true when length is 120 to 160). |
canonical | object | url of the canonical link, and self_referential: true when it equals final_url or the URL you sent, null when no canonical exists. |
robots | object | From the robots meta tag: index and follow (both true unless noindex or nofollow appears), and the lowercased raw value (null when no tag). |
viewport | string or null | Content of the viewport meta tag. |
language | object | primary (e.g. en), full tag (e.g. en-US) and source: html_lang, content_language_header or meta_http_equiv. All null when none is found. |
hreflang | array | { lang, url } for each rel="alternate" link carrying an hreflang. |
headings | object | h1 (all H1 texts), h2 (first 10 H2 texts) and h3_count (number of H3 elements). |
og | object | Open Graph tags keyed by the name after og:, with colon-separated parts camel-cased (og:image:width becomes imageWidth). Empty object when none. |
twitter | object | Twitter card tags keyed by the name after twitter:. Empty object when none. |
json_ld | array | Parsed JSON-LD objects found on the page. Malformed blocks are skipped. For flattened entities and per-block diagnostics use Schema Markup. |
images | object | total image tags and missing_alt (images with a missing or empty alt). |
links | object | internal and external anchor counts, split by whether the link host matches the final URL's host. |
word_count | integer | Words of visible text after removing scripts, styles and tags. |
favicon | string | Absolute URL of the declared icon, or /favicon.ico on the final host when none is declared (existence is not checked). |
credits_used | integer | Always 3 on success. |
credits_remaining | integer | Balance after the charge. |
Behavior and limits
URL rules
- Only
httpandhttpsare accepted. No credentials in the URL, no leading or trailing whitespace, and no fragment: any#in the URL is rejected withinvalid_url. - Hosts must be public.
localhost,*.local,*.internal,*.home.arpa, private and reserved IPv4 or IPv6 ranges, and hosts without a dot are rejected withprivate_ip. Every redirect hop is re-validated, so a public URL cannot redirect you into a private address. - Up to 5 redirects are followed.
Fetch limits
- Timeout is 8 seconds for the whole fetch.
- Only the first 2 MB of a response is accepted. Larger responses fail with
response_too_large. - The request is sent with the user agent
Mozilla/5.0 (compatible; RankParse/1.0; +https://rankparse.com). Sites that block unknown bots may return an error page; the audit then describes that page. - Pages are parsed from the raw HTML the server returns. Content rendered by client-side JavaScript is not seen.
Billing
- Costs 3 credits. If the call fails after being charged (any non-2xx response, such as
503 fetch_failed), the 3 credits are refunded automatically. Requests with a malformed or private URL are rejected before billing. - Calls count against the standard 60 requests per minute limit. See Rate limiting.
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 3 credits. |
402 | spend_cap_reached | Your monthly spend cap was reached. |
429 | rate_limited | More than 60 requests per minute. |
503 | fetch_failed | The target was unreachable, refused the connection, or redirected too many times. |
503 | timeout | The target did not respond within 8 seconds. |
Error bodies look like { "error": "Service Unavailable", "code": "fetch_failed" }. See Errors for the shared format.
Related
MCP tool: get_page_seo.