<!--
ROBOTS ON PAYROLL / THE VAULT
What this is: a one-table UTM scheme for launch week so one filter shows which channel actually drove signups.
How to use it: download this file and give it to your AI (Claude, ChatGPT,
Cursor, Lovable chat) as a reference. Say: "Use this as my playbook for
tracking my launch traffic."
Latest version + full guide: https://robotsonpayroll.com/resources/launch-week-kit
-->

# Launch UTM Scheme

One campaign name, one source per channel, measured at signup (not pageview). Copy the table, swap `yourproduct.com` and the campaign date, done.

## The scheme

Campaign name: `launch-[mon][yyyy]`, e.g. `launch-jul2026`. Same campaign across every channel so one filter isolates the whole launch.

| Channel | utm_source | utm_medium | utm_campaign | Where the link lives |
|---|---|---|---|---|
| Waitlist warm email (D-3) | `newsletter` | `email` | `launch-jul2026` | body link |
| Launch day email (D0) | `newsletter` | `email` | `launch-jul2026-d0` | body link |
| Product Hunt | `producthunt` | `launch` | `launch-jul2026` | your website URL on the PH listing |
| X thread | `x` | `social` | `launch-jul2026` | first reply only, never tweet 1 |
| Show HN | (none) | (none) | (none) | submission URL stays clean; see below |
| r/SideProject | `reddit` | `social` | `launch-jul2026-sideproject` | final line of the story post |
| r/indiehackers | `reddit` | `social` | `launch-jul2026-indiehackers` | in-context mention |
| Follow-up email (D+3) | `newsletter` | `email` | `launch-jul2026-d3` | body link |
| Bio links (X/GitHub) | `bio` | `profile` | `launch-jul2026` | profile fields |

Example built link:

```
https://yourproduct.com/?utm_source=producthunt&utm_medium=launch&utm_campaign=launch-jul2026
```

## Why HN gets no UTM

Show HN submission URLs should be canonical: HN's duplicate detection works off the URL, and the community notices tracking parameters. Measure HN by referrer (`news.ycombinator.com`) instead. Same trick works as a cross-check for every channel.

## Capture at signup, not just pageview

Pageview analytics tells you who visited. You care who signed up. Persist first-touch UTMs and write them to the user record:

```js
// on landing: persist first-touch UTMs (do not overwrite on later visits)
const p = new URLSearchParams(location.search);
["utm_source", "utm_medium", "utm_campaign"].forEach((k) => {
  if (p.get(k) && !localStorage.getItem(k)) localStorage.setItem(k, p.get(k));
});
// on signup: read the three keys from localStorage and send them
// with the signup payload into utm_source/utm_medium/utm_campaign columns.
```

Also store `document.referrer` on first touch, in a `first_referrer` column. That is your HN counter and your safety net for links that lost their UTMs (people re-paste URLs).

## The 5-line analytics check (run D+3)

Signups per channel for launch week, straight from your database:

```sql
SELECT COALESCE(utm_source, split_part(first_referrer, '/', 3), 'direct') AS channel,
       COUNT(*) AS signups
FROM users
WHERE created_at >= '2026-07-11' AND created_at < '2026-07-18'
GROUP BY 1
ORDER BY signups DESC;
```

Swap the dates for your D-3 to D+3 window. If you're on Plausible or GA4 instead: filter to `utm_campaign = launch-jul2026`, break down by `utm_source`, and read the signup/conversion event count, never sessions.

## How to read the result

- **Rank channels by signups, not traffic.** HN can send 10x the visitors of your email list and a third of the signups. This table is what decides where your 6-week follow-through effort goes.
- Compare `utm_source` totals against `first_referrer` totals. A big gap means links are circulating without UTMs (usually a good sign: people are sharing it).
- Keep the scheme after launch week. Same source/medium values forever, only the campaign changes. Future-you doing year-end analytics will be grateful.
