Try the RankNibbler SEO API

Page diff Beta

GET /api/v1/page-diff

Diffs two live pages field by field in a single call — staging vs production, before vs after a deploy, or your page vs a competitor's. It fetches both URLs, fingerprints them, and returns a structured change list that names which specific links and images were added or removed, not just that a count moved.

Beta. This endpoint is new: it is live and safe to call on every plan, but its response shape may still change while we take feedback. Nothing here is scheduled for removal — if you depend on a particular field, tell us and we will keep it stable for you.

Both URLs are SSRF-validated independently before either is fetched. Two fetches, one request against your quota. Static analysis of the served HTML; no browser is involved.

Fields compared: title, meta description, H1, canonical, word count, HTTP status, Open Graph title, Open Graph description, indexing directive, heading outline, structured-data types, detected prices, body text, and the added/removed internal links, external links and images.

Authentication

Send your API key as an X-API-Key header, or as a key query parameter. Available on every plan, including Free — plans differ only in requests per day. This call costs one request against your daily quota, which is shared across every key on the account. See Authentication.

Query parameters

NameTypeDescription
url requiredstringThe "before" / baseline page.
compare requiredstringThe "after" / comparison page. Alias: compare_url. Bare domains default to https://; maximum 2,048 characters.
key optionalstringYour API key, if not sent as the X-API-Key header.

Request

Response

200 · application/json
  1. {
  2. "url": "https://staging.example.com/p",
  3. "compare": "https://example.com/p",
  4. "changed": true, "changeCount": 4,
  5. "badges": ["Title", "H1 heading", "Headings", "Word count"],
  6. "changes": [
  7. { "field": "title", "label": "Title", "cat": "meta", "kind": "changed",
  8. "old": "Best Coffee Beans 2026", "new": "New Title" },
  9. { "field": "internalLinks", "label": "Internal links", "cat": "structure",
  10. "kind": "changed", "old": 22, "new": 20,
  11. "added": [], "removed": ["https://example.com/old-page"] }
  12. ],
  13. "before": { "…": "full page-signals object for url" },
  14. "after": { "…": "full page-signals object for compare" }
  15. }

Response fields

FieldTypeDescription
changedbooleanWhether anything differs. When false, changes and badges are both [].
badgesstring[]Short human labels for the categories that changed — handy for a notification subject line.
changes[]arrayOne entry per changed field: field, label, cat, kind, old and new. List fields also carry added and removed, each capped at 60 entries.
before / afterobjectThe full page-signals fingerprint for each URL, so you can store them without a second call.

Errors

StatusWhen
400compare is missing, or is longer than 2,048 characters.
401Missing or invalid API key.
403Either URL is a private, loopback or cloud-metadata address. Both are checked independently.
429Burst rate limit (60 req/10s per IP, 30 req/10s per key) or your daily quota. See Rate limits.
502One of the two URLs could not be fetched.
503The signal engine is unavailable on this server. This check runs before authentication.

Errors return { "error": "…" }; see Errors.