Technical SEO Page Audit
Pricing
from $20.00 / 1,000 page auditeds
Technical SEO Page Audit
Audit public pages for technical SEO with 44 deterministic checks: indexability, robots.txt, canonical, titles, headings, links, images, JSON-LD, hreflang, HTTPS and headers. Every check carries its evidence. No JavaScript rendering, no AI.
Pricing
from $20.00 / 1,000 page auditeds
Rating
0.0
(0)
Developer
Alijah Konikowski
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
8 days ago
Last modified
Categories
Share
Audits public web pages for technical SEO and returns one JSON report per page: 44 fixed checks, each with a
status, the evidence it was decided on, and a fixed recommendation when it warns or fails. The same HTML and response
headers always give the same checksSha256.
It reads what a crawler reads: the server HTML, response headers, robots.txt and, if you ask, the status of the
page's links. It does not run JavaScript and uses no AI model.
Input
| Field | Type | Default | |
|---|---|---|---|
urls | array of http(s) URLs | Pages to audit, up to 100 | |
sitemapUrl | URL | Optional sitemap or sitemap index; same-host pages are added in sitemap order | |
maxPages | 1-100 | 10 | Pages taken from the sitemap |
checkLinks | boolean | false | HEAD-request the page's links and report 4xx/5xx |
maxLinksToCheck | 1-50 | 20 | Links checked per page |
timeoutSecsPerUnit | 10-300 | 60 | Time allowed per page |
Give urls, sitemapUrl, or both. Example:
{"urls": ["https://example.com/"]}
Output
One dataset item per audited page:
score.overall(0-100) andscore.categories, computed from check weights: pass counts fully, warn half, fail zerocountsof pass / warn / fail / info / not_applicable / not_checkedchecks[]:id,category,title,weight,status,evidence,recommendation(null unless the check warns or fails),measured(true for the two time-dependent checks)page: title, meta description, canonical, robots directives, H1s, word count, link and image counts, JSON-LD types, Open Graph, hreflanghttp: status, redirect chain, response time, HTML bytes, transfer bytes, content encodingcompleteness: whetherrobots.txtand the link check were fully readhtmlSha256(the HTML that was judged) andchecksSha256(the checks, excluding the two time-dependent ones)
A page that cannot be audited (DNS failure, timeout, 4xx/5xx, non-HTML, blocked address) produces an item with
ok: false and an error.code instead. The key-value store record OUTPUT lists every page with whether it was
charged and why.
Real output for the example input above, shortened to 3 of the 44 checks and 6 of the page fields:
{"url": "https://example.com/","finalUrl": "https://example.com/","ok": true,"score": {"categories": {"content": 84,"indexability": 93,"links": 75,"performance": 100,"security": 92,"structured_data": 50},"overall": 86},"counts": {"fail": 0,"info": 5,"not_applicable": 10,"not_checked": 1,"pass": 20,"warn": 8},"completeness": {"linkCheck": "skipped","robotsTxt": "absent"},"htmlSha256": "25ddf2c883e0d1958ea971d279a7e4f0fd446724ee3db7db19dadabd4a62e484","checksSha256": "80404755eac37451a50a6046a764bdb094592c32ead1074bc4bf41a6a4680935","fetchedAt": "2026-10-08T02:51:10Z","checks": [{"category": "indexability","evidence": {"canonical": []},"id": "IDX004","measured": false,"recommendation": "Add one <link rel=\"canonical\"> with an absolute URL in <head>; remove duplicates.","status": "warn","title": "Exactly one absolute canonical URL","weight": 2},{"category": "indexability","evidence": {"http_status": 404,"note": "no robots.txt: everything is allowed","robots_url": "https://example.com/robots.txt"},"id": "IDX006","measured": false,"recommendation": null,"status": "pass","title": "robots.txt allows crawling this URL","weight": 5},{"category": "content","evidence": {"h1": [],"h1_count": 0},"id": "CNT005","measured": false,"recommendation": "Use exactly one <h1> that states the page topic.","status": "warn","title": "Exactly one H1","weight": 2}],"page": {"title": "Example Domain","metaDescription": null,"canonical": null,"lang": "en","h1": [],"wordCount": 25},"http": {"status": 200,"redirects": [],"responseMs": 50,"htmlBytes": 577,"transferBytes": 400,"contentEncoding": "gzip"}}
Pricing
Pay per event:
page-audited: $0.02 per page that produced a report. A page is charged only after its report is validated against the output schema and saved to the dataset.- Apify's run-start event,
apify-actor-start: $0.00005 per run (one event: this Actor's memory is capped at 1 GB). - Platform usage (compute, storage, data transfer) is not charged to you on top of these events.
Never charged: pages that fail to load (DNS, timeout, connection reset, 4xx/5xx, rate limiting), non-HTML responses,
invalid or private-network URLs, and any page the run's maximum charge cannot cover (the run stops before fetching
it). A report whose robots.txt or link check could not be completed is still a report and is charged; completeness
says which part is missing.
Checks
| Id | Category | Rule | Weight |
|---|---|---|---|
IDX001 | indexability | Final response is HTTP 200 | 5 |
IDX002 | indexability | At most one redirect before the page | 1 |
IDX003 | indexability | Page is not marked noindex | 5 |
IDX004 | indexability | Exactly one absolute canonical URL | 2 |
IDX005 | indexability | Canonical points to this page | 1 |
IDX006 | indexability | robots.txt allows crawling this URL | 5 |
IDX007 | indexability | robots.txt declares a sitemap | 1 |
IDX008 | indexability | Response is HTML | 3 |
CNT001 | content | Page has a title | 4 |
CNT002 | content | Title length 10-60 characters | 2 |
CNT003 | content | Page has a meta description | 2 |
CNT004 | content | Meta description length 50-160 characters | 1 |
CNT005 | content | Exactly one H1 | 2 |
CNT006 | content | Heading levels are not skipped | 1 |
CNT007 | content | At least 200 words of visible text | 1 |
CNT008 | content | declares lang | 1 |
CNT009 | content | Mobile viewport meta tag | 2 |
CNT010 | content | Character encoding declared | 1 |
LNK001 | links | Page links to other pages on the site | 2 |
LNK002 | links | Every link has an accessible name | 1 |
LNK003 | links | No broken links among those checked | 3 |
LNK004 | links | No placeholder links (# or javascript:) | 1 |
IMG001 | media | Every image has an alt attribute | 2 |
IMG002 | media | Images declare width and height | 1 |
SD001 | structured data | JSON-LD structured data present | 1 |
SD002 | structured data | All JSON-LD blocks parse | 3 |
SD003 | structured data | JSON-LD nodes have schema.org @context and @type | 2 |
SD004 | structured data | Open Graph title, description and image | 1 |
SD005 | structured data | Twitter card declared | 1 |
INT001 | international | hreflang values and URLs are valid | 2 |
INT002 | international | hreflang set includes this page | 2 |
INT003 | international | hreflang set has x-default | 1 |
SEC001 | security | Final URL uses HTTPS | 5 |
SEC002 | security | HTTP redirects to HTTPS | 1 |
SEC003 | security | Strict-Transport-Security header | 2 |
SEC004 | security | No mixed content | 3 |
SEC005 | security | X-Content-Type-Options: nosniff | 1 |
SEC006 | security | Content-Security-Policy header | 1 |
SEC007 | security | TLS certificate valid for 21+ more days | 3 |
PRF001 | performance | HTML document under 500 KB | 2 |
PRF002 | performance | HTML is compressed in transit | 2 |
PRF003 | performance | At most 2 render-blocking scripts in | 2 |
PRF004 | performance | Server answered within 800 ms | 1 |
PRF005 | performance | HTML response has Cache-Control | 1 |
PRF004 (response time) and SEC007 (certificate days left) depend on when the page is fetched and are excluded
from checksSha256.
What it does not do
- It does not crawl a site. It audits the URLs you give and, if you give a sitemap, up to
maxPagessame-host pages from it. - It does not render JavaScript, measure Core Web Vitals (LCP, CLS, INP) or take screenshots.
- It does not log in, send cookies or fill forms; pages behind authentication are audited as an anonymous visitor sees them.
- It does not report rankings, keywords, backlinks or traffic.
- It does not change your site: every request is read-only (GET for the page and
robots.txt; HEAD for links, or a one-byte ranged GET when a server refuses HEAD).
Limits
- Server HTML only. Content added by JavaScript is not seen; neither are lab metrics such as LCP or CLS.
robots.txtis evaluated per RFC 9309 forGooglebotand*(wildcards,$, longest match, allow wins ties).- At most 100 pages per run, 5 MB of HTML per page, 5 redirects.
- Requests to private, loopback, link-local and reserved addresses are refused, including after redirects.
Schemas and permissions
The input and every output item are described by JSON schemas that ship with the Actor (.actor/input_schema.json,
.actor/dataset_schema.json). The Actor runs with Apify's limited permissions: it accesses only its own run's
storage and the input you give it.