Broken Link Checker: Every Answer Billed avatar

Broken Link Checker: Every Answer Billed

Pricing

from $0.43 / 1,000 link checkeds

Go to Apify Store
Broken Link Checker: Every Answer Billed

Broken Link Checker: Every Answer Billed

Find broken links and 404s on a page, a list, a whole site or its sitemap, billed per link the site answered for. An error on HEAD is re-checked with GET, and a site that refuses the checker is never called broken. One row per link with its status, verdict and page.

Pricing

from $0.43 / 1,000 link checkeds

Rating

0.0

(0)

Developer

Pradio Actors

Pradio Actors

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

22 days ago

Last modified

Share

Broken Link Checker checks the links on a page, a site or its sitemap and returns one row per link it checks. Each row carries the link's final HTTP status, its verdict, its anchor text and the page it sat on. You paste URLs or bare domains, pick Pages, Crawl or Sitemap and press Start. What comes back is your fix list. It is $0.80 per 1,000 checked links, and a link it cannot judge costs you nothing.

Check the links on pages you just published:

{
"queries": ["https://crawler-test.com/links/broken_links_internal", "https://crawler-test.com/links/broken_links_external"],
"mode": "pages"
}
BuyerWhat they run it for
Website ownersFinding dead links before visitors and crawlers do.
SEO practitionersA technical SEO audit in one run; each row names the page and the anchor to fix.
Teams after a migration or redesignChecking that old URLs still redirect somewhere.
Content maintainersAuditing outbound links that rot quietly.

Features

  • Broken takes two answers. A HEAD error other than a refusal is re-asked with GET; a server error, again after a pause. The link is called broken on the answer that stands.
  • Three ways to point it. Pages reads what you list, Crawl follows the site's own links, Sitemap reads every page the sitemap lists.
  • A refusal is reported plainly. A site that answers 403, 429 or 999 is asked nothing more in the run. The row says it refused.
  • A challenge script is named for what it is. An Incapsula or Cloudflare gate is reported as a blocked read, never mistaken for an empty page.
  • A login wall is a working link. A link that redirects to a sign-in page resolves. The link works; the page behind it needs an account.
  • The whole redirect chain. Up to ten redirects are followed per link. Every hop lands on the row with its status.
  • Internal, external, assets. Outbound links are marked so dead ones sort apart from your own. Images, scripts and stylesheets join the check when you ask.
  • Checked once, billed once. A footer link repeated across pages is checked and billed once. Every sighting is listed on its row.
  • Every entry answered. A clean site, a page with nothing to check, an entry that was no usable URL: each gets a row saying so.
  • Polite by default. Every mode reads robots.txt first, waits its crawl delay and sends one request at a time to a site.

Why this one

Run on the same crawler-test.com page on 2026-09-16, the most-used alternative's crawl kept going past the page it was given and returned 19 rows. This one checked what it was given.

This ActorThe most-used alternative
Price per link checked$0.0008$0.001
Start fee, once per run per GB of memory$0.00005$0.00005
Redirect chain on its rows✔️ filled❌ empty on 12 rows
Reason on an error row✔️ filled❌ empty on 16 rows
  • Its pricing read on 2026-09-17 puts the most-used alternative at $0.001 for the same link check this Actor sells at $0.0008.
  • A link is called broken on the site's own answer, asked again with GET when the first read fails.

One real row from a run over the default input:

{
"url": "https://crawler-test.com/links/not_found/foo1",
"final_url": "https://crawler-test.com/links/not_found/foo1",
"status": 404, "status_text": "Not Found",
"classification": "broken", "is_broken": true,
"source_domain": "crawler-test.com",
"source_url": "https://crawler-test.com/links/broken_links_internal",
"anchor_text": "Broken Internal Link 1", "element": "a",
"all_sources": [{ "source_url": "https://crawler-test.com/links/broken_links_internal", "anchor_text": "Broken Internal Link 1", "element": "a" }],
"method": "GET",
"redirect_count": 0, "redirect_chain": [],
"content_type": "text/html", "error_message": null,
"duration_ms": 392, "checked_at": "2026-10-01T15:49:39.007Z",
"diagnosis": "not_found",
"is_external": false, "is_redirect": false, "is_slow": false,
"row_type": "ROW"
}

Every field sits on each row about a link or an entry, so dead links and healthy ones read the same. When a check cannot produce a value the cell is left empty; nothing is guessed.

