Bulk URL Status and Redirect Chain Checker
Pricing
from $1.00 / 1,000 results
Bulk URL Status and Redirect Chain Checker
Checks the HTTP status and redirect chain of each URL and flags loops. Pay per checked URL. robots.txt blocks, 401, 403, 429, login redirects and marked CAPTCHA answers are listed, not charged.
Pricing
from $1.00 / 1,000 results
Rating
0.0
(0)
Developer
Derek Derringer
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
2 days ago
Last modified
Categories
Share
What it does
This Actor checks the HTTP status and redirect chain of each URL in your list. For every URL it records each answer from the start address to the final one, the number of redirects, any loop and the response time. It reads each site's robots.txt first, sends HEAD requests and never reads a page body. Every URL it skips is listed with the reason and is not charged. It never logs in. It stops at login redirects and marked CAPTCHA answers and never tries to get past them.
How to use it
- Open the Actor in Apify Console.
- The form opens with
https://docs.apify.comin URLs to check as a sample. Replace it with your own URLs, one per line. If you keep the sample, it is checked and charged. - Change Maximum URLs, Request timeout or Maximum redirects if the defaults do not suit you.
- Click Start.
- When the run ends, open the Output tab for the checked URLs, the run report and the skipped URLs.
Input
| Field | What it does | Default | Limits |
|---|---|---|---|
URLs to check (urls) | The URLs to check, one per line. A domain name with no scheme gets https:// added. The scheme and host are lower-cased and any # part is removed. The rest is kept as written, then duplicates are removed | Required. Prefilled with https://docs.apify.com | http and https only, up to 2,000 characters. Other entries are listed in SKIPPED and not charged (see Limits) |
Maximum URLs (maxUrls) | The most URLs one run will check. The rest are listed in SKIPPED as over_max_urls, never requested and not charged | 1,000 | 1 to 10,000 |
Request timeout (requestTimeoutSecs) | How long one request may take to answer with its status and headers. A URL that does not answer in time is listed in SKIPPED as timeout and not charged | 15 seconds | 3 to 60 seconds |
Maximum redirects (maxHops) | The most redirects followed for one URL. A chain that keeps redirecting stops there and is marked max_hops_reached. 0 reports only the first answer | 10 | 0 to 20 |
Output
Each checked URL adds one item to the run's dataset. This real item is from a local test run against docs.apify.com:
{"startUrl": "https://docs.apify.com/platform/limits","finalUrl": "https://docs.apify.com/account/limits","finalStatus": 200,"hops": [{"url": "https://docs.apify.com/platform/limits", "status": 301},{"url": "https://docs.apify.com/limits", "status": 302},{"url": "https://docs.apify.com/account/limits", "status": 200}],"hopCount": 2,"loop": false,"stopReason": null,"redirectNotFollowed": null,"responseTimeMs": 346,"checkedAt": "2026-10-15T02:20:57+00:00"}
| Field | What it holds |
|---|---|
startUrl | The address from your list, with https:// added where needed and any # part removed |
finalUrl | The last address requested in the chain |
finalStatus | The HTTP status of the last answer. When a chain stops early, this is the last redirect status |
hops | Every answer in order, from the start URL to the final URL, each with url and status |
hopCount | How many of those answers were redirects (301, 302, 303, 307 or 308) |
loop | true when a redirect points back to an address already in the chain. In a local test, a URL that redirected to a second address and back gave true, with stopReason loop and the start address in redirectNotFollowed |
stopReason | null when the chain ended normally. Otherwise loop, max_hops_reached, redirect_without_location, redirect_to_unsupported_address (such as an ftp address), redirect_to_invalid_address or redirect_target_too_long |
redirectNotFollowed | Where the last redirect pointed, for loop, max_hops_reached and redirect_to_unsupported_address. Otherwise null |
responseTimeMs | For each answer in hops, the milliseconds from sending the request to getting its status and headers, added up. robots.txt reads and Crawl-delay waits are not included |
checkedAt | When the check ended, in UTC |
Items arrive in the order the checks finish, not in your list order, because up to 5 sites are checked at once. The dataset has two views, Status and redirects and Full redirect chains.
Pricing
This Actor is priced per event, with two charges:
- Actor start: Apify's automatic start event, at Apify's default price.
- URL checked: one charge for each checked URL written to the dataset.
Price per checked URL: $1.00 per 1,000 URLs, which is $0.001 each.
A checked URL is charged whatever its final status, so a 404 or a 500 counts, and so does a chain that loops or stops at Maximum redirects.
Never charged: everything listed in SKIPPED. That covers URLs and sites skipped because of robots.txt, final 401 and 403 answers, 429 answers, login redirects, marked CAPTCHA answers, invalid, malformed and duplicate URLs, unreachable sites, timeouts, network errors and anything past Maximum URLs. A 401 or 403 entry keeps its full chain and status, so you still see the answer. REPORT, SKIPPED and STATE are not charged either.
If you set a maximum cost for the run, the Actor checks before each URL starts that one more charge still fits, counting the URLs already being checked. When none fits, it starts no more checks, lists the rest in SKIPPED as spending_limit_reached, writes REPORT saying the spending limit was reached and ends the run without an error.
If Apify restarts the run on another server, URLs already in the run's dataset are not checked or charged again. A new run starts from the beginning and charges again.
robots.txt and site rules
The robots.txt check is always on, and no input turns it off. Before any other request to a site (scheme, host and port), the Actor reads its robots.txt and follows the group for url-status-redirect-checker, otherwise the * group, for at most 24 hours. Every new site in a redirect chain gets the same check first. Every skip below is listed in SKIPPED with the reason and any chain seen so far, and is not charged.
| Case | What the Actor does |
|---|---|
| robots.txt disallows a URL, or an address its chain redirects to | Never requests it (robots_disallowed). SKIPPED shows the rule and, after a redirect, the address not requested |
Disallow: / for this Actor, even with Allow lines | Skips every URL on that site (robots_disallow_all) |
| robots.txt answers 401, 403, 429 or a server error, or cannot be reached or read | Skips every URL on that site |
| robots.txt answers another 4xx, such as 404 | Treats the site as having no rules |
| robots.txt sets a Crawl-delay | Waits that long between requests to that site, counted from the end of the last one |
| The Crawl-delay is over 30 seconds | Skips the site (crawl_delay_too_long) |
| How each address is asked | A HEAD request, on every hop. Only when HEAD is refused (405, 501 or a reset connection) is one GET sent instead, and it is closed as soon as the status and headers arrive. The body is never read |
| Requests to one site | One at a time. Up to 5 sites from your list are checked at once |
| The answer is 401, 403 or 429 | Stops the chain there (http_401, http_403 or http_429), keeps the chain and status, and never retries |
| A redirect to a login address (a path or host name with words such as login, signin, auth or sso), or to an address with a user name or password | Stops before requesting it (login_redirect) |
| A marked CAPTCHA answer: a response header that marks a bot check or CAPTCHA, or a redirect to a CAPTCHA address | Stops there (captcha). A CAPTCHA address is never requested |
| On Apify, a site on a private or local network address | Refused before any request (not_public_address) |
The user agent is url-status-redirect-checker/0.1 (Apify Actor), and it never borrows another crawler's name. No cookies are stored or sent and no proxy is used. There is no cookie, header, login, proxy or user agent input.
Your responsibility
You are responsible for submitting only URLs you are allowed to access and for following each website's terms of use. The Actor checks robots.txt for you, but it cannot read or judge a site's terms.
Run records
Three records in the run's key-value store, never charged:
| Record | What it holds |
|---|---|
| REPORT | Why the run stopped, in words, such as "all URLs were processed" or "the spending limit set for this run was reached". Start and finish times, duration, the user agent, the settings used and any input problems. Counts: URLs in the input, accepted, checked, checked before a restart, charged and skipped, skips by reason, final statuses and stop reasons. Whether a final 401 or 403 is charged (false). The robots.txt result for each site, up to 500 sites. Requests: total, robots.txt, HEAD, GET and GET after a refused HEAD, sites contacted, whether robots.txt was the first request on every site, and the most requests at once on one site and across sites. Storage writes. If you abort the run, checks in progress stop and are listed with the rest as run_aborted. If an unexpected error stops the run, unchecked URLs are listed as run_stopped_by_error. REPORT and SKIPPED are written either way |
| SKIPPED | count and items. Each item has the url, a reason code and a detail in words. Items from the checks also have listIndex, the URL's place among the accepted URLs counting from 0. A URL stopped part way also has lastStatus, the hops seen and stoppedAtUrl, the address it pointed to that was not requested. Problems found in your list come first, then the rest in list order. Reason codes: invalid_url, malformed_url, duplicate, over_max_urls, robots_disallowed, robots_disallow_all, robots_server_error, robots_unreachable, robots_forbidden, robots_rate_limited, not_public_address, crawl_delay_too_long, not_web_url, http_401, http_403, http_429, captcha, login_redirect, timeout, network_error, unexpected_error, spending_limit_reached, run_aborted, run_stopped_by_error |
| STATE | A progress record: a hash of your URL list, the list positions already handled, the skipped entries, counts, whether the run finished, and when it was saved. Written about once a minute and at the end |
Limits
| Limit | Value |
|---|---|
| URLs | Maximum URLs, 1 to 10,000, 1,000 by default, counted after bad entries and duplicates are removed |
| Redirects | Maximum redirects, 0 to 20, 10 by default. With 10, a chain holds at most 11 answers. A chain cut there is a charged result marked max_hops_reached |
| Timeouts | Request timeout, 3 to 60 seconds, 15 by default, for each request. A GET sent after a refused HEAD gets its own. robots.txt reads have a fixed timeout of 15 seconds per step and 20 seconds in all |
| Addresses | http and https only, up to 2,000 characters, with a host name, no spaces and no user name or password. Anything else is listed as invalid_url. An address the HTTP client cannot send, such as one with a DEL character in the path, full-width letters in the host name or a zero-width space right after the host, is listed as malformed_url. Neither is requested or charged. A zero-width space later in the path is percent-encoded and sent, and that URL is checked like any other |
| Redirect targets | A redirect with no Location header, or to a non-web address such as ftp, to an address the HTTP client cannot send, or to one longer than 8,192 characters, ends the chain as a charged result with that stopReason |
| Login and CAPTCHA pages | Found only from statuses, headers and redirect addresses, because the body is never read. A login or CAPTCHA page that answers 200 with no marker header, at an address with no login or CAPTCHA words in it, is reported as a 200 result like any other page |
| Input values | A number outside its range is set to the nearest limit, and one that is not a number gets the default. REPORT notes either |
| Memory | 256 MB, set as the minimum, maximum and default |