Back to projects

ZipLink

Shorten links. Track every click. Know your audience.

Type
Full stack web app
Role
Sole developer
Year
2026
Stack
  • Next.js
  • shadcn/ui
  • SWR
  • Express
  • Node.js
  • MongoDB
  • Mongoose
  • Vercel
ZipLink analytics dashboard

ZipLink is a URL shortener built around what happens after the click. You create short links in seconds, set expiration dates and see real-time analytics for every visit. The frontend is built with Next.js and the API with Express, Node.js and MongoDB.

A short link on its own doesn't tell you much. If you share a link, the useful part is knowing who opened it: from which device and browser, from which country and city, and where they came from. ZipLink puts all of that in one dashboard next to the links themselves.

I built the frontend with Next.js and a REST API with Express and Node.js, storing links and clicks in MongoDB through Mongoose. Every redirect records the visit with its device type, browser, country, city and referrer, and the dashboard turns that into analytics per link. Links can expire on a set date, and there is a public redirect page for each one. The frontend is deployed on Vercel.

  • Short links with optional expiration dates
  • Per-click analytics: device, browser, country, city and referrer
  • Dashboard to manage links and their stats in one place
  • Separate Next.js frontend and Express REST API
  • Authentication with protected routes
  1. Auth middleware on the Edge runtime

    Next.js middleware runs on the Edge runtime, not in React. My first version of the route protection called code that only works inside components, so I moved the auth check to plain cookie logic in the middleware and added an endpoint so the client could load the current user on its own.

  2. Sessions that disappeared on mobile

    Login worked on desktop but the session vanished on phones during testing. The cookie had the secure flag set and the browser was silently dropping it over plain HTTP. Once I found it, the fix was in how the cookie was configured.

  3. API errors that never reached the user

    The data fetching layer was swallowing the error payloads coming from the API, so the UI showed generic failures. I reworked the fetcher so the real message from the backend gets through, including expired tokens.

  • Live demo deployed on Vercel
  • Backend code public on GitHub

Have a project or a role in mind?

Let's talk

Next project

Internal admin panel (Electron desktop app)

Delivery Hub Manager

Internal admin panel for a delivery platform handling 5,000+ orders a day.