URL Redirect Chain Checker avatar

URL Redirect Chain Checker

Pricing

from $1.08 / 1,000 url checkeds

Go to Apify Store
URL Redirect Chain Checker

URL Redirect Chain Checker

Trace public URLs through every redirect hop and export final destinations, HTTP status codes, loops, errors, and timing for SEO migrations and link audits.

Pricing

from $1.08 / 1,000 url checkeds

Rating

0.0

(0)

Developer

Automation Lab

Automation Lab

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

2 days ago

Last modified

Categories

Share

Audit batches of public links with a URL redirect checker that records every fetched hop, HTTP status, raw and resolved Location, final destination, loop or limit state, and timing. It is designed for SEO migrations, canonical-host checks, short-link verification, and recurring link-quality exports.

The Actor makes lightweight HTTP requests instead of rendering pages. It starts with HEAD, uses a bounded GET fallback only when an origin explicitly rejects HEAD, and never stores response bodies.

What does URL Redirect Chain Checker do?

For each unique input URL, the Actor:

  1. normalizes it to an absolute HTTP(S) URL;
  2. confirms each destination resolves to public network addresses;
  3. requests the first URL with automatic redirects disabled;
  4. resolves relative Location headers exactly as a browser would;
  5. follows the chain up to your configured limit;
  6. detects repeated URLs, missing or invalid locations, request errors, and long chains;
  7. exports one typed dataset row with the complete ordered hops array.

Unlike a basic status checker, the result preserves evidence for every fetched response rather than only the first or final status.

Who is it for?

  • SEO teams validating old-to-new mappings before and after a migration.
  • Site reliability teams checking that canonical scheme and hostname redirects still work.
  • Affiliate and campaign operators expanding short links and confirming destinations.
  • Data teams exporting redirect evidence into spreadsheets, warehouses, or monitoring jobs.
  • Developers diagnosing relative redirects, redirect limits, loops, and origins that reject HEAD.

For site-wide link discovery, use Sitewide Broken Link Checker. This Actor checks only the URLs you supply and does not crawl pages to discover links.

Why use this Actor?

  • Batch up to 1,000 public URLs in one run.
  • Preserve each hop's URL, status, timing, method, and headers.
  • Resolve both absolute and relative redirect targets.
  • Export explicit complete, loop, max_redirects, invalid_redirect, and request_error states.
  • Retry only transient network and HTTP failures.
  • Avoid full browser startup and page-body downloads.
  • Block private, loopback, link-local, and credential-bearing destinations.
  • Keep one stable output row per input URL, including truthful failures.

Input parameters

FieldTypeDefaultDescription
startUrlsarrayrequiredPublic HTTP(S) URLs or domains. Request-list objects and strings are accepted.
maxItemsinteger1000Maximum unique URLs processed in input order.
maxRedirectsinteger10Redirect transitions followed per input; allowed range 0–20.
concurrencyinteger10URLs processed in parallel; allowed range 1–50.
requestTimeoutSecsinteger15Timeout for each hop request; allowed range 1–30 seconds.
maxRetriesinteger1Retries for network failures, 408/425/429, and temporary 5xx responses; allowed range 0–3.

A URL without a scheme is interpreted as HTTPS. Duplicate normalized URLs are checked once. Invalid input fails the run before requests begin.

Getting started

  1. Open the Actor in Apify Console.
  2. Add one or more URLs under URLs to check.
  3. Keep maxRedirects at 10 for a normal audit.
  4. Use lower concurrency when many URLs point to the same small origin.
  5. Click Start.
  6. Open the default dataset and select the Redirect audits view.
  7. Export JSON, CSV, Excel, XML, or another dataset format.

A small input:

{
"startUrls": [
{ "url": "http://github.com/apify" },
{ "url": "https://httpbin.org/relative-redirect/2" },
{ "url": "https://www.python.org" }
],
"maxRedirects": 10,
"concurrency": 3,
"requestTimeoutSecs": 15,
"maxRetries": 1
}

Output fields

FieldMeaning
inputUrlOriginal user-supplied value.
normalizedUrlAbsolute normalized first URL.
finalUrlLast reached URL, or repeated target for a loop.
finalStatusCodeLast fetched HTTP status; null if no response or a loop target was not fetched again.
redirectCountNumber of redirect transitions actually followed.
hasRedirectsWhether any fetched response was a redirect.
isLoopWhether the next target was already visited.
reachedMaxRedirectsWhether the configured limit stopped tracing.
stateTerminal result state.
errorCode, errorMessageStable and human-readable diagnostics.
totalTimeMsEnd-to-end elapsed time, including retries.
checkedAtISO 8601 completion time.
hopsOrdered response records with URL, status, location, timing, method, content type, and server.

