SEO & ads intelligence · Developer tools
Bulk URL Status & Broken Link Checker
Check hundreds of URLs at once for status code, full redirect chain, response time, and security headers — spot broken links and redirect loops in one dataset, without ever downloading page bodies.
Free Apify credit covers a first run. No credit card to try.
What this Actor scrapes
Point this at any list of URLs — a sitemap export, a link audit spreadsheet, an affiliate feed, a migration checklist — and get back exactly what a real visitor's browser would see for each one: the final status code, the complete redirect chain (every 301/302/307/308 hop in order), response time, and the security headers that show up in an SEO or infra audit. There's no target API to key against and no site-specific logic — any http:// or https:// URL is a valid input. Nothing gets crawled beyond the URLs you supply, and the page body is never downloaded — this is a status/health check, not a scraper.
What we handle for you
- 🌐 Every check runs through Apify Proxy — a clean vantage point for the request, not your own office or CI-runner IP.
- 🕵️ Real-browser TLS fingerprint — requests go out via
curl-cffiChrome impersonation, so a HEAD or GET from us doesn't look like a bare Python script to the target. - 🧱 Per-URL fault isolation — a DNS failure, timeout, or SSL error on one URL never takes the batch down; every URL gets its own row, always.
- 🧊 Clean, typed dataset rows — Pydantic-validated, one consistent shape whether the URL succeeded or failed, ready for JSON/CSV/Excel export.
- ⏱️ Concurrency and timeout you control — bounded in-flight requests and a per-request timeout mean one slow host can't stall the whole run.
- 💰 Pay only for delivered rows — one flat start fee, then a small per-URL charge whether that URL turned out healthy or broken (a recorded failure is still a delivered result).
Use cases
- SEO audits — find broken internal and external links across a site before Google does.
- Site-migration QA — confirm every old URL 301s to the right new one, not a 404 or a redirect loop.
- Affiliate-link health monitoring — catch dead or redirected affiliate URLs before they cost you commission.
- Uptime and redirect-chain spot checks — verify a domain move or CDN change resolved the way you expect.
- Sitemap link validation — run a sitemap's URL list through in bulk and get one row per entry.
Input
Paste this into the Apify Console, or send it as the run input over the API. Proxy settings are on by default; you rarely need to touch them.
| Field | Type | Required | What it does |
|---|---|---|---|
urls | array | yes | The URLs to check, one per line. Must be http:// or https://. Deduplicated automatically. |
followRedirects | boolean | no | When true, chase the redirect chain (up to 20 hops) and report the final destination. When false, report only the first hop and its Location header. |
timeoutSecs | integer | no | Timeout applied to every request (HEAD, GET fallback, and each redirect hop). |
maxConcurrency | integer | no | Maximum number of URLs checked in flight at once. |
maxUrls | integer | no | Hard cap on accepted input URLs after deduplication. The run fails input validation (no charge) if exceeded. |
{
"urls": [
"https://httpbin.org/status/200",
"https://httpbin.org/redirect/2",
"https://httpbin.org/status/404",
"https://this-domain-does-not-exist-devilscrapes-qa.invalid"
],
"followRedirects": true,
"timeoutSecs": 15,
"maxConcurrency": 10,
"maxUrls": 750,
"proxyConfiguration": {
"useApifyProxy": true
}
} Output
One row per result, schema-validated before it is written. Export JSON, CSV, Excel or XML from the run, or read it over the API.
input_urlfinal_urlfinal_status_coderedirect_chainredirect_countresponse_time_mscontent_typecontent_lengthserveris_brokenerror_classsecurity_headers
{
"input_url": "http://example.com",
"final_url": "https://example.com/",
"final_status_code": 200,
"redirect_chain": [
{
"url": "http://example.com",
"status_code": 301
},
{
"url": "https://example.com",
"status_code": 301
}
],
"redirect_count": 2,
"response_time_ms": 342,
"content_type": "text/html; charset=UTF-8",
"content_length": 1256,
"server": "ECS (nyb/1D2A)",
"is_broken": false,
"error_class": null,
"security_headers": {
"strict_transport_security": "max-age=31536000",
"x_frame_options": null,
"content_security_policy": null
}
} Pricing
| Event | Price | When |
|---|---|---|
| Actor start | $0.20 | Once per run, covers warm-up and proxy session setup. |
| URL checked | $0.0020 | Per result written to the dataset. |
You pay only for results that land. Cap any run with maxTotalChargeUsd. See pricing & billing for worked examples.
Limitations
- No response-body parsing — we report status, redirects, timing, and headers, never the page content itself. Point a different tool at the ones that come back healthy if you need HTML extraction.
- No auth, session, or cookie-jar support — this checks the public, unauthenticated view of a URL. Gated or login-only pages will report whatever an anonymous request sees.
- No historical diffing across runs — every run is a stateless snapshot. Schedule the Actor and compare exports yourself if you want a change-over-time view.
maxUrlsis a hard cap (default 750, max 10 000) — an oversized list fails input validation for free rather than getting silently truncated. Split large lists across runs.- One attempt per URL, by design — we report what a real visitor sees right now, not a status we retried our way past. A transient 429, 503, or timeout is the deliverable here, not noise to smooth over, so it shows up in your dataset instead of getting hidden behind a retry loop.
FAQ
Does this download the page content?
Will a broken link fail my whole run?
Do you retry rate-limited or 5xx responses?
What counts as "broken"?
is_broken: true and, for transport failures, a specific error_class.Ready to run it?
Open the listing on Apify, paste the input above, and watch rows land. If it ever breaks, it is our problem before it is yours.
Related Actors