SEO Audit & Broken Link Checker: Site Crawler avatar

SEO Audit & Broken Link Checker: Site Crawler

Pricing

$2.00 / 1,000 page auditeds

Go to Apify Store
SEO Audit & Broken Link Checker: Site Crawler

SEO Audit & Broken Link Checker: Site Crawler

Crawl a website and get a per-page SEO audit plus every broken link, redirect and blocked URL: titles, meta, H1, alt, canonicals, duplicates, sitemap & robots checks.

Pricing

$2.00 / 1,000 page auditeds

Rating

0.0

(0)

Developer

vantum

vantum

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

5 days ago

Last modified

Security

Limited permissions

Share

SEO Audit & Broken Link Checker

Crawl any website and get, in one run:

  • a technical SEO audit of every page: title, meta description, H1, image alt text, canonical, robots/noindex, hreflang, lang, viewport, thin and duplicate content, mixed content, slow and heavy pages, each with a 0–100 score;
  • every broken link, broken image and broken script/stylesheet, with the pages that link to it and the anchor text;
  • every internal redirect and redirect chain, so you can update links to point at the final URL;
  • a site summary: issues ranked by how many pages they affect, duplicate title/description/content groups, sitemap quality (broken, redirecting, noindex and orphan URLs), robots.txt status and HTTP status codes.

Plain HTTP and no browser, so it is fast and cheap. $2 per 1,000 audited pages. Link checks, link rows, summaries, dry runs and failed sites are free.

Why this one

This ActorTypical SEO audit actorsTypical broken-link checkers
Price$0.002 per page, no start fee$0.005–$0.04 per page$0.001 per link checked, often plus a start fee
Per-page SEO audit (44 checks)✅✅❌
Broken links with source page and anchor text✅ freepartial✅ (paid per link)
External links, images, scripts and CSS checked✅ freerarelysome
HEAD first, then GET fallback (no false "405 broken")✅❌some
403/429/999 reported as blocked, not broken✅❌❌
Canonical target validated (broken, redirect, noindex)✅❌❌
Sitemap quality: broken, redirecting, noindex and orphan URLs✅rarely❌
Duplicate titles, descriptions and content, grouped✅partial❌
Respects robots.txt✅ (option)variesvaries
Free dry run with a cost estimate✅❌❌
Stops safely before the run timeout and still reports✅❌❌

Quick start

  1. Enter one or more websites, e.g. https://crawlee.dev.
  2. Set Max pages per site (default 100). Not sure how big the site is? Tick Dry run first: it is free and tells you how many pages the sitemap lists and what a full audit would cost.
  3. Run. Open the Pages overview, Broken links & redirects and Site summary tabs in the output.
{
"startUrls": [{ "url": "https://crawlee.dev" }],
"maxPagesPerSite": 200,
"checkExternalLinks": true,
"linkRows": "brokenAndInternalRedirects"
}

How it crawls

  • It starts at your URL, reads robots.txt and the sitemaps (including sitemap indexes and .xml.gz files), then follows links breadth-first: closest pages first.
  • It stays on the same site. www. and the bare domain count as one site. Subdomains are optional.
  • It audits HTML pages that answer 200. Redirecting, broken and non-HTML URLs are recorded as link results and are not charged.
  • Tracking parameters (utm_*, gclid, fbclid…) are always stripped. Ignore query strings also merges ?sort= style variants.
  • Only crawl / never crawl patterns take plain text or /regex/.
  • After crawling, it checks every unique URL found on the audited pages once. Canonical targets go first, then internal links, internal images/scripts/CSS, external links and external resources. It tries HEAD and falls back to GET when a server mishandles HEAD. It retries 429/503, honouring Retry-After.
  • If the run is about to time out, it stops crawling early and still writes every row and the summary.

Not covered: pages that render their content only with JavaScript. These are flagged JS_RENDERED so you know. Also not covered: Core Web Vitals, and pages behind a login.

Output

All rows go to one dataset. rowType tells them apart, and the tabs filter the columns.

page row (charged, one per audited page)

