Skip to content

Repository files navigation

Pixel Tracker — serverless email-open & click tracking

Pixel Tracker

A 1×1 tracking pixel on Vercel + Upstash Redis.
Opens, clicks, campaigns, webhooks, and a live dashboard — fully serverless.

GitHub stars GitHub forks GitHub issues License Next.js Upstash Redis Vercel

Live Demo — Open dashboard   Deploy with Vercel


Why

Most email/marketing tools bury open tracking behind a paywall and a SaaS account. This is the smallest useful version: drop a <img> tag in your email, get opens + clicks + per-campaign analytics in a dashboard you own — for the cost of a free Vercel + Upstash plan.

Features

  • /api/track — returns a 1×1 transparent PNG, logs the open
  • /api/click — logs the click, then 302-redirects (open-redirect-safe: only http/https allowed)
  • Campaign tracking?campaign= param on both endpoints
  • Live dashboard — totals, per-day chart, per-campaign breakdown, recent events with campaign filter
  • Webhooks — set WEBHOOK_URL to fan out every event in real time
  • O(1) analytics — counters maintained on write so /api/stats doesn't scan logs
  • Zero frontend deps — hand-rolled SVG chart, no charting library

Quick start

git clone https://github.com/anujarkitekt/pixel-tracker-vercel.git
cd pixel-tracker-vercel
npm install
cp .env.local.example .env.local   # fill in Upstash creds
npm run dev

Open http://localhost:3000 for the dashboard.

Usage

Track an email open:

<img src="https://your-app.vercel.app/api/track?id=user-123&campaign=spring-sale" width="1" height="1" />

Track a click (wraps the destination URL):

<a href="https://your-app.vercel.app/api/click?id=user-123&campaign=spring-sale&url=https%3A%2F%2Fexample.com%2Flanding">
  Shop now
</a>

Get aggregated stats:

curl https://your-app.vercel.app/api/stats
# { totals: { track, click }, byCampaign: [...], byDay: [...] }

Environment variables

Variable Required Purpose
UPSTASH_REDIS_REST_URL yes Upstash Redis REST URL
UPSTASH_REDIS_REST_TOKEN yes Upstash Redis REST token
WEBHOOK_URL no If set, every event is POSTed here (fire-and-forget, 2s timeout)
DASHBOARD_USER no Basic-Auth username for /, /api/logs, /api/stats (default admin)
DASHBOARD_PASSWORD no Basic-Auth password. If unset, auth is disabled. /api/track and /api/click always stay public.

Architecture

Client (email / web)
   │
   ▼
/api/track  ──┐
/api/click  ──┼──▶ recordEvent ──▶ Upstash Redis (logs list + counters)
              │                ├──▶ Webhook (optional)
              │
              ▼
        /api/stats, /api/logs ──▶ Dashboard (/)

Redis layout:

  • logs — capped list (newest 1000)
  • stats:total:{track|click} — counter
  • stats:campaign:<name>:{track|click} — counter
  • stats:day:<YYYY-MM-DD>:{track|click} — counter
  • campaigns, days — sets of known keys

Limitations

  • Apple Mail and Gmail proxy/preload images — opens may be inflated or anonymized
  • Some clients block remote images by default (counts will under-report)
  • Click tracking only redirects http/https URLs (intentional, blocks open-redirect abuse)

Roadmap

  • Per-recipient unique-open detection — SADD unique:track <id> → SCARD on read
  • CSV export — /api/export.csv, "Download CSV" button on the dashboard (auth-gated by middleware)
  • Geo-IP enrichment — country flag + city, via Vercel x-vercel-ip-* headers (no extra deps)
  • Per-campaign unique counts — Unique + Devices columns in the campaign table
  • Hashed UA/IP fingerprint for device dedup — SHA-256 of ip|userAgent, 16-hex truncated
  • TTL on per-event sets (unique:*, device:*) so abandoned campaigns don't grow forever
  • Per-day unique/device split (data layout supports it; UI room is the constraint)

License

MIT © Anuj Singh

About

Serverless 1×1 email tracking pixel on Next.js + Vercel + Upstash Redis. Tracks opens, clicks, campaigns, with webhooks and a live dashboard. Zero-config, MIT

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages