Skip to main content
URL Shortenerlesson 4 of 4 · 2 min read

301 vs 302 and the Analytics Pipeline

The status code is a business decision

Your redirect status code looks like trivia and is actually a business decision.

A permanent redirect gets cached aggressively by browsers, so the second time somebody clicks, their browser goes straight to the destination without contacting you at all.

Read both sides of that. Great for your load. Fatal for your analytics, because you never see repeat clicks, and if your customer later edits the destination, everyone holding the cached redirect keeps landing on the old one.

Use a temporary redirect and every click comes back to you. Nearly every commercial shortener chooses per-click visibility, because the click counts are the product and the redirect is only the delivery mechanism.

Analytics off the critical path

Hang your analytics off the redirect asynchronously. On each click your server emits an event carrying the code, the timestamp, the user agent, the referrer and a coarse location, then answers the redirect without waiting.

Aggregate those into a columnar store, where clicks by country by hour over a billion events is a sub-second query. Keeping this off the redirect's critical path is the difference between an analytics outage and a product outage.

Handle expiry lazily. Check the expiry at read time, return gone, and let a nightly job reclaim the rows, rather than racing timers.

Budget for abuse, the unglamorous half of running a public shortener. Phishers love hiding behind your domain, so you need a scan at creation time, a warning page for suspicious destinations, and a kill switch per code.

Take the cautionary tale seriously. When a shortener is not the core business, the endless abuse fight makes it an easy product to shut down, and one large company did exactly that.

the shape of it
ClickRedirect serviceDestinationEvent streamWarehouse1. GET code2. 3023. emit, no wait4. aggregate
step 1 of 4
A temporary redirect keeps every click visible; analytics runs off the hot path.

Worked example

Priya runs link infrastructure at an email marketing company where customers pay for click reports. A well-meaning platform engineer flips redirects from 302 to 301 during a performance push, and it works: origin traffic drops 30 percent over two weeks as browsers and corporate proxies cache the redirects. Then customer dashboards start showing click counts sliding down 25 to 40 percent with no change in email volume, and two agencies threaten to churn over broken tracking. It takes four days to connect the dashboards to the status code because the redirect service itself looks perfectly healthy. Priya reverts to 302, adds a lint rule that fails the build if the redirect handler returns 301, and writes the incident up: the company sells the click data, so browser caching is not an optimization, it is revenue loss.

URL Shortener: wrapping up

In the real world

  • 01Bitly reports handling on the order of 10 billion clicks per month, and its business is the analytics on those clicks, which is why the click-tracking pipeline is as engineered as the redirect itself.
  • 02Twitter wraps every link in t.co, not to save characters (link display length is fixed anyway) but to scan destinations for malware and to measure click behavior across the platform.
  • 03Google stopped accepting new goo.gl links in 2018; running a free public shortener meant an endless fight against phishing and spam masked behind the google.com trust halo.
  • 04TinyURL has run since 2002 and its early 5 character codes show the capacity math in action: the alphabet and length directly cap how many links you can ever issue before migrating.
  • 05Slack and Discord unfurl short links server-side and show users the true destination, a countermeasure built specifically because shorteners are a standard tool for disguising malicious URLs.

Questions people ask

Should I use base62 encoding or hashing for the short code?

Base62 over a unique ID is the cleaner default: zero collisions by construction and no retry logic. Choose hashing only if deduplicating identical long URLs matters to you, and then implement collision handling as an atomic insert-or-compare, not a check-then-write, because the race between two concurrent inserts is the classic bug in this design.

Why not just use a UUID as the short code?

A UUID is 36 characters, which defeats the purpose of a short link. The whole problem is compressing an identifier into 6 to 8 characters, and that means either encoding a compact sequential ID in base62 or truncating a hash and handling collisions. UUIDs buy uniqueness by spending exactly the length budget you cannot afford here.

How does the shortener stay fast for users on other continents?

Replicate the read path, not the write path. Run redirect servers and Redis caches in each region, backed by a replicated store, and route users with GeoDNS or anycast. A link created in Virginia may take a second to become servable from Singapore, which nobody notices, while every click gets a local sub-100 ms redirect.

Quick review

Write path:
client POSTs long URL → generate short code → store mapping in DB → return short URL
Short code generation:
base62 (a-z A-Z 0-9) encoding of auto-increment ID gives 7 chars for 3.5 trillion URLs
Alternative:
MD5 hash of long URL, take first 7 chars. Handle collisions by appending +1
Storage:
key-value DB is perfect (short_code → long_url). Use Cassandra or DynamoDB at scale
Read path:
GET /abc123 → check Redis cache → cache miss → DB lookup → 301/302 redirect
301 (Permanent Redirect):
browser caches it. Reduces server load but can't track clicks. 302 (Temporary): every click hits your server. Enables analytics
Scale:
read-heavy (1000:1 read/write typical) → Redis cache + read replicas. CDN at edge for top URLs
Analytics:
log every redirect with user-agent, referer, timestamp, geo → aggregate in Kafka → store in columnar DB
the trade-off

Auto-increment leaks total URL count. Hash has collision risk. Bloom filter can detect collisions before DB lookup.

in the room

Classic warm-up interview question. Tests: unique ID generation, caching strategy, redirect semantics, scale estimation.