{
"rowType": "page",
"url": "https://crawlee.dev/blog/page/2",
"statusCode": 200,
"score": 86,
"errors": 0, "warnings": 2, "notices": 2,
"issueCodes": ["TITLE_TOO_LONG", "TITLE_DUPLICATE", "META_DESCRIPTION_DUPLICATE", "CANONICAL_MISSING"],
"issues": [{ "code": "TITLE_TOO_LONG", "severity": "warning", "message": "Title is 108 characters (over 60); search engines will cut it.", "count": 108 }],
"title": "Crawlee Blog - learn how to build better scrapers | Crawlee …",
"titleLength": 108,
"metaDescriptionLength": 52,
"h1": "Crawlee Blog",
"h1Count": 1,
"canonical": null,
"canonicalStatus": "missing",
"indexable": true,
"inlinks": 3,
"inSitemap": true,
"brokenLinkCount": 0,
"brokenLinks": null,
"linksToRedirects": 0,
"imagesMissingAlt": 0,
"wordCount": 1210,
"responseTimeMs": 182
}

Page rows also include: finalUrl, redirectChain, depth, foundOn, notIndexableReason, metaDescription, h2Count, metaRobots, xRobotsTag, lang, hreflang, images, imagesMissingAltSample, internalLinks, externalLinks, structuredDataTypes, ogTitle, ogImage, htmlBytes, contentType and crawledAt.

{
"rowType": "link",
"url": "https://crawlee.dev/blog/img/lukasp.webp",
"state": "broken",
"statusCode": 404,
"internal": true,
"kind": "img",
"linkedFromCount": 1,
"linkedFrom": [{ "page": "https://crawlee.dev/blog/…", "anchor": null, "kind": "img" }],
"checkMethod": "GET"
}

state takes one of these values:

  • broken: 4xx/5xx, a redirect loop or too many redirects.
  • error: DNS, connection, SSL or timeout failure.
  • blocked: 401/403/429/999, meaning the server refused the checker. LinkedIn, Stack Overflow and Cloudflare-protected sites often do this, so check these by hand; they are not counted as broken.
  • redirect: the URL works but redirects; the row shows the full redirectChain.

Link rows decides which states get rows.

summary row (free, one per site)

The summary row holds:

  • pagesAudited, averageScore, pagesWithErrors, nonIndexablePages;
  • brokenInternalUrls, brokenExternalUrls, blockedUrls, redirectingInternalUrls, linksChecked, urlsDiscovered;
  • issues: every issue code with the number of pages it affects, worst first;
  • duplicateTitles, duplicateMetaDescriptions, duplicateContent: groups of pages;
  • sitemaps: URLs listed, plus broken, redirecting, noindex and orphan URLs (in the sitemap but linked from no audited page, checked only when the whole site was crawled);
  • robotsTxt, statusCodes, stoppedBy (maxPages, costLimit, timeout or null).

The same summaries are saved as JSON in the key-value store record RUN_SUMMARY.

Issue codes

Score = 100 − 10 per error − 4 per warning − 1 per notice (minimum 0).

