LaunchBeam
All posts

attribution · analytics · paid ads

Which Launch Channel Actually Worked? Tracked Links, Small Samples and LTV

Tag every listing before launch, join clicks to signups, ignore rates from tiny samples, and judge ad spend against your own LTV rather than benchmarks.

The LaunchBeam team12 min read

Overhead close-up of two hands pulling red thread taut at a brass pushpin in the centre of a blank, faintly contoured paper map pinned to a cork board, threads running out to four more pins and two short ends finishing in loose knots, lit by a desk lamp at night

The week-after question

A week after launch you open your analytics to decide where next month's hours and dollars go. You see a handful of referrers, a long tail, and one large row labelled direct. The biggest number looks like the winner, so that's where the effort goes.

Most wrong calls at this point aren't bad channels. They're bad data: clicks that lost their origin on the way in, rates computed from a few visitors, spend counted twice, a missing number read as zero.

This post covers designing attribution before launch, and reading the result without fooling yourself, including when to keep paying for an ad and when to stop.

Why launch week breaks your analytics

Your referrer data is weakest in the one week you need it most, for three ordinary reasons.

Every listing points at the same URL. Product Hunt, a dozen directories, a Show HN post and three newsletters all link to app.example.com. Once the visitor lands, the URL says nothing about where they came from. The only clue left is the referrer header, the least reliable part of the request.

Browsers trim referrers by default. When a page sets no policy, browsers apply strict-origin-when-cross-origin. A cross-origin HTTPS link sends only the origin, never the path or query string, and a link from HTTPS to HTTP sends no referrer at all (MDN, Referrer-Policy). A link marked rel="noreferrer" omits the header entirely (MDN, noreferrer). And a link opened from a native mail or chat app usually arrives with no referrer, because no web page sent the visitor there.

No referrer and no tags means "direct". GA4 defines its Direct channel as source (direct) with a medium of (none) or (not set) (Google Analytics help). The visitor who opened your launch newsletter in a mail app and the one who typed your URL from memory land in the same bucket. In launch week a lot of real channel traffic can end up there.

One more filter sits on top. Apple's Link Tracking Protection strips the extra tracking information some sites add to URLs from links shared in Mail and Messages. In Safari, the advanced tracking and fingerprinting protection setting removes "known tracking parameters" from all URLs; it's on by default in Private Browsing, and people can switch it on for all browsing (Apple Newsroom; Safari User Guide). Neither page lists which parameters count, so don't assume any particular one survives. Send your own tracked link through Mail and Messages, open it in a Private window, and look at what actually arrives.

Aerial view at golden hour of a braided river on pale grey gravel flats, dozens of thin silver streams in the foreground converging into one broad channel that runs between low hills toward a hazy sun
Once the streams merge, nothing in the water says which one it came from.

Tag before you launch

The fix is boring, and it has to happen before the first listing goes live: every listing and every post gets its own link, either a tracked redirect or a URL with a consistent set of UTM parameters.

A link you create after a listing is approved tracks nothing, because the listing already points at your bare URL. If a directory's review queue puts your listing live weeks before launch day, the tag has to exist when you submit. The directory lead-time guide covers which ones need that much notice.

Google's guidance is to always set utm_source, utm_medium and utm_campaign, and it notes that values are case-sensitive: google and Google count as two sources (Google Analytics help). Write a convention down once and copy from it.

A hypothetical convention for a product at app.example.com:

Placement utm_source utm_medium utm_campaign
Product Hunt listing producthunt directory launch-2026-09
Show HN post hackernews community launch-2026-09
Your own Reddit post reddit social launch-2026-09
Reddit ads reddit paid launch-2026-09
A newsletter sponsorship the newsletter's name sponsorship launch-2026-09

The rules behind it: lowercase everywhere, one spelling per source, and a medium that says what kind of placement it was. That last column is what stops your Reddit ads taking credit for your organic Reddit thread. Product Hunt has quirks of its own, including a six-month submission gap for products that share a root domain (Product Hunt Help); they're in the Product Hunt timing post.

Plan for one exception: Google Ads. With auto-tagging on, Google appends a gclid click identifier to your landing URLs. GA4 gives auto-tagging priority over manual UTM tags, and there's no setting to override that (Google Ads help). For Google traffic, decide which record is the source of truth before you compare it with anything else.

Join the click to the signup

Tags tell you where a click came from, not whether it became a customer. A launch produces two disconnected facts, "400 clicks from the Product Hunt link" and "12 signups this week". Without something joining them, every channel looks equally good.

