On-Page SEO Audit - Metadata, Headings and Explained Scores avatar

On-Page SEO Audit - Metadata, Headings and Explained Scores

Pricing

$2.00 / 1,000 audited pages

Go to Apify Store
On-Page SEO Audit - Metadata, Headings and Explained Scores

On-Page SEO Audit - Metadata, Headings and Explained Scores

On-page SEO audit for supplied public URLs. Export metadata, headings, links, indexability signals and explained rule-based scores as JSON with request errors.

Pricing

$2.00 / 1,000 audited pages

Rating

0.0

(0)

Developer

Grit

Grit

Maintained by Community

Actor stats

0

Bookmarked

1

Total users

1

Monthly active users

12 days ago

Last modified

Share

On-page SEO scraper returns page metadata and a rule-based audit for supplied public URLs. On-page SEO API results include titles, descriptions, headings, links, indexability signals, scores, and errors.

Input example

{
"urls": [
"https://example.com/"
],
"maxItems": 3
}

The input keys and allowed values follow .actor/input_schema.json.

Output fields

FieldTypeExample or excerpt from sample
urlstring"https://example.com/"
finalUrlstring"https://example.com/"
statusCodeinteger200
responseTimeMsinteger297
fetchedAtstring"2026-10-05T13:05:03.966343+00:00"
titlestring"Example Domain"
titleLengthinteger14
titleCountinteger1
metaDescriptionstring or nullnull
metaDescriptionLengthinteger0
metaDescriptionCountinteger0
canonicalstring or null"https://schema.org/Product"
canonicalsarray[]
robotsMetaobject{}
xRobotsTagstring or nullnull
noindexbooleanfalse
hreflangarray[]
headingsarray[]
h1Countinteger0
imageCountinteger0
imagesWithAltinteger0
imagesWithEmptyAltinteger0
imagesMissingAltinteger0
imageAltCoverageinteger or null100
internalLinkCountinteger0
externalLinkCountinteger0
structuredDataTypesarray[]
structuredDataErrorsarray[]
openGraphobject{}
twitterobject{}
wordCountinteger25
errorstring or nullnull
scoreVersionstring"1.0"
scoreRulesarray[{"id": "title", "maximum": 15, "earned": 0, "passed": false, "reason": "Exactly one …
scoreinteger20
issuesarray[]
attemptsinteger1
redirectChainarray[]

Output example

Trimmed from sample_output.json; omitted fields remain available in the dataset.

{
"url": "https://example.com/",
"finalUrl": "https://example.com/",
"statusCode": 200,
"responseTimeMs": 297,
"fetchedAt": "2026-10-05T13:05:03.966343+00:00",
"title": "Example Domain",
"titleLength": 14,
"error": null
}

Transparent scoring: version 1.0

RuleMaximumFull-credit condition
Title15Exactly one title, 30–60 characters
Description15Exactly one description, 70–160 characters
Canonical10Exactly one canonical resolving to an absolute HTTP(S) URL
Indexability10No noindex/none detected in the inspected meta tags or X-Robots-Tag
H110Exactly one non-empty H1
Heading order5Starts with H1; adjacent headings do not skip upward by more than one level
Image alt10Non-empty alt on all images; partial points = 10 × non-empty-alt ratio; no images earns 10
Text quantity10At least 300 text tokens
Structured data5At least one JSON-LD/microdata type, without JSON-LD parse errors
Open Graph5Non-empty og:title, og:description and og:image
Twitter card5twitter:card is summary, summary_large_image, app or player

The maximum sums to 100. Image partial credit is rounded to two decimals; the other rules award their maximum or zero. scoreRules contains the point calculation and reason for each rule.

These thresholds are this Actor's checklist heuristics, not Google's ranking rules or a ranking forecast. Empty alt can be correct for a decorative image; it is reported separately and receives no non-empty-alt credit. Short pages or pages intentionally marked noindex can be correct for their purpose. Inspect the reasons before choosing changes. Response time and hreflang presence do not contribute points.

Limits and error handling

InputDefaultAllowed range
maxItems1,0001–10,000 result rows, including errors
concurrency51–20 workers
timeoutSecs305–120 seconds per fetch attempt
maxRetries20–3 retries after the initial attempt
maxResponseBytes2,000,0001,024–10,000,000 decoded bytes per page

The input list may contain at most 100,000 URL entries before deduplication. The first distinct URLs within maxItems are attempted; dataset order follows completion order. Lower concurrency when requesting many pages from one host.

Network errors and HTTP 408/429/500/502/503/504 receive exponential backoff (1, 2, 4 seconds). Numeric Retry-After is honored up to 30 seconds. There is a maximum of ten redirects per attempt. Redirect destinations are validated before requesting them. Unsupported content types and excessive responses produce error rows.

Only explicitly supplied pages and their HTTP redirects are requested. There is no site-wide crawl, browser rendering, login, CAPTCHA solving, robots.txt fetch, hreflang reciprocity check, link-status check or schema semantic validation. Public host validation rejects private IP literals and private DNS answers; DNS preflight is not connection-level IP pinning, so this is not a security gateway for untrusted hostile inputs. HTML parsing is best-effort for malformed markup, and CSS visibility is not evaluated.

FAQ

What are the output limits? maxItems caps result rows, including errors. Fetch failures, non-HTML responses, and oversized pages produce error rows.

Do I need a proxy or login? Public URLs need no login or proxy. The actor does not authenticate or render JavaScript.

How is this priced? Proposed pay per event: $0.002 per successfully audited page row. Error rows are uncharged. These are proposals in PRICING.md; the owner must configure Store billing.

How are rate limits handled? concurrency limits fetches; transient failures are retried with backoff and Retry-After.

How fresh is the data? Results reflect HTML fetched at run time. JavaScript rendered content may be absent. Scores are this actor’s checklist heuristics, not search ranking predictions; review rule reasons before acting.

Use with AI agents / MCP

After the actor is published, connect your agent to the Apify MCP server with an Apify API token. Use call-actor with the published actor identifier and the JSON input shown above. Read the returned dataset with get-dataset-items; the run response itself contains status and storage IDs, not the result rows. Alternatively, use the Apify API to start a run and read its default dataset. Keep the actor input bounded with maxItems, and inspect source links and any error fields before using results in an answer.