Skip to content

alexjuillardoff/linker

Repository files navigation

Linker logo

Linker

Self-hosted link tracking & analytics platform
A lightweight, open-source Bitly alternative with full click analytics, geolocation, device detection, and a built-in admin dashboard.

Node.js Express PostgreSQL License Self-hosted


Features

Link Management

  • Custom slugs — create short links with your own readable slugs
  • Link expiration — optional expiry date with automatic 410 Gone response
  • Labels & UTM builder — tag links and auto-append UTM parameters
  • QR code generation — one-click QR codes with PNG download
  • Bulk operations — select and delete multiple links at once
  • CSV export — export all links or per-link events

Click Analytics

Every click is tracked asynchronously (non-blocking redirect) and captures:

  • IP address (respects X-Forwarded-For behind proxies)
  • Browser & version (parsed from User-Agent)
  • Device type — desktop, mobile, or tablet
  • Operating system — Windows, macOS, iOS, Android, Linux, etc.
  • Geolocation — country & city via IP lookup (geoip-lite)
  • Referer — where the click came from
  • Timestamp — precise UTC datetime

Dashboard

  • KPI cards — total links, clicks (today / week / month / custom range)
  • Time range filter — 7 days, 30 days, or 90 days
  • Clicks over time — interactive line chart
  • Top links, referrers, devices, countries — bar chart breakdowns
  • Hourly heatmap — click intensity by day of week and hour
  • Per-link analytics — detailed stats, breakdowns, and raw event log

Admin Panel

  • User management — create accounts, assign roles (admin / viewer), reset passwords
  • Role-based access — viewers can read; admins can create, edit, delete
  • Audit log — full history of who did what and when
  • Session auth — secure HTTP-only cookies, 24h expiry with renewal
  • Dark / Light / Auto theme — per-user preference saved in database

Technical

  • Zero framework frontend — vanilla HTML/CSS/JS, no build step
  • No ORM — direct SQL queries with pg (node-postgres)
  • Idempotent schemaschema.sql safe to replay
  • PM2 ready — production config included
  • nginx reverse proxy — sample config included

Quick Start

1. Clone & install

git clone https://github.com/alexjuillardoff/linker.git
cd linker
npm install

2. Create the database

sudo -u postgres psql -c "CREATE ROLE linker_app WITH LOGIN PASSWORD 'your_password' CREATEDB;"
sudo -u postgres psql -c "CREATE DATABASE linker OWNER linker_app;"
PGPASSWORD=your_password psql -h localhost -U linker_app -d linker -f schema.sql

3. Configure

cp .env.example .env
# Edit .env with your database credentials, admin account, and cookie secret
Variable Description
PG_HOST, PG_PORT, PG_USER, PG_PASSWORD, PG_DATABASE PostgreSQL connection
PORT Server port (default: 8010)
ADMIN_DEFAULT_USER, ADMIN_DEFAULT_PASSWORD Initial admin account
COOKIE_SECRET Cookie signing secret

4. Run

# Development (auto-reload)
npm run dev

# Production
pm2 start ecosystem.config.js
pm2 save

nginx Configuration

server {
    listen 443 ssl;
    listen [::]:443 ssl;
    http2 on;
    server_name your-domain.com;

    ssl_certificate /etc/letsencrypt/live/your-domain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/your-domain.com/privkey.pem;

    location / {
        proxy_pass http://127.0.0.1:8010;
        proxy_http_version 1.1;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

server {
    listen 80;
    listen [::]:80;
    server_name your-domain.com;
    return 301 https://$host$request_uri;
}

API Reference

Authentication

Method Route Description
POST /admin/login Log in (returns session cookie)
POST /admin/logout Log out (invalidates session)
GET /admin/me Current session info + theme
PUT /admin/me/theme Update theme preference

Links

Method Route Description
GET /admin/api/links List links (search, sort, paginate)
POST /admin/api/links Create a link
PUT /admin/api/links/:slug Update destination URL, label, expiry
DELETE /admin/api/links/:slug Delete a link
DELETE /admin/api/links/:slug/events Purge tracking events
GET /admin/api/links/:slug/events Paginated event log
GET /admin/api/links/:slug/stats Aggregated analytics
POST /admin/api/links/bulk-delete Bulk delete by slugs
GET /:slug Public redirect + tracking

Statistics

Method Route Description
GET /admin/api/stats/summary KPIs (filterable by ?days=)
GET /admin/api/stats/clicks-over-time Daily click counts
GET /admin/api/stats/top-links Top links by clicks
GET /admin/api/stats/top-referrers Top referrer domains
GET /admin/api/stats/devices Device type breakdown
GET /admin/api/stats/countries Country breakdown
GET /admin/api/stats/browsers Browser breakdown
GET /admin/api/stats/heatmap Clicks by day-of-week × hour

Users & Audit

Method Route Description
GET /admin/api/users List users (admin only)
POST /admin/api/users Create user (admin only)
DELETE /admin/api/users/:id Delete user (admin only)
PUT /admin/api/users/:id/password Reset password (admin only)
GET /admin/api/audit Paginated audit log (admin only)

Export

Method Route Description
GET /admin/api/export/links CSV export of all links
GET /admin/api/export/events/:slug CSV export of link events

Project Structure

linker/
├── server.js              # Express entry point
├── db.js                  # PostgreSQL pool + default admin setup
├── schema.sql             # Idempotent DDL (tables + indexes)
├── ecosystem.config.js    # PM2 production config
├── middleware/
│   └── auth.js            # Session verification + role guards
├── routes/
│   ├── auth.js            # Login, logout, theme preference
│   ├── admin.js           # Link CRUD, events, stats, export, audit
│   ├── users.js           # User management
│   ├── stats.js           # Global analytics endpoints
│   └── redirect.js        # Public redirect + async tracking
├── public/
│   ├── login.html         # Login page
│   ├── admin.html         # Single-page admin dashboard
│   └── favicon.svg        # App icon
├── .env.example
└── package.json

Tech Stack

Layer Technology
Runtime Node.js 18+
Framework Express 4
Database PostgreSQL 14+ (via pg)
Auth bcrypt + server-side sessions
UA Parsing ua-parser-js
Geolocation geoip-lite
Frontend Vanilla HTML/CSS/JS (no framework, no build)
Process Manager PM2

License

MIT

About

Self-hosted link tracking & analytics platform — Bitly-style URL shortener with full click analytics, geolocation, device detection, QR codes, audit logs, and admin dashboard. Built with Node.js, Express & PostgreSQL.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors