UTM parameters tell you which channels bring customers. You post on HN, reddit, twitter, send emails - UTM shows you which one actually converts.
How it works: add tags to your URLs. When someone clicks https://yourapp.com?utm_source=reddit&utm_campaign=launch, you know they came from reddit. When they subscribe later, you know reddit brought that customer.
This answers the real question: where should you spend your time? If HN brings 20 customers and reddit brings 2, focus on HN.
What you track:
utm_source: which channel (reddit, hackernews, twitter, email, blog). Always required.
utm_medium: type of channel (social, email, referral). Optional but useful.
utm_campaign: specific effort (launch-week, producthunt, show-hn). Use this to group related posts.
utm_content: for testing different versions (blue-cta, text-link). Most people don't need this.
utm_term: paid search keywords. Only matters if you run ads.
Real example:
You launch your product. You post in three places:
- HN:
yourapp.com?utm_source=hackernews&utm_campaign=launch - Reddit:
yourapp.com?utm_source=reddit&utm_campaign=launch - Twitter:
yourapp.com?utm_source=twitter&utm_campaign=launch
After 2 weeks you check Stripe customer metadata. Results: HN brought 15 customers, reddit brought 3, twitter brought 1. Now you know: focus on HN, occasionally post to reddit, skip twitter.
Without UTM tracking you'd see "19 new customers" with no idea where they came from. You'd keep doing everything, wasting time on channels that don't work.
Naming that actually works:
Keep it simple and consistent. Use lowercase with hyphens. Pick a pattern and stick to it.
Good patterns:
- HN posts: all use
utm_source=hackernews - Reddit posts:
utm_source=redditwith different campaigns per subreddit - Email:
utm_source=emailwith campaign for each send - Blog:
utm_source=blogwith campaign per post
Bad patterns:
utm_source=social(which platform?)utm_source=hackernews-feb-15-2024(too specific, can't aggregate)utm_campaign=campaign1(meaningless)- Mixing
Twitter,twitter,Twitter-Social(inconsistent)
How to capture this:
The simplest approach: save UTM parameters to cookies when someone lands on your site, then attach those to the customer record when they subscribe.
Client-side (10 lines of code):
const params = new URLSearchParams(window.location.search);
const source = params.get('utm_source') || 'direct';
const campaign = params.get('utm_campaign') || 'none';
// save for 30 days
document.cookie = `utm_source=${source}; max-age=2592000; path=/`;
document.cookie = `utm_campaign=${campaign}; max-age=2592000; path=/`;Then when creating a Stripe customer, read those cookies and save to metadata:
const customer = await stripe.customers.create({
email: email,
metadata: {
utm_source: getCookie('utm_source'),
utm_campaign: getCookie('utm_campaign'),
}
});Now you can query Stripe to see customers by source. See the web attribution guide for the complete implementation.
Why 30 days:
Someone sees your HN post today, thinks about it, comes back next week and subscribes. The cookie needs to last long enough to remember they came from HN. 30 days covers most journeys. Some people use 90 days.
Analyzing the data:
After a few months, check which sources bring customers:
SELECT
metadata->>'utm_source' as source,
COUNT(*) as customers,
SUM(mrr) as total_mrr
FROM stripe_customers
WHERE created_at > '2024-01-01'
GROUP BY source
ORDER BY customers DESC;Results tell you where to focus. If HN brings 40 customers and reddit brings 5, you know HN works 8× better. Now you can make decisions: post more on HN, maybe skip reddit entirely.
Common patterns:
Organic channels (most people):
- HN posts bring high-intent users who stick around
- Reddit posts work in niche communities
- Blog posts compound over time from SEO
- Email to existing audience converts well
Paid channels (if you run ads):
- Google Ads:
utm_source=google&utm_medium=cpc&utm_campaign=search-2024 - Twitter Ads:
utm_source=twitter&utm_medium=cpc&utm_campaign=promoted-tweet
Partner referrals:
utm_source=partner-techcrunch&utm_medium=referral&utm_campaign=reviewutm_source=integration-zapier&utm_medium=referral&utm_campaign=directory
When to skip tracking:
Don't add UTM to internal links (navigation, footer, docs). That's noise. Only track external channels where you're actively promoting.
What this enables:
Once you have attribution data, you can calculate which channels are worth your time. HN post takes 1 hour, brings 15 customers. Blog post takes 3 hours, brings 5 customers but compounds via SEO. Reddit post takes 20 minutes, brings 3 customers.
Now you can optimize for your actual constraint (your time) instead of guessing what works.
See also: web attribution for complete Stripe integration, apple apps for App Store tracking
Quick setup:
- Add UTM to every link you share (HN, reddit, twitter, email)
- Save UTM to cookies on landing (10 lines of JS)
- Attach cookies to Stripe customer metadata on signup
- Query Stripe every month to see which sources bring customers
- Focus on what works, skip what doesn't
This is free, takes 30 minutes to set up, and tells you exactly where your customers come from.