Team Meeting: Jul 28, 2026

2026-07-28 · Ben · digest

Week of Jul 21 → Jul 27. Receipts, not lessons. Four things went live on production, one of them fixed a bug that was quietly costing us money, and one closed a loop that had been open since the affiliate programme started. Every item cites the tag or version it shipped under.

Headline

The affiliate money path was leaking attribution and, on some requests, leaking clicks entirely — both are fixed and verified live. Half of every traced NordVPN dollar could not be tied to the page that earned it, popup revenue was being credited for gateway sales, and any visitor whose browser carried a cookie with a stray % character got a dead redirect instead of a purchase. And by the end of the week the loop was closed: Nord's conversion postback is wired up and verified, so a purchase now traces back to the exact click that produced it. Alongside it: the rich FAQ system went site-wide across ~126 pages in 16 languages, domain-broker v2 went permanent on /domain-broker/, and the get-started paid lander is now running its own A/B.


🚀 MAIN ITEM — Affiliate attribution rebuilt end to end

WHAT

Five deploys on vpn-out (073ea3a70d9546b51e024a2eb79af5b5aa87c22e), one on vpn-translate (d2299217), 11 partner configs re-slotted in PARTNERS_KV, and two D1 migrations.

1. The gateway was throwing away the content page. Our /out interstitial is served at /out, so when a visitor clicked its buy button the referrer was /out and the real page was lost. 371 NordVPN clicks in July reached the affiliate labelled _out — meaning half of all traced revenue was unattributable to any page. All 12 gateway CTAs now carry the origin page explicitly.

2. Popup revenue was being over-credited. The popup slot took whatever A/B cookie was in the browser, and those cookies live 30 days. So a visitor who saw a popup once and bought through the gateway a week later reported as a popup conversion. Corrected read: the gateway is the top earner — $900 of July's $1,257 (72%). True popup revenue was $270 (21%). Worse, the domain-broker hero A/B — a lead form test — was leaking its variant onto 43 affiliate URLs.

3. A live 500 on the money path. /out parsed every cookie in the jar unguarded, so one bare % in any cookie — a consent or analytics cookie we never even read — threw an error and killed the redirect. Confirmed live before the fix: production returned 500, the patched build returned 302. Duration unknown; it was silently losing sales.

4. Landing page now exists. It didn't, anywhere. /out only sees the click, never the arrival, so vpn-translate (routed on every page) now stamps the session's entry page into a cookie that /out reads at click time.

5. One schema across every partner. Slots previously meant different things per partner — aff_sub2 was the page for NordVPN and the placement for Proton, so any combined report was silently wrong.

6. And the loop is now closed on Nord. With the schema standardised, a per-click ID could finally ride the link and come back on the sale. We can trace a purchase to the click that made it — see the postback item below.

SlotNow carries
sub1referring page (where the click happened)
sub2landing page (where the visit started)
sub3exit-intent popup, when applicable
sub4use case
sub5placement — reclaimed from a hardcoded constant sent on every click ever made

WHY

Because we were optimising blind and didn't know it. The July affiliate report looked healthy — until the biggest single row turned out to be "we don't know where this came from," and the second-biggest was crediting the wrong thing. Every decision downstream of that report (which pages to build, which placements to push, which providers to negotiate with) was resting on it.

The 500 is the sharper point: it wasn't a reporting problem, it was lost revenue, and nothing would ever have surfaced it. It doesn't show up in conversion rate, it doesn't trip an error budget, and the visitor just sees a broken link and leaves.

Positive impact moving forward

Technical honesty for the room: two of the bugs above were found while fixing the first one, and one near-miss was mine — an early revision would have silently dropped every homepage click (~509/month) because / normalises to an empty path. A test caught it; no build gate would have. That is the argument for the gates, not for the fix.

