I built my own bitly โ with the analytics Bitly hides.
Feb 2026 ยท 7 min read
Every link I share is piyus.site/โฆ, which means somewhere there's a service turning short codes into redirects. Commercial shorteners do this fine โ and then charge you to see who clicked. So I built my own: FastAPI, server-rendered HTML via HTMX, SQLAlchemy, Docker. No SPA, no build step for the frontend. A form posts, HTML comes back.
The route table is the whole product: POST /shorten mints a code, POST /custom_shorten lets you claim your own slug, GET /{short_code} 302s to the target, GET /h/{name} serves a public ask page, and GET /ana is the analytics dashboard sitting behind HTTP basic auth. Five routes. Nothing else was needed, so nothing else exists.
The part I'm proudest of is invisible: every redirect fires a background task that logs the visit โ IP-derived location, user agent, referrer โ after the 302 is already on its way. Analytics must never slow down the redirect; the redirect is the product, the analytics are the exhaust. FastAPI's BackgroundTasks is exactly the right weight for this โ a queue would be more correct and entirely unnecessary at my scale, and the code admits that.
Unusual for a weekend project: it has test scripts with opinions. The repo carries verify_analytics.py, verify_custom_shorten.py, verify_ask_page.py, and a verify_regression.py that ties them together. I wrote them because shorteners fail silently โ a broken redirect looks exactly like a working page until someone tells you their link is dead. The scripts are the monitoring.
Honest limits: basic auth protects the dashboard but it's one shared password; background tasks die with the process (a crash eats visits); and there's no abuse throttling yet. If it ever outgrows one container, the queue and the rate limiter are the first two things I'd add โ in that order.
keep reading
Bulk uploads beat dashboards: cutting remittance TAT 80%4 minBenchmark 10 classifiers before trusting one5 minPending transactions need a tracer4 minCorporate ChatGPT is blocked. So I built ToolChat.7 minGroup chat on REST and polling. No WebSockets. (On purpose.)6 minStreaming LLMs through a 20-line edge proxy.5 min