Upsell and Cross-Sell Email Automation: Trigger Upgrades from Usage and Purchase History
Upsell email automation works when the trigger is a fact about the customer rather than a date on your content calendar. A contact who just hit 80% of their plan quota, or who bought a template pack two months ago and never returned, is in a specific situation you can detect — and that situation, not "day 30 of the lifecycle," is what makes an upgrade email land. This guide covers both trigger families: usage-limit triggers (a contact approaches or exceeds a plan cap) and purchase-history triggers (what they bought, when, and what they didn't).
What you'll set up and what you need
Two mechanics do the work here.
Usage-limit triggers. Your product knows when someone is running out of seats, storage, API calls, projects, or whatever your plan meters. When usage crosses a threshold — 80% is a more useful line than 100% — that becomes an event. The event carries properties: which plan they're on, what the quota is, how much they've used. Your automation listens for that event and responds.
Purchase-history triggers. Tags or custom fields record what a contact owns. Someone who bought the reporting add-on but not the automation add-on is a cross-sell candidate. Someone who bought a one-off template pack and never bought again is a different candidate. Cross-sell emails built on ownership data avoid the most common embarrassment in this category: offering a customer something they already paid for.
Before you start, get these in place:
- A way to receive usage data. Either an event API call from your product or a signed webhook. Without this, you're guessing.
- Custom fields for plan and limits. At minimum
plan,usage_percent, andquota. These make conditions readable later. - Tags for product ownership. One tag per product or add-on, applied at purchase.
- A verified sending domain. DKIM, SPF, and DMARC configured and confirmed. Upgrade emails are revenue emails; they should not land in spam.
Mailerflow's visual automations support triggers on events, dates, inactivity, and website behavior, plus waits, conditions, and webhooks — which is what makes both trigger types possible in one workflow. If you want a head start, the AI automation builder takes a sentence like "when a Starter customer hits 80% of their seat quota, wait a day, re-check their plan, then email them about upgrading" and drafts the trigger, waits, conditions, and emails for you to review before anything goes live.
Step-by-step: build the automation
1. Define the limit and the event that signals it
Pick the threshold and name the event. usage.threshold_reached at 80% is a good default — it gives you room to send before the customer is blocked. Include properties: plan, quota, used, and a computed usage_percent. Decide now whether the event fires once per billing period or every time usage crosses the line; once per period is usually the right answer.
2. Get the data in
Send the event from your product via the REST API, or have your backend post to a signed webhook endpoint. Map the event properties to custom fields on the contact so conditions can read them. Use idempotency keys on the API call — if your product retries, you don't want a contact counted twice and emailed twice.
3. Create the segment
Build a dynamic segment: plan = starter AND usage_percent >= 80. Dynamic means it updates itself as fields change, so you don't maintain it. If you'd rather describe it in plain language — "Starter customers who are close to their seat limit" — AI segmentation can turn that description into the segment for you.
4. Build the automation
Trigger on usage.threshold_reached. Add a wait of one day. Add a condition that re-checks usage_percent >= 80 AND plan = starter. Then the email. The wait matters: it filters out people who upgrade on their own within 24 hours, and the condition catches anyone whose plan changed in the meantime.
5. Write the email
Three things belong in it: the number they hit, what the next tier unlocks, and one clear call to action. Nothing else. If you want a starting point, the AI email builder takes a description and returns a complete responsive design with subject lines and preview text — then you edit the copy to include the actual quota figure from the contact's fields.
6. Add the cross-sell branch
After the wait, branch on ownership tags. If the contact already owns the reporting add-on, offer the automation add-on instead of the plan upgrade. If they own nothing extra, offer the upgrade. One condition node, two paths, two different offers.
7. Set send timing
Inside the automation, use "send when the contact is most active" rather than a fixed hour. A quota-limit email that arrives while someone is in the product is more likely to be read than one that lands at 3 a.m.
8. Activate and cap frequency
Set a frequency cap so a contact can't receive the same upgrade nudge repeatedly across billing periods, and tag anyone who has been contacted (upsell_sent_starter) so you can exclude them later. Activate.
A worked example: a project tool hitting its seat limit
This is an illustrative scenario, not a real customer.
A project-management SaaS sells a 5-seat Starter plan. When a workspace adds its fifth member, the product fires usage.threshold_reached with plan = starter, quota = 5, used = 5, usage_percent = 100.
The automation:
- Trigger:
usage.threshold_reached - Wait: 1 day
- Condition:
usage_percent >= 100 AND plan = starter - Branch A (no add-ons owned): upgrade email
- Branch B (owns reporting add-on): cross-sell the automation add-on
- Send time: when the contact is most active
The email:
Subject: You've filled all 5 seats
Preview: Here's what happens when a 6th teammate needs access.
Your workspace just added its fifth member, which fills the Starter plan.
A sixth seat is €4/month on Team, and it also unlocks shared views
and the approval workflow.
[Upgrade to Team →]
Note what the email does not do: it doesn't lead with a discount, and it doesn't explain the plan tiers from scratch. It names the exact situation the customer is in and puts one link in front of them.
The purchase-history variant. A different contact bought a one-off template pack 60 days ago and has bought nothing since. No usage event fires, so this runs on a separate automation: trigger on the purchased_template_pack tag, wait 60 days, condition has_tag: purchased_template_pack AND NOT has_tag: subscription_bundle, then send a cross-sell for the subscription bundle that includes the templates plus monthly updates. Same structure, different trigger source.
How to check it works
Work through this list before you trust the automation with real volume.
- Fire a test event with an idempotency key and confirm it appears on the test contact's timeline. If it doesn't show up, your field mapping is wrong.
- Confirm entry. Check the automation's entry log for the test contact.
- Test both branches. Create two test contacts — one with the add-on tag, one without — and confirm each receives the correct email.
- Verify the wait holds. Inspect the scheduled send time for the contact in the wait step. It should be roughly 24 hours out, not immediate.
- Check the render. Send a preview to yourself, click the CTA, and confirm the link carries the right plan parameter so your checkout opens on the correct tier.
- Watch the first real send. Delivery, bounces, and complaints in analytics. Complaints are the number that matters most here — an upgrade email that reads as spam will show up there first.
- Check webhook delivery logs if your product sends the trigger that way, and confirm retries are firing when a delivery fails.
- Review after two weeks. Entry count, click rate on the upgrade CTA, and how many contacts exited at the condition because they upgraded on their own. That last number tells you whether your wait is the right length.
Common mistakes and fixes
Triggering at 100% instead of 80%. By the time someone is blocked, the email reads as an obstacle rather than an offer. Fire at 80%.
Sending the same email every billing period. Add a frequency cap and an upsell_sent tag, then exclude tagged contacts in the condition.
Treating every plan the same. A Starter customer and a Growth customer need different offers. Condition on plan before choosing the email.
Ignoring purchase history. Offering someone the add-on they bought last month damages trust more than a missed upsell costs you. Tag on purchase and exclude in the condition.
No exit condition after the wait. If a contact upgrades during the 24-hour wait, they should drop out. Re-check plan after the wait, not just before it.
Fixed send hour. Use the most-active send time inside the automation instead of a hardcoded 9 a.m.
Double-counting events. Products retry. Use idempotency keys so a retry doesn't create a second entry.
Leading with the discount. The customer's problem is the limit they just hit, not your price. Lead with their number.
FAQ
How do I trigger an upgrade email when a customer hits a usage limit? Have your product send an event when usage crosses a threshold — 80% of quota is a practical default — and trigger the automation on that event. Include plan, quota, and usage as event properties so your conditions and email copy can use them.
Can I use purchase history instead of usage data? Yes. Tag contacts at purchase and trigger on the tag or on a date relative to it. This works for products without metered usage, and it's the better trigger for cross-sell emails where ownership, not consumption, is the signal.
How do I stop someone getting the same upsell twice? Two mechanisms: a frequency cap on the automation, and a tag applied when the email sends that you exclude in the entry condition. Use both — the cap protects against rapid repeats, the tag protects across billing periods.
Should the upgrade email include a discount? Not by default. If the trigger is a real limit the customer just hit, the value argument is already made. Reserve discounts for win-back sequences where the customer has gone quiet.
How long should the wait be between the trigger and the email? One day is a reasonable starting point for usage triggers — long enough to filter out people who upgrade on their own, short enough that the limit is still top of mind. Check your exit-at-condition numbers after two weeks and adjust.
Do I need a developer to send usage events? Usually yes for the initial integration, since the event has to come from your product's backend. Once the event and field mapping exist, marketers can build and edit the automation itself without further engineering work.
Next steps
Build one automation before building three. Pick the plan closest to its cap, wire up a single usage-limit trigger, and let it run for two weeks before you touch anything else. Then add the purchase-history cross-sell branch, which reuses the same condition and branching structure you've already tested.
This article is the pillar of the Upsell cluster. Supporting pieces on win-back sequences, onboarding-to-upgrade paths, and expansion revenue reporting will be linked here as they publish.
If you want to build and test the first automation before committing to a paid plan, Mailerflow's Free plan covers 2,500 contacts, 10,000 emails a month, and 3 active automations. Paid plans start at €9.90/month with unlimited emails.
Describe this automation in a sentence and Mailerflow drafts the workflow for you to review — start free.
