What testing a redirect checks
Testing a redirect means confirming three separate things: that every hop in the chain returns the status code you expect, that the chain ends at the correct final URL, and that nothing gets lost along the way. That last part is the one most people forget to check, and it is usually the one that causes the most damage later. A redirect can look completely fine to a visitor, the page loads, nothing errors, while quietly dropping the tracking parameters that were supposed to travel with the click.
There are three practical ways to do this: your browser's own developer tools, curl from a terminal, and dedicated redirect checker tools. Each one shows you something slightly different, and the browser is generally the one to trust when the other two disagree.
Method 1: browser developer tools
Open the network tab before loading the link, load it, and read the requests that appear. Every hop shows up as its own row with its own status code, and clicking into any one of them reveals the response headers, including the Location header telling the browser where to go next. This is the most reliable method. It runs the exact same rendering engine a real visitor's browser would use, JavaScript redirects and meta refreshes included, rather than simulating one.
Method 2: curl, and the flag that trips people up
From a terminal, curl -I https://your-link sends a HEAD
request and shows you the response headers, but only for the first hop.
If there is a redirect chain behind it, curl will not follow it on its
own, which leads a lot of people to conclude a link only has one redirect
when it actually has three. Add the follow flag: curl -I -L
https://your-link makes curl follow every hop and print the
headers for each one along the way, giving you the full chain from a
single command rather than one hop at a time.
Curl is faster than a browser for a quick check, and it is scriptable across a whole list of links at once, which a browser is not. What it will not show you is anything that depends on JavaScript running, so a client-side redirect will not appear in curl's output the way it would in a browser's network tab.
Method 3: an online redirect checker
A redirect checker tool wraps the same request curl makes into a page that lists the chain for you without needing a terminal. This is convenient, but it comes with the same limitation curl has: it is making its own request from its own server, not from a browser, so anything that depends on JavaScript, cookies already set in your browser, or the specific behavior of an in-app browser will not show up in the result.
| Method | Shows every hop | Shows exact status codes | Catches JS and meta refresh redirects | Needs no install |
|---|---|---|---|---|
| Browser developer tools | Yes | Yes | Yes | Yes |
| curl -I -L | Yes | Yes | No | No, needs a terminal |
| Online redirect checker | Usually | Usually | No | Yes |
Why curl -I can show you something a real visitor never sees
Curl's -I flag sends a HEAD request, which asks a server for headers only, no page body. Most redirects behave identically whether the incoming request was a HEAD or a GET, which is why -I is normally a safe shortcut. It is not universal, though. A server that decides its response based on the request method, which is rare but not unheard of on custom redirect logic, can hand a HEAD request a different status code than the GET request a real browser sends when someone clicks the link. If a curl test and a browser test genuinely disagree on the same link, trust the browser, since it is running the same request type a real visitor's click produces.
This is also where the distinction between a 302 and a 307 stops being academic. A 303 always forces the next request to be a GET, regardless of what the original request was. A 307 explicitly preserves the original method and any body sent with it. For a simple tracked link this rarely matters, since almost every click is a GET to begin with, but it matters a great deal for anything redirecting after a form submission, where switching the method silently drops the data that was supposed to travel with it.
Spotting a redirect loop
A redirect loop happens when a chain points back at a URL it already visited, so it never reaches a final page. A browser will usually stop after a fixed number of hops and show an explicit error, something like "too many redirects," rather than hanging indefinitely. In the network tab, this shows up as the same URL appearing more than once in the chain, which is easy to miss if you are only glancing at the row count rather than reading each destination. Curl behaves similarly: without a limit set, curl -L will eventually give up and report that it hit its default redirect limit, which is itself a useful signal that something in the chain is circular rather than simply long.
What each hop tells you
A 301 or 308 means the link is telling you, and any crawler reading it, that the old URL has moved for good. A 302 or 307 means the opposite, that this is temporary and the old URL might still matter later. If a link that is meant to be a permanent redirect is showing up as a 302, or the reverse, that is worth fixing, not just noting. The full breakdown of what each status code means and when to use it is in what is a redirect.
The in-app browser problem most checks miss
A redirect chain that passes a clean test on desktop Chrome does not automatically pass the same test inside Instagram's or TikTok's built-in browser. These in-app browsers are their own rendering environment, with their own cookie handling and their own quirks around multi-hop chains, and they are also the environment most bio link clicks actually happen in. Test only on a desktop browser and you have effectively never tested the link in the environment it will mostly be used. If a link seems to work everywhere except when opened from the app it was posted in, that mismatch, and what to do about it, is covered in why links open in the wrong browser.
Checking whether tracking data survives the chain
Once the chain itself checks out, look at the final URL specifically for whatever you attached at the start, a UTM parameter or a click ID from an ad platform. A redirect only forwards what it is explicitly told to forward. A redirect built to always point at one fixed destination will drop everything after the question mark without any visible error, the page still loads fine, and the only symptom shows up days later as a pile of clicks in your reporting with no source attached. This is also why a custom domain on your own short links is worth setting up properly. It is one less redirect hop between the click and the destination, and one less place for a parameter to disappear.
What a failed test looks like, and how to fix it
A failing test usually shows up as one of a small number of patterns: a chain that loops back on itself and never reaches a final page, a hop that returns a 404 or 500 partway through, a final URL missing the query string it should have kept, or a chain that behaves correctly on desktop but breaks specifically inside an in-app browser. Each points at a different fix: a broken redirect configuration, a dead destination page, a redirect that does not preserve query parameters, or an in-app browser incompatibility. None of that is visible from clicking the link once yourself and watching it load. Reading the actual network requests is the only way to know which one you are dealing with.