Short links on your own domain, with stats that don't track people.

Link Keeper is an open-source link shortener you run yourself. Create branded short links, tag them with UTM parameters, send iPhone and Android visitors to the right app store, let links expire, and see clicks by day, referrer and device without storing an IP address or setting a cookie. You pay no per-link or per-click fee. First, plan a campaign's links below. Everything runs in your browser, so nothing you paste is uploaded.

1. Plan a batch of tagged short links

Short nameTagged destination

Short names you leave blank are random six-character names without look-alike letters (no 0, o, 1, i or l). Existing utm_* values on a destination are replaced, other query parameters are kept. This plans links; it does not create them. Use the bulk API call below on your server.

2. Run the server yourself

git clone https://github.com/Duncan-Haywood/oss-monorepo && cd oss-monorepo/ventures/link-keeper
ADMIN_KEY=$(openssl rand -hex 16) BASE_URL=https://go.example.com node server.mjs

curl -X POST localhost:8080/v1/links -H "authorization: Bearer $ADMIN_KEY" \
  -d '{"url":"https://example.com/app","slug":"app","ios":"https://apps.apple.com/app/id1","android":"https://play.google.com/store/apps/details?id=com.example"}'
curl localhost:8080/v1/links/app/stats -H "authorization: Bearer $ADMIN_KEY"

Options on a link: utm, ios, android, expiresAt, maxClicks, tags, title. Add + to any short address (/app+) to see where it goes without following it. POST /v1/links/bulk creates up to 200 at once; GET /v1/export.csv exports every link. One-click Render and Fly.io deploys and Docker are in the README.

Questions

Why not just use Bitly, Dub or Rebrandly?

Those are good products with hosted dashboards, team seats and custom domains handled for you, and they are the right choice if you want zero operations. Link Keeper is for people who want their own short domain, no per-link or per-click pricing tier, and click data that never leaves their server. It is one dependency-free Node process with a JSON file for state. It has no visual dashboard: stats come from a JSON API and a CSV export.

What does it record about the people who click?

Per link and per day it keeps counts only: clicks, bots, unique visitors, referrer host (never the path or query), device class, browser family and, if your proxy supplies a country header, a two-letter country. No IP address, user agent or cookie is stored. Unique visitors use a hash with a random salt that is thrown away at the end of each UTC day, so a visitor cannot be followed across days.

Can it be used to send people to a harmful site?

Only you hold the admin key, so only you can create links. You can restrict destinations to your own domains with ALLOW_HOSTS. Any link can be inspected without being followed by adding a plus sign to the end of its address, and javascript:, data: and credential-bearing URLs are refused.

What are the limits?

State is one JSON file, written every few seconds, so it suits thousands of clicks a day, not millions. There is no login screen, no team accounts, no QR image generator and no custom domain handling: point your own domain at the server and set BASE_URL.

What does the browser tool on this page do?

It builds UTM-tagged campaign URLs and plans a batch of short links from a pasted list, using the same code as the server. Nothing you paste is uploaded. Copy the result into the bulk API call to create them all at once.