← All work

Affiliate Tracker

Knowing which click actually paid off.

My own product. An analytics platform for a portfolio of content websites that follows every visit, matches each sale to the click that earned it — and lets me simply ask Claude how things are going.

My role
Sole developer · in-house product
When
2026 — now

Recommending products for a living means knowing which recommendations work. The partner networks tell you that you earned something — not why. I built this to find out, and it runs my own business every day.

How it works

  1. 01

    Which article earned the money?

    I run a handful of content websites that recommend products. When someone buys through one of them, the partner network reports a sale — but not which page, which visit or which ad led to it.

  2. 02

    A small script on every site

    Each site runs a tiny script I built. It notes every visit and every click on a partner link, filters out the bots, and works out where the visitor came from — search, social, an ad or a newsletter.

  3. 03

    Matching sales to clicks

    Every fifteen minutes the night shift fetches the latest sales and matches each one to the click that earned it. Once a night it goes back through the last 90 days, in case the network changed its mind.

  4. 04

    Telling the ads what works

    When a sale started with a paid search ad, that’s reported back to the ad platform — so the budget flows to the ads that actually sell, not just the ones that get clicks.

  5. 05

    Ask it anything

    The numbers live in a dashboard that works on my phone, and a message lands in Slack when a sale comes in. Or I just ask Claude “how did last week go?” — it can read the figures directly.

visits & clicksevery 15 minsale ↔ clickwhat paid offquestionsVisitorsread, click, buyWebsite 1Website 2Website 3Website nTracking enginebots out, source inControl roomdashboard on the phoneClaudeasks the numbersAffiliate networkreports salesNight shift5 scheduled jobsAd platformpaid search
  • Built by me
  • Outside service
  • People

Choices I made

  1. 01

    Watch the bot filter before trusting it

    A strict bot filter can quietly throw away real visitors — and you’d never know what you lost.

    Every rule first just notes why it would block a visit. Only rules that have proven themselves are allowed to remove anything.

    The catch Someone has to decide when a rule is ready — the filter doesn’t promote itself.

  2. 02

    A visit remembers where it came from

    A click on a partner link looks like it came from the site itself, so every sale showed up as “direct”.

    Everything in a visit inherits the source of its first page, and every sale inherits the source of the click that earned it.

    The catch Getting it wrong once meant repairing old data — so the logic now has tests of its own.

  3. 03

    The jobs take turns

    With two servers running, the same sale was sometimes reported to the ad platform twice.

    Each job has to take a lock in the database before it runs, so only one copy ever works at a time.

    The catch The lock must last longer than the job — or two can still slip through.

The result

Under the hood — for the technical reader

Stack NestJS · TypeScript · PostgreSQL · React · MCP

  • Tracking engine 2026

    An API that takes in pageviews, clicks and conversions per site, flags bots with explainable rules, resolves channels per session and enriches visits with location.

    NestJS 11 · Prisma 7 · PostgreSQL · GeoLite2 · isbot

  • Tracking SDK 2026

    A small TypeScript package the websites use to send visits and clicks, published from CI.

    TypeScript · GitHub Actions · GitHub Packages

  • Scheduled jobs 2026

    Network sync every 15 minutes, a nightly 90-day reconcile, offline conversion uploads for paid search, session checks and enrichment — each behind a database lease lock.

    NestJS schedule · PostgreSQL · Google Ads API · Slack

  • Dashboard & MCP server 2026

    An installable dashboard for overview, sessions, events and revenue, plus an MCP server with Google sign-in so Claude can query the stats.

    Vite · React · shadcn/ui · MCP · OAuth 2.1