CodeSeverityMeaning
TITLE_MISSINGerrorThe page has no <title>.
TITLE_EMPTYerrorThe <title> is empty.
TITLE_MULTIPLEwarningThe page has N <title> tags.
TITLE_TOO_LONGwarningTitle is N characters (over 60/160); search engines will cut it.
TITLE_TOO_SHORTnoticeTitle is only N characters (under 30/70).
TITLE_DUPLICATEwarningSame title as N other page(s).
META_DESCRIPTION_MISSINGwarningNo meta description.
META_DESCRIPTION_EMPTYwarningThe meta description is empty.
META_DESCRIPTION_MULTIPLEwarningThe page has N meta descriptions.
META_DESCRIPTION_TOO_LONGnoticeMeta description is N characters (over 60/160).
META_DESCRIPTION_TOO_SHORTnoticeMeta description is only N characters (under 30/70).
META_DESCRIPTION_DUPLICATEnoticeSame meta description as N other page(s).
H1_MISSINGwarningNo <h1> heading.
H1_EMPTYwarningThe <h1> is empty.
H1_MULTIPLEnoticeN <h1> headings.
IMG_ALT_MISSINGwarningN image(s) without an alt attribute.
CANONICAL_MISSINGnoticeNo canonical link.
CANONICAL_MULTIPLEerrorN canonical links with different targets; search engines may ignore all of them.
CANONICAL_RELATIVEnoticeCanonical uses a relative URL (…).
CANONICAL_INVALIDerrorCanonical is not a valid http(s) URL (…).
CANONICAL_OTHER_DOMAINwarningCanonical points to another domain (…).
CANONICAL_TO_OTHER_PAGEnoticeCanonical points to a different page (…); this page will not be indexed itself.
CANONICAL_INSECUREwarningCanonical uses http:// on an https:// page.
CANONICAL_TARGET_BROKENerrorCanonical target returns ….
CANONICAL_TARGET_REDIRECTSwarningCanonical target redirects to ….
CANONICAL_TARGET_NOINDEXerrorCanonical target is noindex.
CANONICAL_ON_NOINDEXnoticePage is noindex but also has a canonical to another page (mixed signals).
NOINDEXnoticePage is noindex (…).
NOFOLLOWnoticePage is nofollow (…).
BROKEN_LINKSerrorN broken link(s) on this page.
BROKEN_IMAGESwarningN broken image(s) on this page.
BROKEN_RESOURCESwarningN broken script, stylesheet or frame URL(s) on this page.
LINKS_TO_REDIRECTSnoticeN internal link(s) go through a redirect.
PAGE_REDIRECTEDnoticeThe URL redirects (…).
REDIRECT_CHAINwarningThe URL goes through N redirects.
LANG_MISSINGnoticeNo lang attribute on <html>.
VIEWPORT_MISSINGwarningNo mobile viewport meta tag.
THIN_CONTENTnoticeOnly N words of text.
CONTENT_DUPLICATEwarningExactly the same text as N other page(s).
MIXED_CONTENTwarningN resource(s) loaded over http:// on an https:// page.
SLOW_RESPONSEnoticeServer took N ms to respond.
LARGE_PAGEnoticeHTML is N KB.
JS_RENDEREDnoticeVery little text in the HTML; the page is probably rendered by JavaScript, which this audit does not run.
HREFLANG_INVALIDwarningInvalid hreflang value(s): ….

Thresholds: title 30–60 characters, meta description 70–160, thin content under 200 words, slow over 3 s, large HTML over 3 MB. Pages that are noindex or canonicalised elsewhere are left out of duplicate checks.

Pricing

$0.002 per audited page saved ($2 per 1,000). Nothing else is charged:

  • link checks and link rows: free, however many;
  • summary rows and the RUN_SUMMARY record: free;
  • dry runs: free;
  • sites that fail to open: free;
  • broken, redirecting and non-HTML URLs: free (they are not audited pages);
  • with Save only pages with issues, pages without issues: free.

Set a maximum cost per run in Apify and the Actor stops before going over it. The summary then shows stoppedBy: "costLimit".

Examples: a 50-page brochure site costs $0.10. A 1,000-page blog costs $2. A 10,000-page shop audited on 2,000 sample pages costs $4.

Tips

  • Big sites: run a dry run, then audit a sample with Max pages per site and an Only crawl pattern per section (e.g. /blog/).
  • Shops and faceted navigation: tick Ignore query strings. Exclude ?filter=, /tag/ and similar.
  • Fragile servers: lower Max parallel requests to 2–3.
  • Only want broken links? Set Link rows to "Broken links only" and Save only pages with issues. Use the Broken links & redirects tab.
  • Scheduled monitoring: schedule a weekly run and compare summary rows, or connect the dataset to Google Sheets, Slack or Zapier via Apify integrations.

FAQ

Does it render JavaScript? No. It reads the HTML that servers send, which is what most search-engine first passes see. Pages whose text appears only after JavaScript are flagged JS_RENDERED.

Why is a link "blocked" rather than broken? Some sites (LinkedIn returns 999, Stack Overflow 403, many Cloudflare sites 403/429) refuse automated requests even though the link works in a browser. Calling these broken would be wrong, so they are reported separately.

Does it obey robots.txt? Yes, by default, for internal pages. External links are checked with a single request each.

Is it legal? It requests public pages, like a search-engine crawler, at a polite concurrency. Audit sites you own or are allowed to audit.

Support

Open an issue in the Actor's Issues tab with the run ID. Feature requests are welcome.