← All articles

GTM Operations

Renewals Convert at 90%. Your Expansion Runs on Luck.

Expansion is 52% of new revenue and the cheapest dollar you can book, yet most teams have no instrumented signal for it. Here is the build ladder, the queries, and the trigger that turn it into a motion.

· 15 min read

Ask a CS team how they handle renewals and you get a system: a 90-day-out task, a health check, a playbook, a forecast line. Ask the same team how they handle expansion and you get a shrug and a story about the time a customer happened to ask for more seats. Renewals convert north of 90% because someone instrumented them years ago. Expansion limps along at whatever the customer thinks to request, because nobody ever did. For years the accepted answer was to hope the good accounts grow and to let the CSM notice when they do. That hope is the whole problem.

The gap is expensive in a way most teams never put a number on. Expansion is 52% of new revenue on 2025 figures (gradient.works, 2025), and it costs $0.80 to book a dollar of expansion ARR against $1.63 to acquire it net-new (Aleph and Benchmarkit, 2026). You are leaving the cheapest, highest-margin revenue in the building on the table because nobody built the signal that says “this account is ready to grow, go now.” I have run books where the only expansion that closed was the expansion a customer volunteered, which is a polite way of saying we booked whatever fell in our lap. Here is the ladder I climbed to stop relying on luck and instrument the signal instead.

52%
Of new revenue is expansion (gradient.works 2025)
$0.80
Cost per $1 expansion ARR vs $1.63 net-new (Aleph x Benchmarkit)
102% / 110%
Median vs top-quartile NRR (Aleph x Benchmarkit 2026)

This is the framework, and it is a build order, not a checklist. Five rungs, bottom to top, each one useless without the one beneath it. A trigger with no signal is noise; a signal with no usage data underneath it is a guess. Scroll the ladder, then I will show you the math, the queries, and the flow under every rung.

Build it bottom to topThe expansion-signal stack
  1. L5Forecast it like a renewalone line

    Expansion goes in the pipeline with a conversion rate and gets inspected in the same cadence as renewals. Once it is a forecastable line instead of a shrug, it competes with new logo for attention, which is the only way it gets worked every week.

  2. L4Wire the trigger, not the reportdaily

    A daily Flow reads the mirrored fields, creates one play per account per signal, and pings the CSM. The idempotency guard is the part people skip and regret. Without it the schedule spams a fresh task every morning and the CSM mutes it.

  3. L3Layer multi-product adoption2nd SKU

    Flag the first meaningful use of a non-primary SKU. This is the highest-value signal when it fires, because a second-module account expands far more and churns far less, but it fires least often, so it rides on top of saturation, never replaces it.

  4. L2Compute the saturation signals90% / 80%

    Turn raw usage into two ratios: active seats over licensed seats, and consumption over entitlement. These are the signals customers feel as friction. Fixed thresholds, agreed in writing with the CS lead.

  5. L1Land raw usage in the warehouseweekly

    One row per account per week with active seats and consumption. This is the substrate. If you cannot see weekly usage per account, you have nothing to threshold against and every rung above this is theater.

Locate yourself on that ladder. Most teams sit below L1, expanding whoever raises a hand. Every rung above subtracts a piece of the luck: L2 replaces “I think the big accounts are ready” with a number, L4 replaces the weekly report with a same-day play, and L5 makes the whole motion visible on the forecast where it can be managed. By the top rung expansion behaves like renewals, on schedule and inspected, instead of arriving by accident.

NRR is the scoreboard, and the median is only 102

Net revenue retention is the number that says whether your installed base grows on its own before a single new logo signs. The median across B2B SaaS is 102% and the top quartile is 110% (Aleph and Benchmarkit, 2026, n=230). The distance between those two numbers is an expansion gap, not a churn gap. Median gross retention is 84% (Aleph and Benchmarkit, 2026), so the teams pulling NRR to 110 are not the ones who churn less. They are the ones who expand more. In the books I have run, usage-priced accounts out-retain seat-priced ones by a wide margin, and the benchmark agrees: NRR runs 108% on usage pricing versus 98% on seats (Aleph and Benchmarkit, 2026), because usage models instrument expansion into the product while seat models wait for a human to ask.

Move the pieces and watch NRR respond. This is the calculation that decides whether your book is an escalator going up or a leak you keep refilling.

Net revenue retention: expansion minus churn on the base

net retention

Try

Above 100% the existing book grows on its own before a single new logo signs. Below 100% you are running up a down escalator: new sales have to refill the leak before they add anything.

net retention: 110.0%

Notice what the formula makes obvious. At 84% gross retention you need 18 points of expansion on the base to reach the 102 median, and 26 points to reach the 110 top quartile. Expansion is the entire distance between a mediocre book and an elite one, which is the compounding argument I make in full in why NRR compounds. The rungs on the ladder above exist to manufacture those points on purpose rather than hope for them.

The four signals that predict expansion (rung L2 and L3)

Expansion looks random only when you are not watching the right fields. Four signal families predict it, and all four already sit in your usage data and your CRM. The work is to stop treating them as trivia and start treating them as a ranked queue.

SignalWhat it meansThreshold I trigger onWhere it lives
Seat saturationActive users approaching licensed seatsActive seats at or above 90% of purchasedProduct / IdP logs
Usage saturationConsumption near the plan ceiling3 of last 4 weeks above 80% of entitlementProduct usage / warehouse
Multi-product adoptionAccount using a second moduleFirst meaningful use of a non-primary SKUProduct feature flags
Engagement depthMultiple active stakeholders, rising3 or more weekly active users across 2 or more teamsProduct + CRM contacts

The most reliable of these is seat saturation, because it is the one the customer feels as friction. When active users hit the licensed ceiling, someone is getting turned away, and that someone is your expansion conversation walking in the door. Usage saturation runs close behind on usage-priced deals. Multi-product adoption is the highest-value signal when it fires, because a second-module account expands far more, but it fires least often, so you rank it on top and never wait for it alone.

Instrument the signal: the query (rung L1 to L2)

A signal you cannot query is a hope. Here is the expansion-signal query I stand up first. It runs against a warehouse table that unions weekly product usage with each account’s entitlement from the CRM mirror, finds accounts where active seats press the licensed ceiling and consumption has stayed high for a sustained stretch, then ranks them by ARR so the biggest opportunities surface first.

-- Accounts ready to expand: seat and usage saturation, ranked by ARR.
-- usage_weekly: one row per account per week with active_seats and usage_pct
-- accounts:    sfdc mirror with licensed_seats, arr, csm_owner
with recent as (
  select
      account_id,
      max(active_seats)                          as peak_active_seats,
      avg(usage_pct)                             as avg_usage_pct,
      count(*) filter (where usage_pct >= 0.80)  as weeks_over_80
  from usage_weekly
  where week_start >= dateadd('week', -4, current_date)
  group by account_id
)
select
    a.account_id,
    a.account_name,
    a.arr,
    a.csm_owner,
    a.licensed_seats,
    r.peak_active_seats,
    round(r.peak_active_seats::float / nullif(a.licensed_seats, 0), 2) as seat_saturation,
    r.avg_usage_pct,
    r.weeks_over_80
from accounts a
join recent r on r.account_id = a.account_id
where r.peak_active_seats::float / nullif(a.licensed_seats, 0) >= 0.90
  and r.weeks_over_80 >= 3
order by a.arr desc;

That query is the difference between “I think the enterprise accounts are probably ready” and “these eleven accounts crossed 90% seat saturation and stayed above 80% usage for three of the last four weeks, ranked by ARR.” One of those you can work on Monday. The comparison operators live inside the code block where they belong, so the greater-than-or-equal reads as >= without breaking the prose. Store the thresholds in one place; if ten dashboards each hardcode their own saturation cutoff, you have ten signals and no signal.

Turn the signal into a trigger, not a report (rung L4)

A weekly report of expansion-ready accounts beats nothing, and it is still too slow. The moment a customer hits a seat ceiling is the moment their intent peaks, and by the next Monday report the moment has cooled. Wire the signal to a trigger so the CSM gets the play the day it fires. In Salesforce that is a scheduled Flow reading the warehouse-synced fields, creating a task, and posting to the CSM. Here is the flow logic as the artifact, not a description of it.

# Flow: Account | Create Expansion Play on Saturation Signal
trigger:
  type: schedule
  frequency: daily          # runs 07:00, before the CSM's day starts
  object: Account
entry_conditions:            # all must be true
  - Seat_Saturation__c >= 0.90
  - Weeks_Over_80__c   >= 3
  - Expansion_Play_Open__c = false     # idempotency guard: no duplicate plays
  - Type = 'Customer'
actions:
  - create_task:
      subject: "Expansion signal: {!$Record.Name} at {!$Record.Seat_Saturation__c} seat saturation"
      owner:   "{!$Record.CSM_Owner__c}"
      due:     TODAY + 2
      priority: High
  - update_record:
      Expansion_Play_Open__c: true     # flip the guard so tomorrow's run skips it
      Expansion_Signal_Date__c: TODAY
  - post_slack:
      channel: "{!$Record.CSM_Slack_Channel__c}"
      message: ">:chart_with_upwards_trend: *{!$Record.Name}* hit {!$Record.Seat_Saturation__c} seat saturation. Play created, due in 2 days."

The Expansion_Play_Open__c guard is the part people skip and then regret. Without it the daily schedule creates a fresh task every morning the account stays saturated, and the CSM drowns in duplicate plays and stops trusting the trigger. Flip the guard when the play opens and clear it when the play closes or the renewal books. That is the same idempotency discipline that keeps any scheduled automation from spamming its own users, covered in idempotent automations. A trigger that cries wolf gets muted, and a muted trigger has quietly become a report again.

A worked example that reconciles to the scoreboard

Take a book of 200 accounts averaging $60K ARR, so a $12M base. Say 12% cross the seat-saturation threshold in a quarter, which is 24 accounts. Before the ladder, the CSM works the 6 who happened to ask. After it, the CSM works all 24 the trigger surfaces. Watch the two paths diverge on the same accounts.

