To SEO audit a website, work in four passes: can search engines crawl it, do they index the right URLs, does each page render the content and metadata you think it does, and is the content plus link profile competitive. Fix crawl and index blockers first — everything else is downstream of them.
What an SEO audit is actually checking
An audit is a diagnostic, not a score. The score most free tools hand you is a summary of dozens of binary checks weighted by someone else's opinion. What you need out of an audit is a ranked list of defects with an owner attached: dev, content, or off-page.
Every serious audit covers the same four layers, in this order of severity:
- Crawlability — robots.txt directives, status codes, redirect chains, internal link reachability, sitemap accuracy, crawl waste on faceted or paginated URLs.
- Indexability and rendering — noindex and canonical signals, duplicate URL variants, and whether the content exists in the initial HTML or only after JavaScript runs.
- On-page and content — titles, meta descriptions, heading hierarchy, internal anchors, thin or decaying pages, keyword cannibalisation between near-duplicate pages.
- Off-page and performance — referring domains and anchor distribution, Core Web Vitals, mobile experience, structured data validity.
Order matters because the layers are dependent. A perfectly optimised title tag on a page that returns 404 to Googlebot is worth zero. Mobile matters more than most desktop-first teams assume: mobile has accounted for roughly 63% of US organic search visits in recent years, per Statista, so the mobile rendering path is the primary one.
The step-by-step SEO audit checklist
This is the sequence I use on a site I have never seen before. It works for a 40-page brochure site and for a 400,000-URL catalogue; only the sampling changes.
- Record the baseline. Export 12 months of organic clicks, impressions and average position from Search Console, plus indexed URL counts by page type. Without a baseline, no post-fix claim is provable.
- Enumerate the URL space. Pull every URL the site advertises — sitemaps plus homepage and navigation links — and compare that set with what analytics and Search Console know about. Orphans and ghosts both show up in this diff.
- Crawl and collect status codes. Look for 4xx in internal links, 302s that should be 301s, redirect chains longer than one hop, and soft 404s serving 200.
- Check indexation by template. Divide indexed pages by published pages for each template (product, category, blog, tag). A tag archive at 100% and a product template at 40% tells you exactly where to dig.
- Compare bot HTML with rendered HTML. Fetch each priority URL twice — once as a plain HTTP client with no JavaScript, once fully rendered — and diff them. This is the single highest-yield check on modern stacks.
- Audit on-page elements in bulk. Missing, duplicated or truncated titles; missing H1s; multiple H1s used as styling; meta descriptions auto-generated from boilerplate.
- Map internal links. Measure click depth from the homepage and inbound internal links per URL. Money pages sitting at depth five with two internal links are a self-inflicted wound.
- Grade content against intent. For each target query, open the live SERP and ask whether the ranking page type matches yours. Wrong page type beats bad copy as a failure cause.
- Find decay and cannibalisation. Pages that lost more than 30% of clicks year on year, and query groups where two of your URLs swap positions week to week.
- Assess the link profile. Referring domains versus the three closest competitors, anchor distribution, and which pages hold the authority. Note that only about 5% of pages get any external links at all, per Backlinko's ranking factors study — a handful of earned links to a key page can move it.
- Measure performance and mobile. Field Core Web Vitals where available, lab data as a fallback, and check for mobile-only layout or blocked-resource issues.
- Write the fix list. Each item: what is broken, which URLs, expected impact, effort, owner, and how you will verify it.
Steps 1 to 4 and 12 are non-negotiable. Everything else scales with the size of the site and the budget.
The check most audits skip: bot view versus rendered view
Free checkers usually fetch a page one way and report on that. But client-side frameworks routinely inject the parts that matter — body copy, canonical tags, structured data, sometimes the title itself — after JavaScript executes. Crawlers may render eventually, and LLM-based crawlers frequently do not render at all. So the useful question is not "is the content there" but "is the content there without JavaScript".
Three findings recur, and all three are invisible to a single-fetch audit:
- Body content present in the rendered DOM but absent from the raw HTML — the page looks thin to any non-rendering consumer.
- Title or meta description overwritten client-side, so the bot-facing version differs from what you approved.
- Canonical or hreflang injected by script, meaning duplicate consolidation silently depends on rendering.
Doing this by hand means curl with JavaScript off, then a headless browser, then eyeballing two blobs of HTML. Doing it at scale means one call per URL that returns both views plus the diff. That is exactly what the SEO Audit API does — no-JS fetch and rendered fetch of the same URL, both views returned, plus the diff (JS-only content, changed title or description, canonical missing without JS) and the bot-facing meta, at $0.0012 per URL.
How to SEO audit a website free — and where free stops
You can get a long way at zero cost. Search Console gives you index coverage, query data and Core Web Vitals field data for your own property. A desktop crawler will surface status codes, duplicate titles and click depth on small sites. Browser dev tools show you the rendered DOM. Free web checkers give a fast first-page snapshot with plain-language explanations, which is genuinely useful for beginners.
Free stops at three places: URL volume caps, repeatability, and rendering comparison. The moment you want the same 5,000 checks re-run weekly and diffed against last week, you are either buying a subscription seat or scripting it.
| Approach | Best for | Typical limit | Cost of re-running weekly |
|---|---|---|---|
| Free online checker | First look, beginners, single-page triage | One page or a shallow crawl; no history | Manual, per URL |
| Search Console + PageSpeed data | Index coverage and real user performance on your own site | Your properties only; sampled URL data | Free, but no crawl of arbitrary URLs |
| Desktop crawler | Deep technical crawl of a mid-size site | Your machine, your IP, manual scheduling | Your time; blocked IPs on hostile targets |
| Platform site audit | Shared reporting, scheduled crawls, non-technical teams | Crawl credits per plan; fixed monthly fee | Flat subscription regardless of usage |
| Scripted API audit | Custom checks, competitor URLs, CI pipelines, agents | You write the logic | Per successful URL, no seat |
Most teams end up mixing three of these. The mistake is paying a subscription for checks you run twice a year.
Scripting the audit: crawl, audit, diff
The scripted version has three moves. Enumerate URLs, audit the priority set, store the results so the next run is a diff instead of a fresh opinion.
Start with a single URL to see the shape of the response:
curl https://api.quanticdata.io/v1/seo-audit \
-H "Authorization: Bearer $QD_API_KEY" \
-d '{ "url": "https://example.com/pricing" }'
{ "success": true,
"data": { "...": "no-JS view, rendered view, diff, bot-facing meta" },
"usage": { "cost_usd": 0.0012 } }
Then enumerate and loop. /v1/map returns the URLs a site advertises — sitemaps plus homepage links, with totals and a per-section summary — for $0.0005 a call, which is your cheapest possible site inventory:
import os, requests
API = "https://api.quanticdata.io/v1"
H = {"Authorization": f"Bearer {os.environ['QD_API_KEY']}"}
# 1. inventory the site
site = requests.post(f"{API}/map",
json={"url": "https://example.com"},
headers=H).json()
urls = site["data"]["links"] # see docs for exact field names
# 2. audit a prioritised slice, not everything
findings = []
for url in urls[:250]:
r = requests.post(f"{API}/seo-audit", json={"url": url}, headers=H).json()
if not r["success"]:
continue # failed calls are not billed
findings.append({"url": url, "audit": r["data"], "cost": r["usage"]["cost_usd"]})
print(len(findings), "URLs audited for $%.4f" % sum(f["cost"] for f in findings))
Every endpoint returns the same envelope — success, data, usage — so the report writer does not care which check produced a row. If you also want the full text of each page for a content audit, crawl to Markdown at $0.0003 per page and run your own thin-content and cannibalisation logic over it; unfetched pages in an async job are refunded when the job settles.
Rank and SERP context
Position data belongs in the same run. Pull the live SERP for each target query and record which URL of yours appears, what page type is winning, and which competitors own the intent. The SERP API returns SerpApi-compatible JSON from $0.0005 per search across 17 verticals, which means the same script can check a local pack, a shopping result, or plain organic. If you have never wired one up, the walkthrough in how to use a SERP API covers the request shape.
Honest cost math for a recurring audit
Assume a 500-URL site audited monthly, with 100 tracked keywords, and a full content pull once a quarter.
| Job | Volume | Unit | Run cost |
|---|---|---|---|
| Site inventory (map) | 1 call | $0.0005 | $0.0005 |
| No-JS vs rendered audit | 500 URLs | $0.0012 | $0.60 |
| Keyword positions | 100 searches | $0.0005 | $0.05 |
| Full content pull (quarterly) | 500 pages | $0.0003 | $0.15 |
That is about $0.65 for a monthly technical and ranking pass, $0.80 in the quarters where you also pull content. The pay-as-you-go tier includes $2 of free usage every month with no card, so a site this size is genuinely free to audit on a schedule; failed calls cost nothing under the pay-per-success rule. Scale the same maths to 50,000 URLs and the audit is $60 — worth comparing honestly against a subscription that caps crawl credits.
The real cost is not the fetching. It is the judgement in step 12: deciding which of 400 findings actually move revenue. No API replaces that.
Turning findings into an SEO audit report
A report nobody acts on is a deliverable, not an audit. Four things make it actionable:
- Severity by traffic exposure, not by check count. Twelve broken links on orphan pages rank below one noindex on a category template.
- URL lists attached to every finding, exportable as CSV. Developers fix lists, not adjectives.
- A stated verification method per item — the exact re-check that proves the fix landed.
- A diff against the previous run. "Eleven issues closed, three new since the last deploy" is the sentence that keeps audits funded.
Keep raw responses. Once you store the no-JS and rendered views per URL per run, regressions become obvious: a framework upgrade that moves the canonical tag into JavaScript shows up as a diff, not as a mysterious traffic drop six weeks later.
Running audits from an AI agent
If your workflow already lives in an assistant, the audit can be a tool call rather than a script. The MCP server exposes eight tools — search, scrape, map, crawl, crawl_status, batch, batch_status and seo_audit — to Claude, Claude Code, Cursor, Windsurf, VS Code and Cline, with the same pay-per-success billing underneath:
claude mcp add quantumproxies \
-e QUANTUMPROXIES_API_KEY=qp_live_your_key_here \
-- npx -y quantumproxies-mcp
The practical pattern: ask the agent to map the site, audit the twenty highest-traffic URLs, and summarise only the findings where the no-JS view differs from the rendered one. You get a written triage in one turn, and you keep the raw JSON for the report. Agents are good at grouping hundreds of similar findings into themes; they are poor at deciding business priority, so keep that decision with a human.
A note on auditing sites you do not own
Competitive and prospect audits touch third-party servers. Respect robots directives and site terms, keep request rates sane, and stick to publicly accessible pages. The general legal landscape is summarised in is web scraping legal in the US — informational only, not legal advice; get your own counsel for anything commercially sensitive.
Cadence and what to ignore
Full audit quarterly. Technical delta after every significant deploy. Rank and index monitoring weekly. Content decay review twice a year. Anything more frequent produces noise that no one reads.
Things safe to deprioritise: chasing a composite audit score toward 100, fixing every non-blocking validator warning, and micro-tuning meta descriptions on pages with no impressions. Organic search still accounts for a large majority of clicks that are not paid — Semrush's search data has put organic at roughly 45% of all search result clicks with paid in single digits (Semrush, State of Search) — which means the return sits in making important pages crawlable, renderable and genuinely better, not in cosmetic scores. And check the basics against Google Search Essentials rather than any tool's interpretation of them.