FieldWhat it is
urlThe link as found, made absolute; one row per unique link.
final_urlWhere the link ended after redirects; empty when it never answered.
statusThe final HTTP code, or the failure word when the site never answered, listed below.
status_textThe server's status line, or the first error after its one re-check.
classificationThe verdict: ok, broken or error.
is_brokentrue dead, false healthy, empty unchecked.
source_urlThe page the link was first found on.
anchor_textThe link's clickable text; alt text for an asset.
elementa, img, script or link; sitemap for a listed page.
all_sourcesEvery place the link appeared, one entry per anchor.
methodHEAD or GET: which request gave the verdict.
redirect_countRedirects followed before the final answer.
redirect_chainEvery hop in order, each with its status.
content_typeThe final answer's media type.
error_messageWhy a link could not be judged; empty on a checked link.
diagnosisWhat happened in one word: not_found is the site's own 404 answer; blocked_by_site, timeout and the like.
is_externaltrue when the link points off the page's site.
is_redirecttrue when the link redirected.
is_slowtrue when the check passed the slow threshold.
duration_msCheck time in milliseconds, redirects included.
checked_atISO timestamp of the check.
source_domainHost of the page the link was found on.
row_typeROW on a checked link, ITEM_STATUS on a miss.
reasonWhy an entry was unread, or what its read found.
rowsFetchedLinks checked before deduplication and any cap.
rowsReturnedThe link rows returned; the count before the limit on a stopped run.
rowsRemainingThe checked rows the spending limit held back.

How much does it cost?

$0.80 per 1,000 links checked. You pay for every link the site answered for, healthy and broken alike. Each is billed once however its check ran.

EventPriceWhen it fires
link-checked$0.0008per checked link, charged after the row lands in your dataset
apify-actor-start$0.00005once per run, Apify's own start event
Checked linksYou pay
100$0.08
1,000$0.80
10,000$8.00

Miss rows and status rows cost you nothing. A link sighted on several pages is billed once: 50 sightings that collapse to 47 distinct links bill for 47.

To budget a sweep of your own sites, a measured run gives an estimate: on a test list of 40 sites, 80% answered and 30 produced checked-link rows, 156.6 rows each on average.

On a paid Apify plan the per-link price steps down with your tier: $0.67, $0.54 and $0.43 per 1,000 checked links on Bronze, Silver and Gold and above.

  1. Open the Actor and press Try for free.
  2. Paste your pages or sites into Pages or sites to check, one URL or bare domain per line. The three example entries it ships with can go.
  3. Pick a Mode: Pages for just those pages, Crawl for the whole site from each page, Sitemap for every page the sitemap lists.
  4. Set Max pages and Maximum items if you need to, then press Start. Rows land in your dataset as links are checked.

Worked examples

Use it to sweep a whole site for broken links.

{
"queries": ["crawler-test.com"],
"mode": "crawl",
"maxPages": 200,
"maxItems": 1000
}

Use it to audit every page a sitemap lists, the site's own links alone, as a technical SEO audit.

{
"queries": ["https://crawler-test.com/test_sitemap.xml"],
"mode": "sitemap",
"checkExternal": false
}

Or start a run over the API:

curl -X POST "https://api.apify.com/v2/acts/Pradio~broken-link-checker/runs?token=YOUR_APIFY_TOKEN" -H "Content-Type: application/json" -d "{\"queries\":[\"https://example.com/\"]}"

Input

InputDefaultWhat it does
queriesthree example pagesThe pages or sites to check; a URL or bare domain per line, at most 2,000.
modepagespages reads what you list, crawl follows the site's links, sitemap reads what the sitemap lists.
maxPages50The most pages one run reads for links, shared by crawl and sitemap.
checkExternaltrueCheck links to other sites too.
checkAssetsfalseAlso check the images, scripts and stylesheets each page loads.
slowThresholdMs5000A healthy link slower than this, in milliseconds, gets the slow diagnosis.
requestTimeoutMs15000How long one link check waits for an answer, in milliseconds.
maxRedirects10How many redirects a link check follows.
maxConcurrency8Links checked at the same time, each on a different site.
maxResultsPerQuerynoneThe most new links checked from one page read.
maxItems100The most link rows one run returns.

A site that refuses any request is left unread for the rest of the run. In Pages mode the Actor reads only what you list. Crawl stays on the site it started on. Links to disallowed pages are still checked once each while their own pages stay unread. Sitemap mode reads the entry when it is a sitemap file; a bare site is resolved through the sitemaps its robots.txt names. Raise Maximum items for a crawl; the default returns the first hundred links.