The join is a visitor id that survives the hop to your domain. Ad platforms do this with click ids: Google Ads appends gclid, and Meta appends fbclid when someone clicks an ad on Facebook or Instagram (Meta developer docs). You can do the same for your own links:

  1. Your tracked link redirects to your site with an id on the URL.
  2. Your site keeps that id and saves it on the user record when the visitor signs up, not only in a cookie.
  3. Your server, not the browser, reports the signup with the id attached.

The server does the reporting because it knows a signup really happened. A browser pixel only knows a page loaded.

Give the id a long life: a launch-week click can turn into a signup weeks later, after the visitor has seen you in three more places. And settle your credit rule before the data comes in. Last-touch, where the most recent click gets the credit, is the simplest.

Then protect anything that carries money. Tracked links are public by design, so if your endpoint accepts "purchase, $499" from anyone holding one, anyone can invent your launch-day revenue. Signup counts can stay open; revenue events should require a secret only your server holds.

"Not available" is not zero

A missing number and a zero are different facts, and dashboards love to blur them.

  • Missing permissions. Platforms decide what a connected app may read. Say your LinkedIn connection can count clicks on your own links but has no access to post impressions. The honest display is your real clicks next to "not available", not "0 impressions". The API rules that decide whether a tool may auto-post also decide what it may measure; the auto-posting API guide goes through them platform by platform.
  • Unmeasured things. A listing that went live before you made its tracked link should read "no link", not "0 clicks". A paid channel with no LTV behind it should read "no verdict", not "kill". A directory whose price you never checked isn't free.
  • Snapshots, not events. Upvotes, likes and impressions are running totals. A post at 410 upvotes at noon and 530 at six has 530 upvotes, not 940. Store each reading as a snapshot, compute the change between readings, and never add them together.

Small samples lie

One signup from two clicks is a 50% conversion rate. It's also the largest percentage on the page, so it wins every comparison. Two days later that channel has 40 clicks and still one signup, and you've already moved your week there.

Set a floor before you look: below a certain number of clicks, show the counts and no rate. LaunchBeam's Analytics page uses 20 clicks, and 20 signups one step further down the funnel. Below that it shows a dash and says why. Twenty is a product choice, not a statistical threshold, and it's still thin: at 20 clicks, each extra signup moves the rate by five points.

Linkage works the same way. If only a few signups carry a visitor id, a rate over those few describes a sliver of your traffic, not the channel. LaunchBeam's funnel refuses to compute a step's rate unless at least 80% of that step's events carry a visitor id. It shows the unlinked count beside the step, so you can tell organic signups from an integration that's dropping the id.

Judging a paid channel, in order

Order matters: the cheap, certain answers come first and the expensive judgement last. This is the sequence LaunchBeam's paid-channel verdict runs. It works as a checklist whatever tool you use:

  1. No spend recorded. Nothing to judge.
  2. Spend, but no attributed clicks. This is a tagging problem, not a dead channel. Check the utm_source on the ad's landing URL against the one you expect. Don't read it as an infinite cost per signup; that would kill what may be your best channel.
  3. Clicks, but no signups. Usually the landing page, or too few clicks to count as a sample. Watch; don't decide.
  4. No lifetime value. No verdict. Whether $80 per customer is good depends on what a customer is worth to you, and a pre-revenue product doesn't know that yet.
  5. Cost per customer above LTV. Kill it. You're paying to lose money; stop before you tune it.
  6. LTV:CAC below 3:1. Watch. It pays for itself but leaves little for everything else.
  7. Payback longer than 90 days. Watch. It's profitable, and it will eat your runway if you scale it hard.
  8. Otherwise. Scale.

The formulas are short. LTV = ARPU ÷ monthly churn rate. LTV:CAC = LTV ÷ CAC. Payback in months = CAC ÷ ARPU.

A hypothetical: ARPU is $40 a month and monthly churn is 4%, so LTV is $1,000.

Channel Spend Attributed clicks New customers CAC LTV:CAC Payback Verdict
A $1,200 310 6 $200 5:1 5 months Watch: over 90 days
B $1,500 280 1 $1,500 0.7:1 37.5 months Kill
C $300 0 0 none none none Fix the tag
D $400 45 0 none none none Watch: landing page or sample
E $600 150 6 $100 10:1 2.5 months Scale

Channel A clears 3:1 comfortably and still gets a watch, because it takes five months to return its cost.

One caution about LaunchBeam's version: it divides spend by attributed signups, not paying customers. If most signups never pay, your real CAC is higher than the figure it compares with LTV, so read its Scale as the optimistic answer.