Instrumented expansion on 24 saturated accounts
Instrumented expansion works every account that crosses the threshold, not just the handful who volunteer. Of the 24 the signal surfaces and the CSM works, 12 convert.
View as table
ItemValue
Surfaced24 accts
Worked24 accts
Converted12 accts

Put the money on it. If half of the 24 convert at a 25% seat uplift, that is 12 accounts times $15K, or $180K of expansion ARR in a quarter that used to run on luck. Here is the reconciliation to the NRR scoreboard at the top of the page.

LineAccidentalInstrumented
Accounts saturated in quarter2424
Accounts worked624
Conversions at 50%312
Expansion ARR / quarter (25% uplift)$45K$180K
Annualized expansion on the $12M base$180K$720K
Points of NRR from this signal alone1.5 pts6.0 pts

The instrumented path adds 6 points of NRR against the same base from one signal. At 84% gross retention, 6 points is most of the 8-point climb from the 102 median to the 110 top quartile. The signal did not create demand; it caught demand you were already generating and letting cool. And it caught it at $0.80 per dollar of ARR, against the $1.63 you would spend acquiring the net-new equivalent, which is the whole reason expansion is the first dollar to instrument and the last to skip.

Where expansion sits in the motion

Expansion is the right side of the bowtie, the part of the revenue engine that starts after the deal closes and that most orgs still run without instrumentation. The signal fires from the product, the warehouse ranks it, the trigger routes a play, and the expansion books as either a CSM-owned seat add or an AE-owned handback for a larger cross-sell. The wiring matters as much as the signal.

The expansion loop From usage signal to booked expansion
Product usageseats + consumptionSignal queryrank by ARRDaily triggerplay + SlackCSM: seat addAE: cross-sell
The product emits the signal, the warehouse ranks it, the trigger routes a play, and the CSM or AE closes it. Every arrow is instrumented, not assumed.

That handback, deciding when a signal stays with the CSM and when it routes to an AE, is the seam where expansion revenue leaks most, and it is the half of CS that usually goes unbuilt. I cover the ownership model for it in the missing half of CS ops and the full right-side architecture in the right side of the bowtie.

Accidental versus instrumented

Accidental expansion Instrumented expansion
Trigger Customer thinks to request more Saturation crosses 90%, play fires next morning
Coverage The handful who volunteer Every account that crosses the threshold
Timing Whenever, often after friction festers The day intent peaks
Forecast Unforecastable, "we hope" A pipeline line with a conversion rate
NRR effect Stuck near the 102 median Climbs 6 points toward the 110 top quartile
Same accounts, same product usage. The only difference is whether a signal fires or a customer happens to ask.

The four-week build

Four weeks, roughly. The first two are plumbing, the second two are the motion. This is the ladder turned into a calendar, built in dependency order because a trigger with no signal is noise and a signal with no play is a report nobody reads.

Standing up the expansion motion
  1. 1

    Define the thresholds with the CS lead, in writing

    Agree what seat saturation, usage saturation, and multi-product adoption mean numerically for your product. 90% of seats, 80% usage for 3 of 4 weeks, first non-primary SKU use. Vague thresholds produce a signal nobody trusts. Write the numbers down and version them.

  2. 2

    Land the usage fields in the CRM (rung L1)

    Sync Seat_Saturation__c, Weeks_Over_80__c, and a multi-product flag from the warehouse onto the Account daily. The signal query runs in the warehouse; the trigger runs on the mirrored fields. Compute in SQL, act in Flow.

  3. 3

    Ship the ranked signal query (rung L2 to L3)

    Stand up the SQL above, ranked by ARR, and review the output with the CS lead for a week before automating anything. If the accounts it surfaces are obviously right, the thresholds are calibrated. If they are junk, fix the thresholds, not the automation.

  4. 4

    Wire the trigger with an idempotency guard (rung L4)

    Build the daily Flow with the Expansion_Play_Open__c guard so it creates one play per account per signal, not one per morning. Route the play to the CSM with a Slack ping. Clear the guard when the play closes or the renewal books.

  5. 5

    Forecast it and inspect it like renewals (rung L5)

    Put expansion in the pipeline with a conversion rate and inspect it in the same cadence as renewals. Once expansion is a forecastable line instead of a shrug, it competes for attention with new logo, which is the only way it gets worked consistently.

Renewals convert at 90% and expansion runs on luck for one reason: renewals got instrumented years ago and expansion never did, not because expansion is harder to close. The signals already sit in your data. The query is 30 lines. The trigger is one Flow with one guard. Build the thresholds this week, ship the ranked query next, wire the trigger the week after, and stop booking only the expansion that walks in the door. The dollar you were leaving on the table is the cheapest dollar in the business, and the ladder is how you pick it up on schedule instead of by accident.

expansion nrr signals

Keep reading

One email. Every week.

One email a week: an operating problem I solved or botched, with the model, the numbers, and what I would change. No roundups, no theory, unsubscribe whenever it stops being useful.

The newsletter opens soon.

Connect a provider in src/config.ts