Output

Rows land in the default dataset as links are checked. The default input's three example pages return 12 link rows. Each row is one of:

Row kindWhat it means
ROWa link the site answered for; the billed row
ITEM_STATUSa link or start page it could not judge, or an entry it could not read; pushed so you see it, never billed
its status worderror (unjudgeable), bad_url, not_found (no sitemap entry, not the 404 diagnosis), blocked (reason on the row), no_broken_links, no_links_found, not_reached (your caps)
NO_RESULTSno start page produced a checkable link; one row says why
STOPPED_EARLYyour spending limit ended the run; one row says what came back and what did not
RUN_SUMMARYthe run's summary entry in the key-value store: links fetched, rows pushed, rows charged, duplicates dropped

A start page that cannot be reached is itself a row with the reason on it, and a run that finds nothing returns one row saying so.

Paste this line to give an agent this Actor through Apify's MCP server:

claude mcp add --transport http apify "https://mcp.apify.com?tools=Pradio/broken-link-checker"

Personal data

  • Rows carry link-check facts: the checked URL, its status and verdict, the redirect chain, timing and short anchor-text fragments cut to at most 200 characters. Page-body content stays out of the rows, and nothing on a row names a person.
  • Mailto, tel and javascript links are left unrequested; the addresses and numbers in them stay off your rows.
  • You choose the pages and sites; run it against sites you operate or are permitted to check.
  • Every mode honours the site's robots.txt and its crawl delay, one request at a time per site. A refused read stays terminal for the run: a blocked verdict is a report row, never retried inside the run; wait and re-run the site later.
  • A site owner can open an issue on the Issues tab naming the domain. The domain goes on the exclusion list every run reads first.

Limits

  • It reports the links it checks; repair stays with you.
  • A crawl stays on the start page's site; a site larger than Max pages is read in part, and pages robots.txt disallows are skipped.
  • Links a page builds with JavaScript after load stay unseen. Pages are fetched over plain HTTP with no browser. A page answering with a recognised script gate is reported as blocked; any other such page reads as having nothing to check.
  • Requests are logged-out and public, with cookies and login left out, one ordinary browser identity all run. A site can still answer automated traffic with a dead status it would not serve your browser. The row keeps the site's own answer.
  • A certificate the checker cannot verify comes back as an error row. So does a link still unanswered at the request timeout of 15 seconds, or a chain past 10 redirects.
  • The verdict is the HTTP answer: a page that answers 200 with its own "not found" message reads ok.
  • Across the 4,698 captured rows, anchor text filled on 87.5%; where a redirect happened, the chain carried too. Empty cells are what the page gave.
  • One run reads at most 2,000 pages and checks at most 8 links at once, each on a different site.

FAQ

Will it call a link broken that still works? It takes two answers before a link is called broken. An unhealthy HEAD answer is asked again with GET, and a server error is asked again after a pause. The answer that stands gives the verdict. A refused request, a 401, 403, 429 or 999, is reported with the reason and costs you nothing; the refusal is its answer. The case it cannot see is a page that answers 200 with its own "not found" message.

Does it plug into Zapier, Make or a schedule? Yes. Integrations connect on the Actor's Integrations tab, and a scheduled run re-checks the same pages on a timer.

Is it legal to check links this way? It reads only publicly accessible pages you name, honours robots.txt and its crawl delay, sends one request at a time to any one site and stops on a refusal. It does not claim a site's terms permit the checks; that permission stays with you. You are responsible for having the right to check the pages and sites you give it, and for how you use the rows. A site owner who objects can open an issue on the Issues tab and the site is excluded from then on.

Release notes

  • 2026-10-01: a recognised script gate reports blocked instead of no links found; requests go out under one ordinary browser identity, and a server error is asked again before a link is called broken.
  • 2026-09-17: sightings of the same link merge across entry pages, and a row's anchor text comes from the first sighting that carried it.
  • 0.1, 2026-09-16: first release: checks the links on the pages and sites you name, misses unbilled, robots.txt honoured at one request at a time per site.

Feedback

Found a problem or a missing field? Open an issue on the Issues tab; it is answered within two days. If this Actor saved you time, a review on the Store helps other buyers find it.

Not affiliated

Broken Link Checker is an independent tool, not affiliated with or endorsed by any site you point it at.