All schema fields are nullable so exports remain stable when an origin omits a header or a request fails.

Output example

{
"inputUrl": "http://github.com/apify",
"normalizedUrl": "http://github.com/apify",
"finalUrl": "https://github.com/apify",
"finalStatusCode": 200,
"redirectCount": 1,
"hasRedirects": true,
"isLoop": false,
"reachedMaxRedirects": false,
"state": "complete",
"errorCode": null,
"errorMessage": null,
"totalTimeMs": 184,
"checkedAt": "2026-01-15T12:00:00.000Z",
"hops": [
{
"hop": 0,
"url": "http://github.com/apify",
"statusCode": 301,
"statusText": "Moved Permanently",
"location": "https://github.com/apify",
"resolvedLocation": "https://github.com/apify",
"responseTimeMs": 42,
"method": "HEAD",
"usedGetFallback": false,
"contentType": "text/html",
"server": "GitHub.com"
}
]
}

Header values vary by origin, so the live row may contain null contentType or server values.

Understanding result states

  • complete: a non-redirect response ended the chain.
  • loop: a redirect pointed to a URL already visited in this chain.
  • max_redirects: another redirect existed after the configured limit.
  • invalid_redirect: a redirect had no usable Location value.
  • request_error: DNS, timeout, TLS, network, or public-destination validation failed.

HTTP 4xx and 5xx responses are still valid completed HTTP evidence. Check finalStatusCode to classify them.

Redirect timing and methods

responseTimeMs measures time until response headers arrive for one recorded hop. totalTimeMs includes all hop requests, retries, DNS checks, and backoff.

The Actor first uses HEAD. If a server returns 405 or 501, it performs a bounded GET, asks for one byte, and closes the response stream after headers arrive. The hop then reports method: "GET" and usedGetFallback: true.

Safety and public URL rules

Only public HTTP and HTTPS destinations are supported. The Actor rejects:

  • loopback and unspecified addresses;
  • private IPv4 ranges;
  • link-local addresses and cloud metadata ranges;
  • private, link-local, and multicast IPv6 ranges;
  • URLs containing embedded usernames or passwords;
  • redirects that resolve to any blocked destination.

This makes the Actor unsuitable for checking intranet services. It is intentionally scoped to public web audits.

Retries, limits, and failure behavior

Transient failures may be retried with bounded exponential backoff. Stable 4xx responses, malformed URLs, invalid redirect locations, and blocked destinations are not blindly retried.

The default run timeout is five minutes. A large batch containing slow origins can reach that limit; lower maxItems, reduce retries, or split the list into multiple Tasks. Request-error rows are exported for diagnosis but are not charged as url-checked events.

How much does it cost to check URL redirect chains?

Pay-per-event pricing includes a $0.0004 start fee and one url-checked event for each non-transport-error URL audit. At the BRONZE tier, the current per-URL price is $0.0018.

Approximate BRONZE prices:

Completed URL auditsBRONZE estimate (USD)
10.0022
100.0184
1000.1804
1,0001.8004

FREE is $0.00207 per URL, SILVER is $0.001404, and GOLD/PLATINUM/DIAMOND are $0.00108. Actual billed totals depend on completed charge events and Apify's billing rules. Refunds, fraud, disputes, taxes, corrections, or clawbacks can affect final amounts.

SEO migration workflow

  1. Export your old-to-new URL map from the CMS.
  2. Put the old URLs into startUrls.
  3. Run once before cutover to capture the baseline.
  4. Schedule the same Task after deployment.
  5. Compare finalUrl, finalStatusCode, redirectCount, and state between datasets.
  6. Investigate loops, multi-hop chains, 302/307 temporary redirects, and unexpected destinations.

The Actor reports observed redirects; it does not decide whether a destination matches your private migration plan.

Recurring audits and integrations

Useful automation patterns include:

  • schedule a weekly canonical-host check;
  • send loop and request-error rows to Slack through an Apify integration;
  • export datasets to Google Sheets for migration sign-off;
  • load JSON results into BigQuery, Snowflake, or a data lake;
  • trigger a webhook after each run and compare with a prior dataset;
  • call the Actor from CI before replacing legacy routes.

Apify schedules, webhooks, dataset APIs, and integrations can automate these steps without changing Actor input.

Run with the Apify API using cURL

curl -X POST \
"https://api.apify.com/v2/acts/automation-lab~url-redirect-chain-checker/runs?token=$APIFY_TOKEN" \
-H "Content-Type: application/json" \
-d '{"startUrls":[{"url":"http://github.com/apify"}],"maxRedirects":10}'

Never commit an Apify token. Use environment variables or your secret manager.

Run with JavaScript

import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('automation-lab/url-redirect-chain-checker').call({
startUrls: [{ url: 'https://httpbin.org/relative-redirect/2' }],
maxRedirects: 10,
maxRetries: 1,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items);

Run with Python

import os
from apify_client import ApifyClient
client = ApifyClient(os.environ['APIFY_TOKEN'])
run = client.actor('automation-lab/url-redirect-chain-checker').call(run_input={
'startUrls': [{'url': 'http://www.python.org'}],
'maxRedirects': 10,
})
items = client.dataset(run['defaultDatasetId']).list_items().items
print(items)

Use with MCP and AI agents

Add the Apify MCP server to Claude Code:

claude mcp add --transport http apify \
"https://mcp.apify.com?tools=automation-lab/url-redirect-chain-checker"

Claude Desktop, Cursor, and VS Code setup

Claude Desktop, Cursor, VS Code, and other MCP-capable editor clients can use:

{
"mcpServers": {
"apify": {
"url": "https://mcp.apify.com?tools=automation-lab/url-redirect-chain-checker"
}
}
}

Example prompts:

  • “Trace these 25 old campaign URLs and list any chain longer than one redirect.”
  • “Run my saved redirect audit Task and summarize loops and terminal 404s.”
  • “Export the final destinations and timing for this URL migration list.”

Tips for reliable audits

  • Group URLs by origin and use moderate concurrency to avoid self-created rate limits.
  • Keep retries low for scheduled audits so one slow host cannot dominate runtime.
  • Use maxRedirects: 0 when you only need the first response and raw Location.
  • Compare resolvedLocation, not only the raw header, when origins use relative redirects.
  • Treat a changing server header as diagnostic context, not stable identity.
  • Run from a consistent schedule when comparing latency over time.

Limitations

  • The Actor observes server-side HTTP redirects, not JavaScript navigation, HTML meta refresh, SPA router changes, or links changed after page rendering.
  • Some origins intentionally return different results for HEAD and GET. GET fallback occurs only for explicit 405/501 responses.
  • Public DNS and origin behavior can vary by time and Apify data-center location.
  • Authentication, cookies, custom request headers, and residential proxy routing are not supported.
  • Response-body content and page titles are not downloaded or parsed.
  • A DNS record resolving to both public and private addresses is rejected for safety.

Troubleshooting

Why did I get BLOCKED_DESTINATION?

The URL or a redirect target resolved to a non-public address. Use this Actor only for publicly reachable web destinations. It cannot be configured to access an intranet or metadata service.

Why is finalStatusCode null?

No response was available for that final target. This occurs for request failures and when loop detection avoids fetching an already visited URL again. Read state, errorCode, and errorMessage.

Why did a URL use GET?

The origin returned 405 or 501 to HEAD. The Actor retried with a bounded GET and recorded usedGetFallback: true.

Why is a JavaScript redirect missing?

This is an HTTP redirect chain checker, not a browser. Client-side navigation requires rendered-page tooling such as a browser Actor.

Legality and responsible use

Check only URLs you are authorized to test. Respect website terms, rate limits, robots guidance where applicable, and relevant privacy and computer-access laws. Do not use high concurrency to disrupt services. Dataset rows can contain user-supplied URLs, so review them before sharing exports publicly.

FAQ

Does it work as a free online redirect checker?

You can run small checks under your Apify plan, but the Actor uses pay-per-event pricing rather than claiming unlimited free service. See the pricing section for exact active event prices.

Does it follow 301, 302, 303, 307, and 308 responses?

Yes. It also treats HTTP 300 and 305 with a valid Location as redirect responses and records every fetched status.

Can I export every redirect hop?

Yes. Each dataset row includes an ordered hops array. JSON preserves the full nested structure; spreadsheet formats may serialize the array into a cell.

Are failed URLs included?

Yes. Request failures produce typed request_error rows and are not charged as completed URL checks. Malformed input fails before the run begins.

Can I check more than 1,000 URLs?

Split the list across several Actor runs or saved Tasks. The per-run cap keeps runtime, memory, and load on target origins bounded.

Does the Actor cache results?

No. Every run observes the current public HTTP behavior, which is appropriate for recurring migration and link audits.