Enter a URL to trace its redirect chain
Paste a URL and see every redirect it goes through before a page finally loads: the status code of each hop (301, 302, 307, 308 or an HTML meta refresh), where it points, and how long it took. The check runs from our edge, not from your browser, because a browser follows redirects silently and never exposes the intermediate responses. Use it to find chains, loops and redirects that end on a 404.
Enter a URL to trace its redirect chain
Each row is one request. A 3xx row with a Location is a hop; the last row is the page that answered with content or an error. One hop is normal, for example http to https. Two or more means the rules are chained and could be collapsed into a single redirect straight to the final URL, which saves a round trip for every visitor and keeps the full ranking signal in one jump.
Redirects that depend on cookies, login state, device or country will show their default path, because the request is sent from Cloudflare's network with a generic user agent and no cookies. JavaScript redirects (window.location in a script) are not followed either, only HTTP headers and meta refresh tags.
# -I = HEAD, -L = follow, -s = quiet. Prints every hop's status line and Location.
curl -sIL http://github.com | grep -iE "^(HTTP|location)"
# HTTP/1.1 301 Moved Permanently
# location: https://github.com/
# HTTP/2 200 Add -A "Mozilla/5.0" if a site answers curl differently from a browser, and --max-redirs 10 to stop a loop.
async function traceRedirects(url, max = 10) {
const hops = [];
for (let i = 0; i < max; i++) {
const res = await fetch(url, { redirect: "manual" });
const location = res.headers.get("location");
hops.push({ url, status: res.status, location });
if (res.status < 300 || res.status >= 400 || !location) break;
url = new URL(location, url).href; // Location may be relative
}
return hops;
}
console.log(await traceRedirects("http://github.com")); redirect: "manual" works in Node.js and on servers. In a browser it returns an opaque response with no status or headers, which is why this tool runs on the edge.
import requests
r = requests.get("http://github.com", allow_redirects=True, timeout=10)
for hop in r.history:
print(hop.status_code, hop.url, "->", hop.headers.get("Location"))
print(r.status_code, r.url)
# 301 http://github.com/ -> https://github.com/
# 200 https://github.com/ This tool follows the specifications below. Read them when you need the exact normative wording, for example to settle an edge case between two implementations.
Every hop between the URL you enter and the page that finally returns content. For each response you get the status code (301, 302, 307, 308 or a meta refresh), the Location header it points to, the response time and the server header. The chain ends at the first non-redirect response or after ten hops.
Browsers follow redirects silently and only show the final address. Typical chains are http to https, then non-www to www, then a trailing slash fix. Each is a separate round trip that slows the page and leaks a little ranking signal, so collapse them into one redirect where you can.
Yes. If a hop points back to a URL already in the chain, the tool stops and flags the loop. A browser would show ERR_TOO_MANY_REDIRECTS for the same URL.
Some sites redirect based on country, language, device or cookies. The check runs from Cloudflare's network with a generic user agent and no cookies, so a site that sends logged-in users or mobile visitors elsewhere will show its default path here.
Use 301 for a permanent move, so search engines transfer the ranking and browsers cache it, and 302 for a temporary one. Use 308 and 307 when the request method must be preserved, for example on API endpoints that receive POST. The redirect rule generator writes the server config for all four.
Fix a chain by writing the rule with the redirect rule generator, look up what each code means in the HTTP status code list, or confirm the final host is up with the website down checker.