Check redirects
A single redirect is easy to reason about; three or four chained together, each added by a different team over a different year, is how sites quietly start losing search rankings and shaving seconds off load time without anyone noticing. This redirect checker API follows a URL through every hop it takes and returns the full chain, not just the final destination.
Run it online
Run this on our servers with your account. Free tools run in your browser; this one bills your KIT balance per the price above.
How redirect chains actually accumulate
Nobody sets out to build a four-hop redirect chain on purpose. It happens one migration at a time: a URL structure changes and gets a redirect, then a domain moves to https and gets another, then a CDN or campaign tool adds a tracking redirect on top, and each addition is reasonable in isolation. Years later the original link still works, but a visitor's browser is quietly making three or four extra round trips to get there, and nobody remembers why.
What the endpoint returns
Send a URL to POST /web/redirect-chain and the task follows every redirect in sequence, recording the status code, the target and the response time at each hop, all the way to the final URL that returns actual content. Instead of a single final answer, you get the entire path — useful for spotting exactly where a chain grew a hop it did not need.
Why the specific status code at each hop matters
A 301 tells search engines and browsers the move is permanent and safe to cache and follow directly next time; a 302 or 307 says the opposite, that it might change back, so it gets re-checked on every visit. A chain built entirely from temporary redirects when the moves were actually permanent means paying the latency cost of every hop, forever, on every single request.
Where this fits into ongoing maintenance
Because it is async and delivered by signed webhook, the check fits naturally into a periodic site audit, a pre-launch QA pass after a domain migration, or an SEO tooling pipeline that flags any URL taking more than one or two hops to resolve. Running it on a schedule catches chains that grow silently over time, one well-intentioned redirect at a time.
What a healthy result looks like
A single hop, or at most two, with a permanent status code is the goal for most links; anything longer is worth tracing back to its origin and collapsing into a direct redirect, since every extra hop is pure latency with no benefit to the visitor. Fixing the source link once is always cheaper than living with the extra round trip indefinitely.
What you can do with it
Post-migration link audits
Confirm old URLs after a domain or platform migration resolve in one clean hop instead of bouncing through several legacy redirects.
SEO redirect cleanup
Find chains built from temporary redirects that should be permanent, so search engines pass link value through cleanly.
Marketing link and campaign QA
Trace a shortened or tracked campaign URL through every intermediate hop before it goes into a paid ad or newsletter.
Site performance audits
Identify pages losing load time to unnecessary redirect hops that accumulated over years of incremental changes.
FAQ
What does a redirect chain checker actually show?
Every hop between the starting URL and the final destination, including the status code, target URL and response time at each step, not just the final result.
How many redirect hops is too many?
One or two hops with permanent status codes is normal; three or more is usually worth investigating, since each hop adds latency with no benefit to the visitor.
Does it distinguish permanent from temporary redirects?
Yes, the status code returned for each hop shows whether it was a permanent redirect like 301 or a temporary one like 302 or 307.
Is this free to use?
There's no free tier — free tiers get abused and slow everyone down. Access runs on a prepaid ForHosting KIT balance: top up from $10.00 (it never expires) and each request is charged at its published price, so a call with no balance returns HTTP 402. No subscription, no tokens, no invented credits, and a failed task is never charged.
How do I get the results?
By signed webhook when the task finishes, recommended for automation, or a signed link valid for 24 hours.
Am I charged for a failed check?
No. Failed tasks retry automatically up to three times and are never billed; only completed checks are charged.
What is the cost?
$0.002 per request, one price regardless of how many hops the chain contains.
Can I check redirect chains for a large list of URLs?
Yes, submit each URL as its own async task and track them by task_id, which scales naturally to auditing an entire site's link structure.
For developers — API access
Everything on this page is available programmatically. This section is for teams who want to wire it into their own systems; everyone else can just use the tool above.
API endpoint
Prefer to automate it? One authenticated POST creates the task; the result comes back by webhook or a signed link. The same capability also runs here on the web, and soon from our app, email and Telegram.
Call it from your stack
curl -X POST https://api.kit.forhosting.com/web/redirect-chain \
-H "Authorization: Bearer $KIT_KEY" \
-H "Content-Type: application/json" \
-d '{"url":"https://ejemplo.com"}'const res = await fetch("https://api.kit.forhosting.com/web/redirect-chain", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.KIT_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
"url": "https://ejemplo.com"
})
});
const { task_id } = await res.json();import os, requests
res = requests.post(
"https://api.kit.forhosting.com/web/redirect-chain",
headers={"Authorization": f"Bearer {os.environ['KIT_KEY']}"},
json={
"url": "https://ejemplo.com"
},
)
task_id = res.json()["task_id"]<?php
$res = file_get_contents("https://api.kit.forhosting.com/web/redirect-chain", false, stream_context_create([
"http" => [
"method" => "POST",
"header" => "Authorization: Bearer " . getenv("KIT_KEY") . "\r\nContent-Type: application/json",
"content" => '{"url":"https://ejemplo.com"}',
],
]));
$task = json_decode($res, true);body := bytes.NewBufferString(`{"url":"https://ejemplo.com"}`)
req, _ := http.NewRequest("POST", "https://api.kit.forhosting.com/web/redirect-chain", body)
req.Header.Set("Authorization", "Bearer "+os.Getenv("KIT_KEY"))
req.Header.Set("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)Example request
{
"url": "https://ejemplo.com"
}Example response
{
"task_id": "tsk_a1b2c3d4e5f6a1b2c3d4e5f6",
"type": "web.redirect_chain",
"status": "queued",
"_links": {
"result": "/tasks/tsk_…/result"
}
}The API is asynchronous: the call returns a task_id immediately and the result arrives by webhook. Polling is capped at 1 req/s per task.
Pricing
Published price — no tokens, no invented credits. A failed task is never charged.
Limits
timeout_sec | 30 |
max_crawl_pages | 25 |
Errors
| HTTP | Code | Meaning |
|---|---|---|
401 | unauthorized | Missing or invalid API key. |
402 | insufficient_balance | Your balance doesn't cover the task price. |
404 | unknown_type | That task type doesn't exist. |
429 | rate_limited | Too many requests. Use the webhook instead of polling. |