Quiet ways to fool yourself

None of these looks like an error. Each produces a clean, plausible number that happens to be wrong.

Channels that share a source. In LaunchBeam's channel registry, Google Search, Performance Max and App Campaigns all map to one source, google. Their clicks can't be split after the fact, and dividing them by budget share is a guess dressed up as a number. Report them together and say so. If you need them apart, use Google Ads' own campaign reports; LaunchBeam matches on utm_source and can't split them.

Spend counted twice. Say you typed June's spend by hand, connected the ad account in July, and the import re-read June. Summed, spend doubles and cost per signup halves: a losing channel rendered profitable. Find the days where two records cover the same channel, and decide which one counts before you compute anything. LaunchBeam flags days where your typed or CSV entries overlap spend synced from a connected Meta ad account (a beta it switches on per workspace today) and withholds that channel's verdict until you pick a record, which you do on the Agents page. It doesn't compare typed rows with imported ones, so the same day's spend entered under two campaign labels counts twice.

Rows dropped on import. A spend import that silently skips a third of the file understates spend, so CAC comes out low: wrong in the flattering direction. Ambiguous dates are a common culprit: 03/04/2026 is two different days depending on where you live. Rejected rows should come back loudly, with a reason. LaunchBeam's CSV import accepts dates as YYYY-MM-DD only, and skips nothing silently: it tells you how many lines it rejected and shows the line number and reason for the first three.

Benchmarks: a sanity check, not a verdict

Published cost-per-click and cost-per-lead averages are good for one thing: noticing that a campaign is broken. If you're paying several times the typical click price for your channel, check the targeting and the creative first.

They can't tell you whether a channel pays. A channel at twice the average CPC can be your best one if your customers are worth a lot, and a channel at half the average can be losing money if they aren't. That's why this post quotes no benchmark figures. Without a named report and year they're folklore, and even with one they don't know your LTV. LaunchBeam shows its benchmarks beside each verdict, with the date they were compiled, and never uses them to reach it.

An antique brass balance scale on a dark, worn wooden counter, a short stack of plain brass coins on the left pan and a small corked glass jar of dried amber herbs on the right, the beam level, with rows of unlabelled brown glass bottles blurred on shelves behind
A cost per customer only means something when it's weighed against what a customer is worth.

The 3:1 target is a heuristic too, not a law. David Skok's SaaS Metrics 2.0 puts the best SaaS businesses above 3:1 LTV:CAC, and describes profitability as weak once recovering CAC takes more than 12 months. Those are sensible defaults for a company that can wait a year for its money. His definitions also adjust months to recover CAC for gross margin; the CAC ÷ ARPU formula above doesn't, so it runs shorter than his would.

LaunchBeam's verdict uses a 90-day payback target instead. That's our opinion, and it's a bootstrapper's one. If you fund acquisition from revenue or savings, a channel that takes a year to return its cost is a channel you're lending money to for a year. Pick your own thresholds; the point is to pick them before you see the results.

Policies, help pages and the Skok articles checked on September 10, 2026.

Where LaunchBeam fits

LaunchBeam builds this tracking into the launch. The first time you mark a directory submission Submitted or Live, it mints a /d/<code> link for that listing, and campaign posts carry /r/<code> links. On the Free Trial the six premium directories, Product Hunt among them, are locked and get no link. Both kinds of link redirect with utm_source, utm_medium and an lp_sid visitor id that lasts 180 days, and the Analytics page counts only traffic that arrived through them. Your server reports signups to the conversion webhook with that id; the Funnel tab shows the exact request. Trials, purchases and anything carrying a value need the product's ingest secret in the x-launchbeam-secret header; signups don't.

The Paid channels page is on Pro ($49 a month) and Scale ($149 a month), not on the Free Trial or Starter. You record spend by hand or paste a CSV export, and each channel is judged in the order above against a lifetime value computed from at least two metric snapshots, taken across the whole workspace rather than per product. Until those exist, every row reads No verdict yet. Pricing has the full plan comparison, and the docs walk through each page.

Two limits to know before you rely on it. It only sees clicks that pass through LaunchBeam's own tracked links, so clicks from an ad that sends people straight to your site, UTM tags and all, never reach LaunchBeam, and that channel reads Not tracking. And it matches on utm_source alone, not medium, so organic clicks through LaunchBeam's post and listing links that share an ad channel's source (reddit, twitter, linkedin, facebook, tiktok, youtube, g2, capterra) count toward that channel. If you post organically on a platform you also advertise on, read that row as organic plus paid.