POST /v1/seo-audit fetches a URL twice — once as a plain HTTP bot with no JavaScript,
once fully rendered — and returns both views, the diff between them, and the bot-facing meta
(robots directives, Open Graph, Twitter card, JSON-LD types).
That diff is the whole point. A page whose text only exists after hydration is the classic SPA SEO hole, and it is invisible in a browser: your eyes always see the rendered view.
QuanticData SEO Audit API — $0.0012 per URL, or cheaper
with no_render: true when you only want the bot view.
pip install requests
export QUANTICDATA_API_KEY=qd_live_your_key_here
python3 audit_url.py https://example.com
python3 audit_site.py https://example.com --limit 100| File | What it does |
|---|---|
audit_url.py |
one URL, both views, human-readable verdict |
audit_site.py |
map the site → audit every URL → CSV of the findings |
ci_gate.py |
exit non-zero when a page regresses — drop it in CI before a deploy |
hasContent is true when the view carries at least 150 indexable words — <noscript>
included, because bots read it.
| Flag | What it means | Severity |
|---|---|---|
contentOnlyInJs |
the page is essentially blank without JS | critical |
canonicalMissingNoJs |
canonical injected by JS — crawlers may miss it | high |
h1OnlyInRender |
no H1 in the served HTML | medium |
titleChanged |
title rewritten client-side; the SERP may show the other one | medium |
descriptionChanged |
same, for the snippet | low |
- How to perform an SEO audit
- How to SEO audit a website
- How to run a site audit in Semrush
- Crawl & Map API — where the URL list comes from
- robots.txt tester
MIT licensed.
{ "url": "https://example.com", "finalUrl": "https://example.com/", "noJs": { "status": 200, "title": "…", "description": "…", "canonical": "…", "h1": "…", "wordCount": 812, "hasContent": true }, "render": { "status": 200, "title": "…", "description": "…", "canonical": "…", "h1": "…", "wordCount": 1140, "hasContent": true }, "diff": { "titleChanged": false, "descriptionChanged": false, "h1OnlyInRender": false, "canonicalMissingNoJs": false, "contentOnlyInJs": false // ← the one that costs you rankings }, "meta": { "robots": "index,follow", "ogTitle": "…", "ogUrl": "…", "twitterCard": "summary_large_image", "jsonldTypes": ["Organization", "FAQPage"] }, "durationMs": 2140 }