How Long Is a Buying Signal Worth? Time Decay, Weights, and Verification
Every buying signal has a shelf life, and most GTM systems never write it down. A job change is worth acting on for months. A hiring spike is stale in weeks. Serve both to a rep with the same weight and no expiry, and the rep chases last spring’s news with a reason that no longer holds. The fix is small: give each signal type a window and a weight, verify the signal before it counts, and stop serving it when the window closes.
John Kutay, who runs growth and GTM engineering at Rippling, described how they do this in his talk on Rippling’s Growth OS, for a system with 2,000 internal monthly users processing over a billion rows a day. The mechanics are the same at a startup.
Not every signal is equal #
Rippling keeps a large catalog of signals, but a handful are canonical: a job change, a funding round, a new office opening. Those are ranked high and handed to the rep as the reason, when the account is in the addressable market and matches the ICP. Everything else is ranked below them in different ways.
That split is the first decision to make: which signals are strong enough to be the reason for a touch on their own, and which only nudge a score. Most teams skip it and end up with a single intent number made of thirty ingredients, which a rep cannot explain to a prospect and a model owner cannot debug.
The simplest decay is a WHERE clause #
Asked how they set the decay per signal, John’s answer was refreshingly plain: it is a filter. How recent was the signal? If it is outside the window, it is not served to the rep.
-- Serve only signals still inside their window.
SELECT s.*
FROM signals s
JOIN signal_types t ON t.slug = s.type
WHERE s.observed_at >= now() - t.window
The windows he gave: three to six months for a job change, a little longer for an office opening, and much fresher for hiring activity. The numbers matter less than the fact that each type has one, it is written down, and it is in a table you can change with a reviewed diff instead of a setting nobody remembers.
Start with a hard window. It is easy to reason about, easy to explain (“we only flag job changes from the last four months”), and it removes most of the stale noise on day one.
When to add weights and a curve #
A hard window treats a signal from yesterday and one from 89 days ago the same. Once the window is working, the next step is a weight that falls over time. An exponential half-life is the usual shape:
-- Weight halves every half_life; zero outside the window.
SELECT s.account_id,
SUM(t.weight * power(0.5, extract(epoch FROM now() - s.observed_at)
/ extract(epoch FROM t.half_life))) AS intent
FROM signals s
JOIN signal_types t ON t.slug = s.type
WHERE s.observed_at >= now() - t.window
GROUP BY s.account_id
Two rules keep this honest:
- Set weights from outcomes, not intuition, as soon as you can. Which signal types preceded meetings and pipeline last quarter? That is a query, not a debate. Until you have the data, a reasoned guess written in a file beats an unreviewed guess in a tool.
- Keep the canonical signals as reasons, not just points. A rep needs “they raised a round three weeks ago”, not “intent is 74”. The score ranks the list. The signal is what goes in the first line.
Verify before it counts #
The step most teams skip comes before any of this. In John’s words, raw signals need verification.
A signal arrives as a fragment: someone changed jobs, a company raised money. Before it can mean anything, it has to be resolved to an account and a contact you already know, checked against what the CRM says, and confirmed to be what it looks like. A funding headline about a company with a similar name is not a signal. It is a false positive with a timestamp.
Rippling does this with coding agents. The question they encoded is how a human would check this: pull the record from the CRM, compare the sources, decide. The agent gets the same tools and makes the same decision, with evaluations run against it before the pipeline ships. Only verified signals go live for sellers.
Verification is also where decay starts. The clock runs from when the event happened, not when you found out. A job change your provider reported in September that happened in May has already used most of its window.
What to write down #
A signal catalog is one table, and it belongs next to the scoring model in your repository:
| Field | Example | Why |
|---|---|---|
slug | job_change | The stable key every play references |
canonical | true | Can this be the reason for a touch alone |
window | 120 days | After this, it is not served |
half_life | 45 days | How fast its weight falls inside window |
weight | 3 | Relative strength against other types |
verified_by | agent:resolver | What confirms it before it counts |
When a rep says an alert was stale, the answer is a one-line pull request against this table, reviewed and reversible. When it lives in a vendor’s settings, the answer is a shrug.
For the wider pattern, see signal-based selling and operationalizing custom signals.
FAQ #
It depends on the type. Rippling serves job changes for roughly three to six months, office openings a little longer, and hiring activity for a much shorter window. Give every signal type its own window, write it down, and stop serving the signal once the window closes.
Time decay reduces the weight of a buying signal as it ages, so recent events count more than old ones. The simplest version is a hard expiry window. A more precise version applies a half-life so the weight falls gradually until the window ends.
Use both. A score is useful for ranking accounts, but the strongest signals, such as a job change or a funding round, should also be passed to the rep as the explicit reason for reaching out, because a number alone gives them nothing to say.
Because raw signals are fragments. A signal has to be resolved to a known account and contact and checked against existing records before it is trusted, or reps act on false positives such as news about a similarly named company.