SEO Site Audit (0-100 Score and Fix List) avatar

SEO Site Audit (0-100 Score and Fix List)

Pricing

from $2.75 / 1,000 pages

Go to Apify Store
SEO Site Audit (0-100 Score and Fix List)

SEO Site Audit (0-100 Score and Fix List)

Audit any website for SEO: a 0-100 score per page and per site, a ranked fix list with why and how, and page checks for title, meta description, h1, canonical, schema.org and alt text. Also AI crawler access (GPTBot, ClaudeBot), llms.txt and optional Core Web Vitals. $5 per 1,000 pages.

Pricing

from $2.75 / 1,000 pages

Rating

0.0

(0)

Developer

locaihost data

locaihost data

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

14 days ago

Last modified

Share

Audit any list of websites for SEO and website health: a 0-100 score for every site and page, a prioritised fix list in plain words (what's wrong, why it matters, how to fix it), on-page checks, which search and AI crawlers robots.txt allows, and optional Core Web Vitals, as JSON or CSV rows. No login; you only enter the sites.

  • Agencies: monthly client reports. Run every client site on a schedule and send the site score and topFixes (with why and how) as the to-do list.
  • Site owners: are we visible to AI search? See bot by bot whether robots.txt blocks OAI-SearchBot, PerplexityBot, Claude-SearchBot or ChatGPT-User, and whether the site has an llms.txt.
  • Developers: catch a bad deploy. A weekly run flags an accidental noindex, a missing <title> or a page that now returns 404.
  • Content teams: fix pages in priority order. Page scores and each page's fixes show thin pages, missing meta descriptions, multiple <h1>s and images without alt text.
  • Speed checks: add Core Web Vitals from Google's real-visitor data for each homepage, at no extra charge.

Quick start

Paste this into the JSON tab of the input and click Start:

{"urls": ["apify.com", "example.com"], "maxPagesPerSite": 5}

You get up to 5 page rows per site plus one free summary row per site: 8 rows in about 10 seconds. Enter domains (example.com) or start URLs (https://example.com/blog); each site is crawled breadth-first from there through same-site links.

With Core Web Vitals for each homepage:

{"urls": ["stripe.com", "python.org"], "maxPagesPerSite": 10, "includeWebVitals": true, "googleApiKey": "<your Google API key>"}

What data can I get?

Real site summaries from this Actor's output: AI-readiness score, llms.txt, robots.txt, AI crawler access and sitemap size for four public sites

Two row types in one dataset: one site summary per site and one page row per page audited.

GroupFields
Site scoresiteScore, siteScoreBand, averagePageScore, topFixes (priority, issue, why, how, pages), topIssues, recommendations
Site statussite, input, auditedSite, status, pagesAudited, pagesFailed, pagesBlockedByRobotsTxt, pagesTried, stoppedEarly, https
Crawlers and filesrobotsTxtFound, aiCrawlers, aiCrawlersBlocked, aiReadinessScore, llmsTxt, sitemap, sitemapUrlCount, checkErrors
Page scorescore, scoreBand, fixes, issues, charged, error
On-page SEOtitle, titleLength, metaDescription, metaDescriptionLength, h1, h1Count, canonical, lang, openGraph, schemaTypes
ContentwordCount, imageCount, imagesWithoutAlt, internalLinkCount, externalLinkCount
Fetchurl, status, indexable, redirected, requestedUrl, responseTimeMs
Core Web VitalswebVitals (only when Measure Core Web Vitals is on; see below)

What the less obvious fields mean:

  • status on a site row: audited, unreachable, http-error, blocked-by-robots, blocked-by-bot-protection (the site served a bot-protection page such as Cloudflare's "Just a moment" instead of its content), not-started-time-limit (free), incomplete-time-limit (its pages are in the dataset) or audit-error (an error on our side; free).
  • aiCrawlers: allowed, blocked or unknown for 12 bots: GPTBot, OAI-SearchBot, ChatGPT-User, ClaudeBot, Claude-SearchBot, PerplexityBot, Google-Extended, Applebot-Extended, meta-externalagent, Amazonbot, CCBot and Bytespider (checked for /). unknown when robots.txt couldn't be read; it never guesses allowed.
  • auditedSite: present when your start URL redirected to another host. Within the same site (python.org to https://www.python.org) the audit continues there. A move to a different domain gets only its landing page audited.
  • llmsTxt: true, false, or null if the request failed. sitemap comes from robots.txt or /sitemap.xml and /sitemap_index.xml; sitemapUrlCount includes up to 10 child sitemaps of an index.
  • checkErrors: which of robots.txt, llms.txt or the sitemap couldn't be checked, and why. Unknowns earn no points and are never reported as missing.
  • indexable is false on a meta robots or X-Robots-Tag noindex. Page text is stored as a reader sees it: line breaks and repeated spaces collapsed.

One real site row and one real page row (run on 2026-10-18; aiCrawlers trimmed to 4 of 12 bots, topFixes and fixes to 1):

[
{
"type": "site",
"site": "https://apify.com",
"input": "apify.com",
"status": "audited",
"https": true,
"siteScore": 95,
"siteScoreBand": "good",
"aiReadinessScore": 96,
"averagePageScore": 93,
"pagesAudited": 10,
"pagesFailed": 0,
"robotsTxtFound": true,
"aiCrawlers": {"GPTBot": "allowed", "OAI-SearchBot": "allowed", "ChatGPT-User": "allowed", "ClaudeBot": "allowed"},
"aiCrawlersBlocked": [],
"llmsTxt": true,
"sitemap": "https://apify.com/sitemap.xml",
"sitemapUrlCount": 289816,
"topFixes": [{"priority": 3, "issue": "Images without alt text", "why": "Search engines can't tell what the images show, and people using screen readers miss them.", "how": "Add a short alt description to each meaningful image. Use alt=\"\" for purely decorative ones.", "pages": 7}]
},
{
"type": "page",
"site": "https://example.com",
"url": "https://example.com/",
"status": 200,
"title": "Example Domain",
"titleLength": 14,
"metaDescription": null,
"canonical": null,
"lang": "en",
"h1Count": 0,
"schemaTypes": [],
"openGraph": false,
"wordCount": 25,
"indexable": true,
"responseTimeMs": 34,
"score": 45,
"scoreBand": "poor",
"issues": ["Missing meta description", "Missing <h1>", "No canonical link", "No schema.org structured data", "No Open Graph tags", "Thin content (25 words)"],
"fixes": [{"priority": 2, "issue": "The page has no meta description", "why": "Search engines then pick a snippet of page text for the result, which usually earns fewer clicks.", "how": "Add a meta description of 50–170 characters that sums up the page and gives a reason to click."}],
"charged": true
}
]

The dataset has four views (Scores and fixes, Site summaries, Page audits, Everything) and exports to JSON, CSV, Excel or HTML.

How the scores work

Every score comes from the checks below with fixed weights, so the same pages always get the same score.

Page score (score) starts at 100 and loses points for each failed check. A page that answers an HTTP error scores 0.

CheckPoints lostFix priority
Page is set to noindex201
No <title>251
Title shorter than 10 or longer than 65 characters53
No meta description152
Meta description shorter than 50 or longer than 170 characters53
No <h1>102
More than one <h1>33
No canonical link53
No schema.org structured data102
No lang on <html>53
No Open Graph tags53
Images without alt text2 per image, up to 103
Under 150 words of text102

Site score (siteScore) adds up to 100:

PartPoints
Average page score of the audited pages70 × average ÷ 100
Pages that load without an HTTP error10 × share of pages that loaded
Served over HTTPS5
robots.txt loads (with rules, or a plain 404)5
XML sitemap found5
AI answer engines allowed (OAI-SearchBot, ChatGPT-User, Claude-SearchBot, PerplexityBot)5 × share allowed

Bands use Google Lighthouse's cut-offs: good 90-100, needs-work 50-89, poor 0-49.

Fix order. Priority 1 means the page or site can't be found or used (an error page, noindex, no title, a robots.txt that errors, no HTTPS). Priority 2 means it's found but shows or ranks worse than it could. Priority 3 is polish. Within a priority, fixes that cost more points (on more pages, for topFixes) come first. Core Web Vitals never change siteScore or score, but a homepage with slow Core Web Vitals adds a fix to topFixes.

AI-readiness score (aiReadinessScore): 60% of the average page score, plus 10 points each for an llms.txt, an XML sitemap and schema.org data on the start page, plus up to 10 points (2.5 per bot) for allowing the AI answer engines OAI-SearchBot, ChatGPT-User, Claude-SearchBot and PerplexityBot. Blocking training crawlers such as GPTBot or CCBot doesn't cost points; it's reported so you can see what you're blocking.

Core Web Vitals (optional)

Turn on Measure Core Web Vitals and the start page of each site (or up to 10 pages, with Pages to measure per site) gets a webVitals object from Google's PageSpeed Insights, tested as a mobile phone:

FieldWhat it means
assessmentGoogle's verdict for real visitors: the worst rating of LCP, INP and CLS (good, needs-improvement, poor). null when Chrome has too little data for the site
lcpMs/lcpRating, inpMs/inpRating, cls/clsRatingLargest Contentful Paint, Interaction to Next Paint and Cumulative Layout Shift for real Chrome visitors over the last 28 days (75th percentile), with Google's rating for each
fieldDatapage = data for that exact page; origin = data for the whole site, used when the page has too few visits; none = not enough Chrome traffic for either
performanceScore, labLcpMs, labCls, labTbtMsGoogle's lab test: the Lighthouse performance score (0-100) and its measurements on a simulated mid-range phone
speedFixesUp to 3 of Lighthouse's biggest speed improvements, with the estimated time saved
status, errormeasured, failed (with the reason) or skipped (not tried, with the reason)

The site summary's webVitals is the start page's. Google API key: add your own free key in Google API key (Google Cloud Console, APIs & Services, Credentials, then enable "PageSpeed Insights API"; about 2 minutes). Google currently refuses almost every request without a key; the run still finishes normally and each webVitals says why it wasn't measured. The key is stored encrypted, sent only to Google, and never written to the output or the log.

How much does it cost?

You pay per page audited. There is no charge for Apify platform usage on top.

RowFree and StarterScaleBusiness
Page audited$5 per 1,000$3.75 per 1,000$2.75 per 1,000

Plus $0.00005 per run start. Apify's free $5 monthly credit covers about 1,000 pages. Free-plan runs stop at 50 charged pages each; any paid Apify plan removes the cap.

What's free: site summary rows; Core Web Vitals measurements; robots.txt, llms.txt and sitemap checks; pages that fail (timeout, DNS error, HTTP 3xx/4xx/5xx), which still appear with charged: false; bot-protection pages served instead of the real page; sites that can't be audited; and skipped inputs. Only real pages that answered 2xx are charged. To cap a run's spend, set Maximum cost per run in the run options, or Max pages in total in the input.

Example: an agency audits 20 client sites at 10 pages each in one run: 200 pages = $1.00 on Starter ($0.75 on Scale, $0.55 on Business).

Limits, stated up front

  • Up to 500 pages per site (maxPagesPerSite), crawled breadth-first through same-site links. PDFs, images, documents and media files are skipped.
  • No JavaScript rendering. Pages are analysed as the server sends them, which is also what most AI crawlers see. The optional Core Web Vitals lab test is the exception: Google loads the page in its own browser.
  • It respects robots.txt for its own user agent (locaihost-site-audit, following RFC 9309: a robots.txt that answers a server error means "crawl nothing"), fetches one page at a time per site, and never logs in.
  • Sites behind bot protection (Cloudflare, Imperva, Sucuri, DataDome) often can't be audited: the site row says blocked-by-bot-protection and nothing is charged.
  • Up to 4 sites are audited at once. A run that would outlast its timeout stops itself shortly before, keeps every page audited so far and still writes each site's summary.
  • Each Core Web Vitals measurement takes about 15-40 seconds on Google's side; the crawl carries on meanwhile. With a key, up to 4 pages are measured at once; without one, one at a time. A missing or rejected key, or a used-up daily quota, stops further measurements for that run.
  • Inputs that are IP addresses, localhost, private or reserved names, or not http(s) are skipped (free), and listed in the run's SUMMARY record.

Schedules

Save your site list as a task and add a weekly or monthly schedule under Schedules in Apify Console. Every run fetches robots.txt, llms.txt, the sitemap and the pages live, so it catches a new noindex, a newly blocked bot or a broken page soon after a deploy.

Integrations: API, n8n, Make and AI agents

API. Run it and get every row back in one call (synchronous runs time out after 5 minutes, so use the async run endpoint for many sites):

curl -X POST "https://api.apify.com/v2/acts/locaihost~site-audit/run-sync-get-dataset-items?token=YOUR_APIFY_TOKEN" \
-H "Content-Type: application/json" \
-d '{"urls": ["example.com"], "maxPagesPerSite": 10}'

Python, with pip install apify-client:

from apify_client import ApifyClient
client = ApifyClient("<APIFY_TOKEN>")
run = client.actor("locaihost/site-audit").call(run_input={"urls": ["example.com", "example.org"], "maxPagesPerSite": 10})
for row in client.dataset(run["defaultDatasetId"]).iterate_items():
if row["type"] == "site":
print(row["site"], row["siteScore"], row["aiReadinessScore"], [f["issue"] for f in row["topFixes"][:3]])

n8n, Make, Zapier, Google Sheets, Slack, webhooks. Apify's built-in integrations send each run's dataset wherever you need it, for example each client's topFixes into a Google Sheet.

AI agents (MCP). Add this Actor to Claude, Cursor or any MCP client with https://mcp.apify.com/?tools=locaihost/site-audit, then ask something like "Can ChatGPT search and Perplexity crawl acme.com? Audit 10 pages and give me the site score and the top fixes." The site row holds siteScore, topFixes, the AI-readiness score and the bot-by-bot aiCrawlers map, so the agent can answer from that one row.

FAQ

How much does an SEO site audit cost?

$5 per 1,000 pages audited on the Free and Starter plans, less on Scale and Business. Site summaries, Core Web Vitals and failed pages are free. Apify's free $5 monthly credit covers about 1,000 pages.

Can I use it through the API or from Python?

Yes. Use the run-sync-get-dataset-items call or the Python example above, or Apify's JavaScript client. Every run's data is also available as JSON, CSV or Excel from its dataset.

Can I use it from an AI agent?

Yes. Through the Apify MCP server (https://mcp.apify.com/?tools=locaihost/site-audit) any MCP client can call it with {"urls": ["acme.com"], "maxPagesPerSite": 10} and read the site row back.

It reads only public pages, respects robots.txt for its own user agent, fetches one page at a time per site, and never logs in. It's meant for sites you own or manage, and your clients' sites. It records technical facts about pages (status codes, tags, counts and scores); the only page text it stores is the title, meta description and first <h1>, and it never extracts emails, phone numbers, names or form contents. You are responsible for how you use it.

Does blocking GPTBot lower my scores?

No. Only the AI answer engines (OAI-SearchBot, ChatGPT-User, Claude-SearchBot, PerplexityBot) count towards siteScore and aiReadinessScore. Blocking training crawlers is reported in aiCrawlersBlocked but costs no points.

Why are some fields empty?

A failed page has a null score and band, with the reason in error. A site that couldn't be audited has a null siteScore and aiReadinessScore (see status). aiCrawlers values are unknown when robots.txt answered with an error or a bot-protection page; checkErrors.robotsTxt says what happened. webVitals appears only when Core Web Vitals is on.

Why were fewer pages audited than I asked for?

The site has fewer same-site HTML links reachable from the start URL, robots.txt disallows the rest (pagesBlockedByRobotsTxt), or the run's time limit was reached (stoppedEarly: true). On the free plan, runs stop at 50 charged pages.

More from locaihost data

Did it help?

If this saved you time, a quick rating on the Store helps other people find it.

Support

Something not working, or another check you need (hreflang, broken-link checking)? Open an issue on the Issues tab: we answer issues within 24 hours.