listen · buying moments
Warm triggers
People already in your funnel.
In Buying moments
Warm triggers: people already in your funnel.
A warm trigger fires on someone who has already touched you: replied, raised a hand, signed up, paid, or left. Eleven of them, in four families. They come from your own data, so they are the most reliable signals you have, and the ones with the clearest rules about what you may send.
Buying Moments Map → Warm triggers → Detector kinds → Signal catalog → Playbook Library
Your data, your rules — No scraping and no third-party terms: replies, forms, analytics, your app and Stripe.
Permission decides the channel — Reply where they spoke; email only people who gave you the address; customers get product email.
Fix before you win back — A cancel reason is a bug report. Win-back waits until it's fixed.
what it is
A moment in someone's relationship with your product.
Industry terms: product-qualified signals, lifecycle triggers, churn signals and expansion signals. They need no detector tuning and carry no terms risk, but they come with permission rules: what the person has allowed decides the channel.
Noticing you — Paying attention, haven't signed up. · · 3 triggers · 5 detectors
Trying you — Signed up, not paying yet. · · 3 triggers · 3 detectors
Paying you — Customers, in a moment that matters. · · 4 triggers · 6 detectors
Left you — Cancelled. · · 1 triggers · 1 detectors
how it works
From a moment to a message.
- replies and mentions
- forms and waitlist
- site analytics
- your app events
- Stripe webhooks
- Owned detector — event + condition
- Signal — person · trigger · at
- Permission check — what may we send?
- Lifecycle play — nudge, rescue, win-back Conditions are joins on your own events, e.g. signed_up AND no activation within 24 hours. The permission check is a rule, not a model: they spoke first, they gave an email, or they are a customer.
step 1 — Define activation · Pick the one action that predicts paying. Every 'didn't start' and 'went quiet' trigger depends on it.
step 2 — Wire the events · Sign-ups, the activation event, Stripe webhooks, form submissions, replies.
step 3 — Set the permission rule · For each trigger: which channel is allowed, and how many touches.
step 4 — Attach the lifecycle play · Each warm trigger has one play; most are a single message.
the object
Every trigger is one record.
Triggers are the stable layer. Detectors come and go; the trigger they serve, and the play that answers it, stay put. The sample is the Trial ending, not converted trigger as VibeDraft would store it.
| Field | Type | What it holds |
|---|---|---|
trigger_id | string | Stable slug, e.g. trg.tried-it-and-it-failed. Every signal and lead carries it. |
name / aka | string | The guide's plain name and the industry term (e.g. competitor dissatisfaction). |
side | cold | warm | Strangers in public, or people already in your funnel. |
family | enum | One of nine families: shopping, switching, burned, struggling, changing, noticing, trying, paying, left. |
heat | 1 to 5 | How close the family usually is to buying. A prior, replaced by measured reply and payment rates. |
status | start | on | later | off | The screening decision for this product's ICP, with the reason, stamped with the ICP version. |
where_it_shows | text | The sources and phrases where the moment becomes visible. |
detectors | detector ids | The monitoring rules that catch it (see Detector catalog). |
fresh_for | duration | How long a caught signal still counts. Starts as a guess; fitted from the reply-by-age curve. |
feeds | playbook ids | The plays that answer it. |
permission | rule | Warm only: what the person has allowed (they spoke first, gave an email, are a customer). |
version | integer | Bumped when status, window or feeds change. |
one trigger, as data
{
"trigger_id": "trg.trial-ending-not-converted",
"name": "Trial ending, not converted",
"aka": "trial expiration",
"side": "warm",
"family": "trying",
"heat": 4,
"status": {
"value": "on",
"reason": "trials exist once sign-ups open",
"icp_version": "icp.vibedraft.v3 (example)"
},
"where_it_shows": "your app plus Stripe trial dates",
"detectors": [
"det.trial-ending-not-converted.stripe"
],
"fresh_for": "3 days",
"feeds": [
"Stalled-trial rescue"
],
"permission": "account holder: product email allowed",
"version": 1
}the catalog
All 11 warm triggers, with what catches them.
Each card: what the moment is, three example buyers, where it shows, the first move, the play that answers it, triggers it stacks with, and every detector that catches it. Placeholders in braces come from the brief: {job}, {category}, {competitor}, {role}.
Noticing you · Paying attention, haven't signed up.
Noticing you — · window 3 to 7 days
Engaged with your content
industry term: content engagement
Replied, bookmarked, followed, or joined your newsletter.
- where it shows
- your own analytics and newsletter list
- permission
- they spoke first: reply where they spoke
- first move
- Reply to what they said. Make the offer only through your own posts unless they ask.
- answered by
offer-post-reply-loop· offer post; reply only if they spoke first- stacks with
- Hand-raise, Checked your pricing
VibeDraft
replied to your post about finding first users
Accountants (invoicing tool)
commented on your LinkedIn post about late payments
Shopify stores (cart app)
joined your newsletter about email flows
detectors that catch it (2)
| Source | Kind | Match | Strength · fresh | Throw out |
|---|---|---|---|---|
| Replies and mentions | your data | a reply, mention or comment from someone who isn't a lead yet | medium 3 days | bots, friends, other vendors |
| Forms and email list | your data | a new newsletter subscriber | weak 7 days |
Noticing you — · window 2 days
Hand-raise
industry term: inbound request, opt-in
They asked for your offer and handed over their details: a link, an email, answers to a few questions.
- where it shows
- replies to your offer post, lead-magnet form submissions, waitlist survey answers
- permission
- they asked: deliver privately
- first move
- Deliver exactly what was promised, privately and fast, then one follow-up. Nothing else.
- answered by
comment-a-keyword· deliver the offer, then one follow-up- stacks with
- Engaged with your content
VibeDraft
replied to your "drop your link, I'll find 3 people ready for it" post with their product URL
Accountants (invoicing tool)
downloaded your overdue-invoice email templates with their firm's email
Shopify stores (cart app)
entered their store URL into your free cart-recovery audit
detectors that catch it (2)
| Source | Kind | Match | Strength · fresh | Throw out |
|---|---|---|---|---|
| Replies and mentions | your data | a reply under your offer post that contains a URL or asks for the offer | strong 2 days | people after exposure, not help; deliver privately |
| Forms and email list | your data | a lead-magnet submission, or answers to waitlist survey questions | strong 2 days | fake emails |
Noticing you — · window 3 days
Checked your pricing
industry term: pricing-page visit
Visited the pricing page more than once.
- where it shows
- your site analytics
- permission
- anonymous unless identified; email only if given
- first move
- Answer the pricing objections in your owned content; email only if they gave you the address.
- answered by
Activation nudge· owned content, retargeting; email only if they gave it- stacks with
- Engaged with your content, Trial ending, not converted
VibeDraft
visited vibedraft.app/pricing twice this week
Accountants (invoicing tool)
opened your pricing page from a Reddit thread
Shopify stores (cart app)
viewed pricing, then your Shopify app listing
detectors that catch it (1)
| Source | Kind | Match | Strength · fresh | Throw out |
|---|---|---|---|---|
| Site analytics | your data | an identified visitor views /pricing twice in 7 days | strong 3 days | anonymous visitors: countable, not reachable |
Trying you · Signed up, not paying yet.
Trying you — · window 1 day
Signed up, didn't start
industry term: unactivated signup
Made an account, never did the first thing that matters.
- where it shows
- your app: no activation event in 24 hours
- permission
- account holder: product email allowed
- first move
- One short note that removes the first blocker, linking straight to the first action.
- answered by
Activation nudge· activation nudge- stacks with
- Went quiet
VibeDraft
connected X, never generated a draft
Accountants (invoicing tool)
created an account, never imported clients
Shopify stores (cart app)
installed the app, never switched on a flow
detectors that catch it (1)
| Source | Kind | Match | Strength · fresh | Throw out |
|---|---|---|---|---|
| Your app | your data | signed_up and no activation event within 24 hours | strong 1 day | test accounts; your own team |
Trying you — · window 3 days
Trial ending, not converted
industry term: trial expiration
A few days left and no sign they'll pay.
- where it shows
- your app plus Stripe trial dates
- permission
- account holder: product email allowed
- first move
- Show them what they made during the trial and ask what would make it worth paying.
- answered by
Stalled-trial rescue· stalled-trial rescue- stacks with
- Checked your pricing
VibeDraft
day 5 of 7, two drafts made, none scheduled
Accountants (invoicing tool)
day 10 of 14, one invoice sent
Shopify stores (cart app)
day 6 of 7, flow on, no recovered carts yet
detectors that catch it (1)
| Source | Kind | Match | Strength · fresh | Throw out |
|---|---|---|---|---|
| Stripe | your data | customer.subscription.trial_will_end (3 days before the end) with low usage | strong 3 days | trials already using it with a card on file |
Trying you — · window 30 days
Went quiet
industry term: dormant user
Signed up, used it a bit, then stopped.
- where it shows
- your app: no logins for 30 days
- permission
- account holder: one personal note
- first move
- One personal note asking what got in the way. No discount on the first touch.
- answered by
Bring back quiet signups· bring back quiet signups- stacks with
- Signed up, didn't start, Using it less
VibeDraft
last login 5 weeks ago
Accountants (invoicing tool)
no invoices sent in a month
Shopify stores (cart app)
app installed, flows paused
detectors that catch it (1)
| Source | Kind | Match | Strength · fresh | Throw out |
|---|---|---|---|---|
| Your app | your data | no login or key action for 30 days after some use | medium 30 days | seasonal products |
Paying you · Customers, in a moment that matters.
Paying you — · window 1 day
Payment failed
industry term: involuntary churn, dunning
The card bounced.
- where it shows
- Stripe webhook
- permission
- customer: transactional email
- first move
- A plain, friendly note with the update-card link. Retry on Stripe's schedule.
- answered by
Failed payment· failed payment- stacks with
- Using it less
VibeDraft
card expired on renewal
Accountants (invoicing tool)
card declined on the monthly charge
Shopify stores (cart app)
Shopify billing failed
detectors that catch it (1)
| Source | Kind | Match | Strength · fresh | Throw out |
|---|---|---|---|---|
| Stripe | your data | invoice.payment_failed | strong 1 day | none: always real |
Paying you — · window 7 days
Using it less
industry term: usage decline, churn risk
Still paying, but usage is dropping. Usually comes before a cancel.
- where it shows
- your app: usage down sharply over a few weeks
- permission
- customer: a personal check-in
- first move
- A personal check-in from the founder, by hand, before they cancel.
- answered by
A personal check-in· a personal check-in, by hand- stacks with
- Payment failed, Went quiet
VibeDraft
scheduled 20 posts a week, now 2
Accountants (invoicing tool)
sending half the reminders they used to
Shopify stores (cart app)
flows on, but no new campaigns in a month
detectors that catch it (1)
| Source | Kind | Match | Strength · fresh | Throw out |
|---|---|---|---|---|
| Your app | your data | key actions down by half or more over 4 weeks against the 4 before | medium 7 days | holidays, seasonal businesses |
Paying you — · window 7 to 14 days
Outgrowing their plan
industry term: expansion signal
Hitting limits, or has a second use for it.
- where it shows
- plan limits hit; a second product or location visible
- permission
- customer: product email allowed
- first move
- Offer the plan or the second product before they hit the wall.
- answered by
Second product· second product- stacks with
- Just had a win
VibeDraft
launched a second product
Accountants (invoicing tool)
added a second office
Shopify stores (cart app)
opened a second store
detectors that catch it (2)
| Source | Kind | Match | Strength · fresh | Throw out |
|---|---|---|---|---|
| Your app | your data | hits a plan limit, or adds a second product, location or teammate | strong 7 days | |
| X | phrase | the customer announces a second product or location | medium 14 days |
Paying you — · window 7 days
Just had a win
industry term: customer success milestone
Got a result worth talking about.
- where it shows
- your app: a milestone; a happy reply
- permission
- customer: ask before quoting
- first move
- Thank them, then ask if you can share the story. Quote only what they said, with permission.
- answered by
customer-proof-amplified· share a new customer; ask for a story- stacks with
- Outgrowing their plan
VibeDraft
first paying customer came from a VibeDraft reply
Accountants (invoicing tool)
cut overdue invoices in half
Shopify stores (cart app)
recovered $3k in carts this month
detectors that catch it (2)
| Source | Kind | Match | Strength · fresh | Throw out |
|---|---|---|---|---|
| Your app | your data | a milestone event: first result, first payment caught | medium 7 days | |
| Replies and mentions | your data | a happy reply, mention or survey score of 9 or 10 | strong 7 days | politeness |
Left you · Cancelled.
Left you — · window 60 days
Cancelled
industry term: voluntary churn
Gone, usually with a reason.
- where it shows
- Stripe cancel plus the reason they gave
- permission
- former customer: once, after the fix
- first move
- Wait until the reason they gave is fixed, then tell them once.
- answered by
Win-back· win-back, only once the reason is fixed- stacks with
- Using it less
VibeDraft
"didn't sound like me"
Accountants (invoicing tool)
"my clients didn't like the portal"
Shopify stores (cart app)
"too expensive at my size"
detectors that catch it (1)
| Source | Kind | Match | Strength · fresh | Throw out |
|---|---|---|---|---|
| Stripe | your data | customer.subscription.deleted, with the reason from cancellation_details if your cancel flow asks | strong 60 days | win-back only once the reason is fixed |
failure modes
How warm triggers go wrong.
| Failure | What it looks like | How to catch it |
|---|---|---|
| No activation event | "Didn't start" and "went quiet" can't fire without a defined first action. | Write the activation event down before wiring any trying-family trigger. |
| Messaging without permission | Emailing an anonymous pricing visitor you matched by IP. | The permission field is a hard rule; anonymous visits are counted, never contacted. |
| Discount reflex | Every rescue email offers money off. | No discount on the first touch; test discounts as an arm, not a default. |
| Winning back too early | Asking churned users back before the reason they left is fixed. | Gate the win-back play on the fix shipping. |
| Holiday false alarms | Usage drops over a holiday read as churn risk. | Compare 4 weeks against the 4 before; exclude seasonal products. |
| Double touches | A trial email and a founder DM on the same day. | One owner per person per day in the contact policy. |
| Treating a reply as consent to sell | Someone replied to a post; that isn't an opt-in for email. | Reply where they spoke; the offer stays in your own posts. |
data to capture
Record it so the windows can be learned.
Following the guide's data rules: log the decision, version it, freeze the inputs, keep the negatives.
record
- the event that fired, the condition, and the person or account
- the permission state at the moment it fired
- which play ran, the message, and its touch_id
- the cancel reason, verbatim, when one is given
label
- activated within N days of the nudge
- paid after the rescue, recovered after the failed payment
- came back after the win-back
- stop or unsubscribe after any touch
trains
- conversion and churn models built on warm triggers
- the best send delay for each lifecycle play
- which cancel reasons are fixable, from the text
test
- nudge at 24 hours vs 72 hours after sign-up
- founder-written vs templated rescue note
- a 10% holdout per lifecycle play to measure lift