shrtnr is a self-hosted URL shortener you drive from code and from AI assistants, not only from a dashboard. Every deployment ships a REST API with an OpenAPI spec, typed SDKs on npm, PyPI and pub.dev, and a native MCP server that Claude, Copilot and any other MCP client connect to through OAuth on Cloudflare Access. Links belong to the person who created them, several slugs can point at one destination, and bundles roll the clicks of a whole campaign into one report. It runs on Cloudflare Workers and D1, inside the free tier.
Stuck on setup? We're here to help. Talk to us

Tools for links, slugs, bundles, QR codes and analytics, served from the same Worker. OAuth through Cloudflare Access; every tool call runs as the signed-in user. Read-only, idempotent and destructive annotations on every tool.
Group the links of one campaign. Total clicks, timeline, countries, referrers, devices, browsers and each link's share, over any range. A link can belong to several bundles.
One destination, a random slug plus any number of custom ones, each tracked and switchable on its own.
Identity from Cloudflare Access. Creators own what they make; everyone can read. API keys are issued per person and act as that person.
TypeScript, Python, Dart. Generated from the OpenAPI spec and pinned to its hash in CI.
OpenAPI 3.1, interactive reference on every deployment, scoped bearer keys.
Country, referrer, device, OS, browser, QR versus link, adaptive timeline, bots filtered by default.
Expiry, reversible disable, delete guard for anything with clicks, idempotent creation, labels from the page title.
English, Indonesian, Swedish. Three themes. QR codes.
D1 and KV provisioned for you, migrations applied on first request.
Not yet: password-protected links, import/export, routing by device or country, tags, social preview overrides, click webhooks.
Launched something across a blog post, a GitHub repo, an npm page, and a docs site? Put them in a bundle. One shared picture of the campaign, not eight separate charts. Links can belong to as many bundles as they need to, and you archive a bundle when the campaign ends.


Bundle links from any domain, campaign, or project. Each bundle tells its own story independently.
Total clicks, timeline, countries, referrers, devices, OS, browsers, QR versus link and each link's share of the total, over any range.
A link can live in several bundles at once. No duplicates, no forked tracking, no clean-up later.
Every shrtnr deployment includes an MCP server. Claude, Copilot and any MCP client connect to it through OAuth on Cloudflare Access: shorten URLs, manage bundles, or pull analytics in conversation. Every tool call runs as the person who connected, so an assistant cannot disable or delete another user's links. Prefer code? Typed SDKs for TypeScript, Python and Dart wrap the same REST API.
npm install @oddbit/shrtnr
// Links, slugs, bundles and analytics from TypeScript
flutter pub add shrtnr
// The same client in Dart and Flutter apps
pip install shrtnr
// Link management from Python services and scripts
https://mcp.your-domain.com
// OAuth through Cloudflare Access, no token to paste

Cloudflare Access supplies the identity. Creators own their links and bundles, and only the owner can edit, disable, delete, or remove slugs and bundle members. Everyone signed in can read everything, add a slug to any link and add any link to a bundle. API keys are issued per person and act as that person.
Read the permission modelSelf-hosted in your own Cloudflare account. Your links and click data stay in your D1 database.

You own the domain and the logic. No platform risk, no link rot. Your assets stay under your control.

Deploy your own. Open source, self-hosted, on Cloudflare's free tier.
shrtnr is something we built for ourselves and released. If you want this level of engineering on your own product, tell us what you are building.

Tell Us About Your Project