Why this matters
Averaging across go-to-market motions hides everything. Self-serve and sales-led customers behave nothing alike:
- Self-serve activates in days, churns fast, has tiny ACV, compounds via word-of-mouth.
- Sales-led activates in weeks, churns slowly, has 30x ACV, requires a CSM.
A blended “30-day activation rate” tells you nothing useful about either. The PM looks at the number, sees 25%, doesn’t know whether to ship a self-serve onboarding fix or hire another CSM. Most dashboards never split the cohorts because nobody wired up the source signal at signup.
Agentry’s HogQL splits cohorts by source in one query and shows the two ICPs side by side. The strategic conversation gets unblocked.
What you get
- Two cohorts (self-serve, sales-led) with their 30/60/90-day rates for activation, retention, upgrade
- The metric where the gap is largest (= where the GTM playbook should differ most)
- A public dashboard you can show the leadership team
Walk through it
Split signups into self-serve (signed up via /pricing) vs sales-led (signed up after a demo). Compare their 30/60/90-day activation, retention, expansion.
Building the two cohorts first.
agentry_create_cohort {
project_id: "default",
name: "self_serve_q1",
description: "Signups that came through /pricing (no preceding demo event)",
filters: [
{ event: "signup_completed", properties: { signup_path: "/pricing" }, since: "90d" }
]
}
{ "cohort_id": "coh_ss_1", "member_count": 1840 }
agentry_create_cohort {
project_id: "default",
name: "sales_led_q1",
description: "Signups that completed a demo before signing up (within 30d)",
filters: [
{ event: "demo_completed", since: "120d" },
{ event: "signup_completed", since: "90d" }
]
}
{ "cohort_id": "coh_sl_1", "member_count": 168 }
1,840 self-serve vs 168 sales-led. Now run the comparison.
agentry_analytics_query {
project_id: "default",
hogql: "WITH self_serve AS (SELECT distinct_id, min(timestamp) AS signup_ts FROM events WHERE event = 'signup_completed' AND properties.signup_path = '/pricing' AND timestamp >= now() - INTERVAL 90 DAY GROUP BY distinct_id), sales_led AS (SELECT distinct_id, min(timestamp) AS signup_ts FROM events WHERE event = 'signup_completed' AND distinct_id IN (SELECT distinct_id FROM events WHERE event = 'demo_completed' AND timestamp >= now() - INTERVAL 120 DAY) GROUP BY distinct_id), metrics AS (SELECT 'self_serve' AS cohort, count(DISTINCT s.distinct_id) AS n, countIf(DISTINCT s.distinct_id, exists(SELECT 1 FROM events e WHERE e.distinct_id = s.distinct_id AND e.event = 'first_project_created' AND e.timestamp < s.signup_ts + INTERVAL 30 DAY)) AS activated_30d, countIf(DISTINCT s.distinct_id, exists(SELECT 1 FROM events e WHERE e.distinct_id = s.distinct_id AND e.event = 'subscription_started' AND e.timestamp < s.signup_ts + INTERVAL 60 DAY)) AS paid_60d, countIf(DISTINCT s.distinct_id, exists(SELECT 1 FROM events e WHERE e.distinct_id = s.distinct_id AND e.event = 'plan_changed' AND e.properties.to_plan_rank > e.properties.from_plan_rank AND e.timestamp < s.signup_ts + INTERVAL 90 DAY)) AS expanded_90d FROM self_serve s UNION ALL SELECT 'sales_led', count(DISTINCT s.distinct_id), countIf(...), countIf(...), countIf(...) FROM sales_led s) SELECT * FROM metrics"
}
{
"rows": [
{ "cohort": "self_serve", "n": 1840, "activated_30d": 920, "paid_60d": 184, "expanded_90d": 22 },
{ "cohort": "sales_led", "n": 168, "activated_30d": 134, "paid_60d": 134, "expanded_90d": 41 }
]
}
The contrast is dramatic:
| self-serve | sales-led | |
|---|---|---|
| n | 1,840 | 168 |
| activated 30d | 50% | 80% |
| paid 60d | 10% | 80% |
| expanded 90d | 1.2% | 24% |
Volume is 11x on self-serve. Conversion is 8x better on sales-led. Expansion is 20x better on sales-led.
Strategic read: self-serve is correctly funded if your ACP is low and you want compounding. Sales-led is correctly funded if you can run a sales motion with that conversion. The MIDDLE — generic onboarding that treats them the same — is wrong for both.
Specifically: your sales-led activation gap (50→80%) is a sales-engineering job, not a product job. Self-serve’s pay-conversion gap (10% vs 80%) is the standard PLG funnel improvement, worth investing.
The output
Self-Serve vs Sales-Led — last 90d cohort
METRIC SELF-SERVE SALES-LED RATIO COMMENTARY
n (signups) 1,840 168 11.0x Volume lives in self-serve
activated 30d 50% 80% 0.62x Sales-led activates better
paid 60d 10% 80% 0.13x Sales-led converts 8x better
expanded 90d 1.2% 24% 0.05x Sales-led expands 20x better
WHERE THE PLAYBOOKS DIVERGE:
Self-serve activation: 50% → improve via in-product onboarding
Self-serve conversion: 10% → improve via trial UX, pricing page
Sales-led activation: 80% → already strong, hold the line
Sales-led conversion: 80% → CSM quality issue, hire to match deal flow
IMPLIED ARR (rough, assuming self-serve $50/mo, sales-led $1,500/mo):
Self-serve 60d revenue: 184 × $50 = $9,200/mo new
Sales-led 60d revenue: 134 × $1,500 = $201,000/mo new
→ Sales-led drives 95% of revenue from 8% of accounts.
Strategic question: are we under-investing in sales given that ratio?
Setting it up
The only new requirement is knowing how each signup arrived. Capture it on the signup event:
// On signup completion, attach the path that brought them
await fetch(`https://api.agentry.sh/v1/analytics/${process.env.AGENTRY_PROJECT_ID}/`, {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.AGENTRY_DSN}`,
"Content-Type": "application/json",
"User-Agent": "myapp/1.0", // REQUIRED — Cloudflare 403s default UAs
},
body: JSON.stringify({
event: "signup_completed",
distinct_id: user.email,
properties: {
signup_path: user.signup_path, // "/pricing" | "/demo" | "/start" | etc.
had_demo: user.last_demo_at != null,
utm_source: user.utm_source,
},
}),
});
// Fire demo_completed from your demo-booking tool's webhook (Calendly, etc.)
await fetch(`https://api.agentry.sh/v1/analytics/${process.env.AGENTRY_PROJECT_ID}/`, {
method: "POST",
headers: { /* same */ "User-Agent": "myapp-calendly/1.0" },
body: JSON.stringify({
event: "demo_completed",
distinct_id: bookingEmail, // ← MUST match what they sign up with
properties: { ae: bookingAssignee, demo_outcome: "qualified" },
}),
});
If you can’t reliably fire demo_completed, an OK fallback is the signup-path heuristic alone (/pricing = self-serve, /contact-sales = sales-led).
Variations
- “Same split but for last quarter only — has the ratio changed since we added the AE team?”
- “Build the same comparison for 3 sub-cohorts: low ACV self-serve, mid-market sales-led, enterprise sales-led.”
- “For sales-led only, compare activation rate by AE. Which reps are best at handoff?”
- “For self-serve only, find users who didn’t activate in 30d but came back at 60d and DID activate. What did they do differently?”