You are the marketer, the founder, and the person who fixes the broken link in the welcome email at 11 p.m. Enterprise attribution playbooks assume a RevOps hire and a CDP. You have a UTM builder bookmark and guilt about inconsistent tags from last quarter.
This guide is the UTM attribution guides home base: a naming scheme you can keep in your head, habits that survive busy weeks, and how to read results when nobody else will check your work.
The four parameters and what indie teams should actually use
Google’s classic four:
utm_source, who sent the click (twitter, newsletter, partner-name).utm_medium, channel shape (social, email, cpc if you ever run ads).utm_campaign, the initiative (launch-jan, onboarding-v2).utm_content, the specific creative or link placement (optional but powerful).
Skip utm_term unless you buy search ads. Skip custom parameters until the four are boringly consistent.
Rule: if you cannot explain a tag in one sentence, rename it before the next send.
A minimal dictionary that scales to two years
Create a one-page dictionary (Notion is fine):
| Key | Allowed values | Example |
|---|---|---|
| source | lowercase, no spaces | beehiiv, x, ph |
| medium | fixed set | email, social, referral |
| campaign | YYYY-MM-slug | 2026-01-winter-offer |
| content | placement slug | cta-footer, thread-2 |
Date-prefix campaigns let you sort chronologically without remembering that biglaunch was March or May.
Capture on first touch in the session
UTMs belong on the first pageview of a session. If someone lands without UTMs then clicks internal links, you still know they came from the tagged URL that started the session.
Your tracker should persist UTMs in sessionStorage until the tab closes. Internal navigation must not strip them for attribution reads, only the visible URL may clean up for aesthetics.
Reading UTMs without spreadsheet joins
You want a dashboard row: source × revenue × visitors. Not exports. Not pivot tables on Sunday.
Sort by revenue when choosing what to repeat. A source with 2,000 clicks and $0 is a creative problem or a landing problem, check RPV by lander before blaming the channel.
One-person workflow for a typical week
Monday: pick one campaign name for anything you ship this week. Tuesday–Thursday: every external link gets the same campaign, different content if placements differ. Friday: 10-minute review, top source by revenue, not clicks. Monthly: delete or archive campaign names you will never use again from the dictionary.
When UTMs lie (and it is your fault)
- You edited a post and removed query strings.
- You used a shortener that strips parameters (fix or ban).
- You reused
utm_campaign=launchfor six different launches. - You tagged internal links and polluted source with
utm_source=newsletteron every page.
Tag outbound entry points only unless you run a deliberate internal campaign.
Pair UTMs with pinned dates
Campaign review without pinned ranges is storytelling. Pin the week you sent 2026-01-winter-offer and compare to the prior week’s baseline, same pattern as marketing pulse guides.
Automation tools (n8n, Zapier, Make)
Scheduled posts and webhook-driven tweets need campaign names that match the automation, not the day the zap fired. The guide on n8n and Zapier UTM naming covers machine-generated links without turning your dictionary into noise.
Newsletters and redirect wrappers
Email tools wrap links. Some preserve UTMs; some eat them. Test one click per provider monthly. The newsletter UTM guide walks provider-specific habits.
Social threads and carousels
Use utm_content per slide or per tweet in a thread so you know which hook drove traffic, not just that “Twitter worked.” See utm_content for threads.
Direct traffic is not a moral failure
High direct with revenue often means word-of-mouth, mobile apps, or bookmarks. Do not force UTMs onto every mention. Instead, improve lander RPV and let direct rise as a compliment.
Governance without a committee
You are the committee. Three enforcement tricks:
- Browser bookmark with prefilled UTMs for your top three channels.
- Checklist item on publish: “external links tagged?”
- Quarterly 30-minute audit: top 10 campaigns by revenue, do names still mean something?
Honest limits
UTMs do not track:
- Dark social shares without tags.
- Podcast mentions unless you use vanity URLs.
- Multi-device journeys before login.
You are measuring tagged acquisition, not the entire universe. That is still enough to stop random acts of marketing.
What to implement this week
- Write the dictionary page.
- Fix the next newsletter link before send.
- Add
utm_contentto one thread with multiple CTAs. - Review revenue by source inside a pinned week.
UTM attribution for solo marketers is mostly discipline, not software. The software just has to show you the table without a CSV export, then you can get back to writing and shipping.
Worked example: one week, three channels
You ship a minor feature Tuesday, send the newsletter Wednesday, run a five-tweet thread Thursday, and post a LinkedIn carousel Friday. Campaign name for all external entry: 2026-01-feature-notifications.
| Source | Medium | Content | Visitors (7d) | Revenue (7d) | Notes |
|---|---|---|---|---|---|
| beehiiv | cta-button | 420 | $380 | Primary driver | |
| x | social | t5-cta | 260 | $90 | Final tweet wins |
| social | slide-6 | 180 | $40 | Lower intent audience |
Newsletter RPV beats social, not surprising. The actionable bit: thread revenue concentrated on t5-cta, so next launch you lead with pricing proof in tweet one instead of burying it.
Without utm_content on tweets, the whole thread is one blob and you rewrite hooks blindly.
Partner and affiliate links without chaos
Partners want ?ref=partner-a. Keep partner id in utm_source=partner-a and utm_medium=referral so your main table stays consistent. Document partner slugs in the dictionary; do not let each partner invent query keys you merge manually.
Pay revenue share using billing data, not UTMs alone, tagged links under-count when buyers return direct later.
Paid ads later (even small budgets)
If you spend $200 on Meta or Google, add utm_medium=cpc and a campaign per ad set. Indie budgets are tiny; you still want to know if the experiment beat zero. Compare paid RPV to organic social RPV in the same week, pause losers fast.
Cleaning old campaigns
Once a year, archive campaigns older than 18 months in your dictionary (not in analytics data). Write one sentence per archived slug: what it was. Prevents reusing spring-launch for a different product era.
Where KiboData fits (no oversell)
You need first-pageview UTM capture, a revenue column beside source, and pinned weeks for sends. KiboData does that for self-serve stacks with webhooks; it does not replace ad platform reporting or solve identity across devices. Free tier works if you accept the badge; lifetime removes it. That is the trade, not a guarantee of more revenue.
Failure modes checklist
- Shortener stripped params → stop using it for primary CTAs.
- Same campaign name for six launches → rename with month prefix.
- Tagged internal nav → strip UTMs on in-app links.
- Compared 48h email revenue to 28d baseline → use a 7-day pin instead.
Pick one broken habit from the checklist, fix the next send, then read revenue by source on day seven. That loop is the whole job until you hire marketer number two.