Skip to main content

Activation tracking & onboarding retention

Why

WS-Starter (and API plans generally) churn at a chronic ~30-day cliff — median churner leaves at first renewal, and ~60% of every signup cohort is gone by day 45. The differentiator is activation: of currently-active WS-Starter accounts, ~79% make API requests and ~21% are dormant (paying, never integrated). Dormant-by-day-20 → churned-at-day-30. The lever is proactive onboarding of new signups — getting every new account to its first successful API call within days, while they’re still in the trial/first-month window and expecting setup help. This is deliberately scoped to new accounts: we do not email existing active, non-cancelled customers who’ve gone quiet — reminding a paying customer they’re not using the product invites a cancel decision (sleeping-dogs risk). Dormancy in an established paying account is a signal to watch (via the KPI), not to poke. This required (a) a durable activation signal — previously we only had Redis usage counters with a 31-day TTL, no “activated ever” — and (b) an automated first-week onboarding drip gated on activation.

How it works

  • v3/utils/usage_tracker.goTrackUsage writes two persistent Redis keys on every request: activation:first:{email} (SETNX, first-ever) and activation:last:{email} (SET, most-recent). No TTL, so “activated ever” is durably answerable. GetActivation(email) reads them.
  • account-service/scripts/activation_reconcile.ts — cron (~every 15 min). Denormalizes the markers into api-tokens.firstRequestAt / lastRequestAt, and the first time it observes an account activate it sets the Loops contact activated=true and sends an api_activated event (the drip’s exit condition). --dry-run supported.

Scheduling

Runs in-process via worker.ts (node-cron), same as the other account-service jobs — no separate Railway cron to configure. Scheduled at 10,25,40,55 * * * * (every 15 min, offset from the other jobs). Also runnable directly for a one-off: tsx --env-file=.env scripts/activation_reconcile.ts.

Loops setup (one-time, dashboard)

Onboarding is a Loop built in the Loops UI — no code, so timing/copy can be tuned without deploys:
  1. Create two custom contact properties: activated (boolean), apiPlan (string). No signup code change is needed: new contacts simply have activated empty, and the loop filter below treats empty as “not activated”. The reconciler sets activated=true on first request.
  2. New Loop, trigger “Contact added” filtered to API subscribers.
  3. Wait 3 daysfilter activated is not true (matches empty too) → send Day-3 setup.
  4. Wait until day 7filter activated is not true → send the Day-7 escalation email.
  5. The reconciler sets activated=true on first request, which drops them out of the loop.
Scope: this drip targets new signups only. We deliberately do not email established active, non-cancelled customers who’ve gone quiet — that invites a cancel decision. Dormancy in a paying account is a watch-signal (KPI), not an outreach trigger.

Email copy

Day 3 — “Let’s get your first API call working” (only if not activated)

Subject: Your odds-api.io key is ready — here’s your first call Hi , You’re set up on , but I noticed you haven’t made your first API request yet. Most customers are pulling live odds within 10 minutes — here’s the fastest path:
  1. Your key + a copy-paste example:
  2. Endpoints & filters:
If anything’s in the way — auth, a specific bookmaker, WebSocket setup — just reply to this email and I’ll help directly. Happy to jump on a 15-min call.

Day 7 — escalation (only if still not activated)

Subject: Still stuck getting started? I’ll set it up with you Hi , You’re a week into and haven’t made a call yet — I don’t want you paying for something you’re not using. Two options:
  • Reply with what you’re trying to build and I’ll send working code for your exact use case, or
  • Grab 15 minutes here and we’ll get you live on the call:
If odds-api.io isn’t the right fit, tell me — I’ll help either way.

The KPI

Track per signup-month cohort, not monthly revenue:
  • Day-7 activation rate — % who made ≥1 request within 7 days.
  • Day-45 survival — % still subscribed at day 45.
Dec 2025 proved lifting survival from ~15% → ~45% is achievable. scripts/_churn-analysis.ts (analysis, not committed) produces the cohort table; wire it into a weekly report once firstRequestAt has accumulated data.