(Notes #193, #195#199. Commits f7a5b65e8f5e2e in vpn-workers — six, still unpushed.)


Shipped (rest of the week)

NordVPN conversion postback — wired up and verified end to end (vpn-out aa87c22e, migration 0005)

We can now answer the question the affiliate dashboard cannot: which click actually bought. /out mints a per-click UUID, sends it to Nord, Nord returns it on the sale, and a join resolves the payout to the exact click — and through it the page, entry page, use-case, placement and country already on that row.

Verified live with a real postback:

transaction MANUAL-1 · nordpass · $5.00
  clicked from  /vpn/nordvpn/     landed on  /vpn/
  use case      streaming          placement  qa_pb_prod
  country       US                 click → sale: 17 min

⚠️ Read the coverage honestly — it ramps, it doesn't switch on. Only 3 of 25,378 clicks are joinable today (those minted after the deploy), and there are no real conversions yet. Nord's attribution window is ~30 days, so sales arriving over the next few weeks will often reference clicks made before this shipped: those postbacks land with an empty click_uid and won't join. That is expected, not a bug — worth knowing before someone opens the table next week and reports one. Full click-level coverage arrives as the pre-deploy click population ages out.

Available right now with no engineering: Nord's own sub-ID report can already break conversions down by page, retroactively — we've been sending the page in a sub-ID slot for weeks. That's dimension-level rather than click-level, but for deciding which pages to build it is most of the value, and nobody has pulled it.

FAQ system — site-wide, English + 16 languages (tag prod-2026-07-24-001)

Domain broker v2 — promoted to 100% on /domain-broker/ (tag prod-2026-07-22-001)

V1 vs V2 — what the data actually supports. Two findings survive scrutiny:

Domain-broker form V2 more than doubled on-page engagement and doubled median domains submitted per seller. Average time on /domain-broker/ rose from 115s (Jul 1–12, 380 sessions, V1 only) to 265s and 475s in two independently measured V2 windows (Jul 23–24, 54 sessions; Jul 13–24, 321 sessions). Median domains per seller rose from 1 (n=46) to 2 (n=14).

Source: askbowtie page metrics + D1 domain_intake / domain_intake_items, measured 2026-07-24. V2 is identified by the presence of an e-signature (agreement), the only field FormV2 can set and V1 cannot. The engagement figures are keyed on page and date, so they don't depend on inferring a form version at all — that is why they're the sturdiest numbers here.

"So did it make more money?" — not knowable yet, and this belongs in the same breath as the numbers above. CRM qualification lags submission by 20–25 days and V2 launched Jul 13, so the first V2 qualifications aren't due until early August. Zero of the V2 leads have qualified, and that is expected timing, not a bad signal. Do not let an engagement number be read as revenue.

Excluded as unreliable — do not quote these:

Get-started paid lander — A/B live (prod-2026-07-22-002, GETSTARTED_AB_ACTIVE=true)


Open items / decisions needed

1. Confirm ExpressVPN's Impact sub-ID parameter names. We're sending the documented Impact standard (subId1subId3). If it's wrong the click still pays, but it would look like working attribution while reporting nothing — the worst failure mode. One look at the Impact dashboard settles it.

2. Windscribe and Mullvad earn us $0 on ~895 clicks/month. Neither has an affiliate deal; /out sends them to the provider's own homepage. Either negotiate, or stop routing buying intent to them for free. Decision needed — this is commercial, not technical.

3. Verify PIA and CyberGhost sharing one affiliate ID. Both configs point at the same base URL with aff_id=1312, differing only by offer_id. Both are Kape brands so a shared platform is plausible and probably correct. If it isn't, PIA's commissions are landing in CyberGhost's account. 30 seconds to check.

4. Configure postbacks for the other networks — Proton first. ✅ Nord is done (see above). But Proton is 2,531 clicks/30d, effectively tied with Nord's 2,803, and it is completely dark — same for Surfshark (451), CyberGhost (480) and PIA (405). Their clicks already carry the join key and their KV slots are mapped; each just needs one entry in its own affiliate dashboard, same URL pattern. Until then we have zero visibility into whether half our outbound volume converts at all. Decision: who has dashboard access for Proton?

5. Get-started A/B — keep it running, or call it? At ~2 leads/day split 50/50 it needs weeks to say anything, and get-started volume dropped to 1 then 0 leads/day right at activation while the hub held steady. Decision: re-measure Jul 27 and kill it if the dip holds — a test that suppresses conversions while producing no verdict is worse than no test.

6. Five new languages — Hebrew, Russian, Thai, Norwegian, Polish. Infrastructure ready; the rollout is a multi-hour bulk translation job needing a green light. (Carried from Jul 21 and Jul 14 — unchanged.)

7. vpn-workers commits are local-only. Four commits from this week's attribution work are unpushed.

Metrics snapshot (7-day, bowtie)

MetricValueRead
Sessions6,518+10% wk/wk, +11% vs 4-wk avg
Conversions1,079 @ 16.6%+73% wk/wk — but see the caveat below before quoting this
/out 5xxfixedThe malformed-cookie 500 is gone; expect the error rate to fall by design
Incidents1 critical (3 sessions)Rest is low ad-block noise; two network-error clusters worth a look

⚠️ Do not quote the conversion jump as growth. Three measurement changes land inside this window: the dashboard conversions chart was fixed on Jul 23 after under-counting ~94% of conversions, conversions moved server-side on Jul 16, and the sub-ID slots changed meaning on Jul 24. Read conversion levels, not week-over-week deltas, across this period. Also filter placement LIKE 'qa_%' — QA clicks from the attribution work are in Friday's data.