How to Bulk Unshorten URLs & Trace Redirect Chains in 2026
Resolve thousands of short links at once — bit.ly, t.co, ow.ly, TinyURL — and trace every redirect hop, status code and final URL. No API key, CSV or JSON.
Short links hide where they actually go — that’s the whole point of them, and it’s exactly the problem when you’re auditing a marketing campaign, triaging a phishing report, or de-duplicating a URL dataset. Opening each bit.ly or t.co link in a browser to see the destination doesn’t scale past a handful, and it means loading pages you may not want to load. This guide covers how to resolve thousands of shortened URLs in one pass, capture the full redirect chain hop by hop, and get the final destination for every link — using nothing but HTTP HEAD requests.
What you get per URL
Each input URL resolves to exactly one output row describing its complete redirect sequence. The fields:
originalUrl— the short URL you submitted.finalUrl— the final resolved destination after following every redirect.isShortened—trueif at least one redirect was followed,falseif the URL was already the final destination.hopCount— the number of redirect hops traversed.redirectChain— the full chain as a JSON array; each hop carriesurl,statusCode,redirectType(permanent/temporary),nextUrl, andlatencyMsfor that individual hop.chainUrls— a comma-separated list of every URL in the chain, in traversal order, for quick spreadsheet scanning and filtering.totalLatencyMs— total round-trip time for the full resolution.statusCode— the HTTP status of the final destination.error— an error message if resolution failed (timeout, DNS, TLS, etc.).resolvedAt— ISO 8601 timestamp of when the resolution ran.
The redirectChain field is the interesting one for forensics: it doesn’t just tell you where a link ended up, it tells you every intermediate hop — the tracking domains, the redirect services, the utm-laced landing steps — with the exact status code at each stage.
How resolution actually works
The technique is deliberately simple, which is what makes it fast and cheap. For each URL, the actor sends an HTTP HEAD request with followRedirect: false. When the response is a 3xx status with a Location header, that hop is logged and the actor follows to the next URL. Each hop measures its own latency, and the loop repeats until one of three things happens:
- A non-redirect status (2xx, 4xx, 5xx) is returned — this is the final destination.
- The max redirect limit is hit — the chain is cut and the last URL is recorded as final.
- A network, timeout or DNS error occurs — resolution fails gracefully and the reason lands in the
errorfield.
Using HEAD instead of GET is the key decision. A HEAD request returns only the response headers, not the page body, so no HTML, images or scripts are downloaded. That’s why thousands of links resolve per run on minimal bandwidth — and why you can trace a suspicious link’s destination without ever loading it in a browser.
The actor handles all standard redirect status codes — 301, 302, 303, 307, 308 — from any shortener: bit.ly, t.co, ow.ly, TinyURL, short.link, Rebrandly, and custom short domains. Protocol is auto-fixed: bit.ly/xyz is upgraded to https://bit.ly/xyz before resolving, so you don’t have to normalize your input list first.
A basic batch:
{
"urls": [
"https://bit.ly/3abcXYZ",
"https://t.co/xyz789",
"https://tinyurl.com/example",
"https://ow.ly/abc123"
],
"maxRedirects": 15,
"maxConcurrency": 20,
"proxyConfiguration": { "useApifyProxy": true }
}
▶ Run the Bulk URL Unshortener on Apify — paste thousands of short links, get one clean row per URL with the full redirect chain, hop latency and final destination. No API key, no browser. Export to CSV or JSON.
The access reality: rate limits and loops
The friction here isn’t anti-bot walls — it’s the shorteners’ own per-IP rate limiting and the occasional malicious redirect loop. Two settings handle both.
Concurrency and proxies. maxConcurrency controls how many URLs resolve in parallel (default 20, up to 100). Push it up for very large lists, but keep Apify Proxy enabled so a single IP doesn’t get throttled by a shortener that sees a thousand rapid HEAD requests from one address. For high-volume forensic sweeps, a residential proxy group spreads the load further:
{
"urls": ["https://bit.ly/aaa", "https://bit.ly/bbb", "https://short.link/ccc"],
"maxRedirects": 30,
"maxConcurrency": 100,
"proxyConfiguration": { "useApifyProxy": true, "apifyProxyGroups": ["RESIDENTIAL"] }
}
Loop prevention. maxRedirects (default 15, up to 30) caps the hops per URL. Some links — especially deliberately obfuscated ones — chain through many redirects or loop back on themselves. When the limit is hit, the chain is cut cleanly and the last URL is reported as final. No infinite loops, no runaway runs. For suspicious links you can lower the cap to fail fast; for legitimate multi-hop tracking chains, raise it.
Example output
One resolved short link with a two-hop chain:
{
"originalUrl": "https://bit.ly/3abcXYZ",
"finalUrl": "https://example.com/landing-page?utm_source=twitter",
"isShortened": "true",
"hopCount": "2",
"chainUrls": "https://bit.ly/3abcXYZ, https://example.com/lp",
"totalLatencyMs": "162",
"statusCode": "200",
"resolvedAt": "2026-07-06T12:00:00.000Z"
}
The redirectChain field (omitted above for brevity) holds the structured per-hop array with each statusCode, redirectType and latencyMs, so you can see that hop one was a 301 permanent and hop two a 302 temporary, for example.
Use cases
- Security / phishing triage — trace where a suspicious short link actually leads, hop by hop, without opening it in a browser. HEAD-only means no page content is ever loaded.
- Digital forensics & OSINT — map redirection chains across campaigns, ad networks and tracking links; the intermediate hops reveal the infrastructure behind a link.
- Marketing link audits — verify that shortened links in emails, social posts and ads still point to the intended destination and haven’t been re-pointed or expired.
- SEO audits — confirm that short links in backlinks and social profiles resolve to the correct canonical URL rather than a redirect or a dead page.
- Brand protection — scan for short links that impersonate your brand and trace where they redirect.
- Data enrichment — append resolved final destinations and redirect metadata to large URL datasets for categorization and deduplication (two short links that resolve to the same
finalUrlare duplicates).
Build it yourself vs. use the managed actor
You could write a HEAD-follow loop in an afternoon — the logic is genuinely simple. What you’d then own:
- Concurrency management — a naive
forloop resolving thousands of URLs serially is slow; a parallel one without backpressure gets your IP rate-limited. - Proxy rotation — shorteners throttle by IP, so a single-IP script stalls on large lists.
- Edge-case handling — protocol normalization, redirect loops, malformed
Locationheaders, TLS errors, timeouts, and the per-hop latency instrumentation.
The managed actor runs on pay-per-result: you’re charged per URL resolved, with no separate platform fee to calculate and no monthly floor. At a fraction of a cent per URL, resolving a list of 10,000 short links costs a few tens of cents including proxy bandwidth. The trade you’re making is a few dollars against the concurrency, proxy and edge-case engineering.
Common pitfalls
Specific gotchas when working with redirect data:
redirectChainis a JSON string, not a nested object. In the dataset it’s serialized as a string containing a JSON array. Parse it (JSON.parse) before you iterate the hops in code.isShortened: falseis a useful signal, not an error. A direct URL with no redirects returns a valid row withisShortenedfalse andhopCount0. Use it to filter which URLs in a list are already final.- A cut chain still returns a
finalUrl. IfmaxRedirectsis reached, the last URL seen is reported as final even though it may itself be another redirect. CheckhopCountagainst yourmaxRedirectsto spot chains that were truncated rather than fully resolved. - HEAD isn’t universally honored. A small number of servers respond differently to HEAD than to GET, or reject HEAD outright — those land in the
errorfield rather than resolving. This is rare but worth accounting for in strict audits. - Final
statusCodecan be 4xx or 5xx. A link can resolve fully to a dead or error page.finalUrlplus astatusCodeof404tells you the destination exists as a URL but is broken — a distinct result from a resolutionerror. - Query parameters are preserved. Tracking params (
utm_*, click IDs) survive intofinalUrl. Strip them yourself if you’re deduplicating on destination rather than on exact URL.
Scheduling and monitoring
Short links aren’t static — a bit.ly that pointed somewhere legitimate last month can be re-pointed to a malicious destination, and campaign links expire. Schedule the actor on Apify to re-resolve your link lists daily or weekly, then diff each run’s finalUrl against the last: a changed destination for the same originalUrl is exactly the signal a brand-protection or phishing-triage workflow watches for. Push results to Google Sheets, a database, a SIEM or a webhook via the Apify API, or wire the run into Make, n8n or Zapier to build automated link-monitoring and phishing-triage pipelines that flag when a tracked short link’s destination moves.
Wrapping up
Unshortening one link is trivial; unshortening tens of thousands cleanly — with per-hop chains, proxy rotation and graceful failure — is the part worth not rebuilding. If you’re auditing links, triaging phishing, or enriching a URL dataset, a managed HEAD-based resolver gives you the full redirect intelligence in one run.
▶ Open the Bulk URL Unshortener on Apify — resolve thousands of short links per run with the full redirect chain, hop-by-hop latency and final URL. No API key, no browser. Export to CSV or JSON. Start on Apify’s free monthly credit.
Related guides
How to Build a Deep-Research Retrieval Layer for AI Agents
Give an agent a topic and get ranked web sources, full-page Markdown, and recent news with citations — keyless multi-source retrieval for RAG and grounding.
How to Extract Structured Data from Any URL in 2026
Turn any web page into clean JSON without an LLM: parse schema.org JSON-LD, OpenGraph, tables, prices and contacts deterministically — no API key, no browser.
How to Add Live Web Search to AI Agents (No API Key)
Give your LLM fresh, citable search results without a Tavily or SerpAPI key. How live SERP extraction works: ranked results plus Markdown page content for RAG.