Skip to content
rinopatrickPublic

About

Self-hosted URL shortener with click analytics, smart expiry, and QR codes. FastAPI + SQLite. No cloud, no subscriptions

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

License: MIT

Clip

License Stack Python

Self-hosted URL shortener with click analytics, smart expiry, and QR codes. The free, open-source alternative to bit.ly and tinyurl.

What does this do? Paste a long URL, get a short one. Share it anywhere. Track who clicked — browser, OS, device, referer. Set links to auto-expire after time or clicks. Generate QR codes instantly. All data stays on your machine. No accounts, no cloud, no subscriptions.

Self-hosted by design. Clip runs on your own machine. It is NOT a public SaaS. There is no auth and no multi-user isolation — because it is intended to run locally or behind your own firewall.


Features

  • One command deploy — docker run clip and you're running
  • Custom slugs — Use your own short code or auto-generate one
  • Smart expiry — Choose permanent, time-based, or click-based expiration
  • QR codes — Generate QR codes for any short link instantly
  • Click analytics — Browser, OS, device, referer, timestamp
  • Real-time dashboard — Dark mode UI to create and manage links
  • Auto-cleanup — TTL-based link expiry (default 30 days)
  • Zero dependencies — just SQLite, no Redis/Postgres needed

Quick Start

Docker

docker run -p 8080:8080 clip

Open http://localhost:8080 and start shortening URLs.

Docker Compose

docker compose up -d

From Source

git clone https://github.com/rinopatrick/clip.git
cd clip
uv sync
uv run python -m clip

API

Create a Link

Permanent (default):

curl -X POST http://localhost:8080/api/links \
  -H "Content-Type: application/json" \
  -d '{"url": "https://example.com/very/long/path", "slug": "mylink"}'

Time-based expiry (24 hours):

curl -X POST http://localhost:8080/api/links \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com",
    "expiry_type": "time",
    "expiry_hours": 24
  }'

Click-based expiry (max 5 clicks):

curl -X POST http://localhost:8080/api/links \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com",
    "expiry_type": "clicks",
    "max_clicks": 5
  }'

Response:

{
  "id": 1,
  "slug": "mylink",
  "url": "https://example.com/very/long/path",
  "short_url": "http://localhost:8080/mylink",
  "clicks": 0,
  "expiry_type": "permanent",
  "is_expired": false
}

List Links

curl http://localhost:8080/api/links

Get Click Analytics

curl http://localhost:8080/api/links/mylink/clicks

Get QR Code

curl http://localhost:8080/api/links/mylink/qr

Response:

{
  "slug": "mylink",
  "qr_url": "https://chart.googleapis.com/chart?cht=qr&chs=300x300&...",
  "short_url": "http://localhost:8080/mylink"
}

Delete a Link

curl -X DELETE http://localhost:8080/api/links/mylink

Redirect

curl -v http://localhost:8080/mylink

Endpoints

Method Path Description
POST /api/links Create a shortened link
GET /api/links List all links (paginated)
GET /api/links/{slug} Get link details
DELETE /api/links/{slug} Delete a link
GET /api/links/{slug}/clicks Get click analytics
GET /api/links/{slug}/qr Get QR code image URL
GET /{slug} Redirect to original URL
GET /health Service health check

Configuration

All settings are configurable via environment variables with the CLIP_ prefix:

Variable Default Description
CLIP_HOST 0.0.0.0 Server bind address
CLIP_PORT 8080 Server bind port
CLIP_DEBUG false Enable debug mode
CLIP_DATABASE_URL sqlite+aiosqlite:///./clip.db SQLite database URL
CLIP_BASE_URL http://localhost:8080 Base URL for short links
CLIP_REQUEST_TTL_DAYS 30 Days before links auto-delete
CLIP_CLEANUP_INTERVAL_SECONDS 3600 Background cleanup interval
CLIP_MAX_SLUG_LENGTH 32 Max custom slug length

Tech Stack

  • Backend: Python 3.13 + FastAPI + SQLite (aiosqlite)
  • Frontend: Vanilla JS + Tailwind CSS
  • Docker: Multi-stage build (slim runtime)
  • Testing: pytest + pytest-asyncio + httpx

Development

# Run tests
uv run pytest

# Lint
uv run ruff check src/

Support

If this tool saves you time, consider giving it a ⭐ on GitHub and supporting its development:

Platform Link Payment Methods
Saweria (Indonesia) saweria.co/rinopatrick QRIS, GoPay, OVO, Dana, LinkAja
Ko-fi (International) ko-fi.com/rinopatrick PayPal, Credit Card

Every cup of coffee helps keep this project alive and growing.


License

MIT


Clip — Shorten URLs without leaving your machine.

Production-readiness status

Current state: engineering sample / pre-production.

Recommended next steps:

  1. Add CI checks (tests + lint) on every push/PR
  2. Add release/versioning policy
  3. Add deployment/runtime hardening docs
  4. Add monitoring and operational runbook

About

Self-hosted URL shortener with click analytics, smart expiry, and QR codes. FastAPI + SQLite. No cloud, no subscriptions

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages