CUSTOMER JOURNEYSAIGUIDE

Throttling notifications across product, transactional, and marketing streams

KSKyle Seyler

Kyle Seyler

April 16, 2026

Throttling notifications across product, transactional, and marketing streams — cover

TLDR

Courier already keeps product, transactional, and marketing notifications in one Journeys environment. That makes throttling a configuration question rather than an integration project. The working setup is three throttles, one per stream. Transactional is a tagged category that bypasses the throttle (and respects preferences) without per-flow branch logic. Product overflow feeds a batch, and the batch payload runs through the AI node to produce a prioritized digest. Marketing overflow drops on the floor.

The whole flow lives in Courier Journeys using the throttle, batch, fetch-data, and AI nodes. For context on the AI node, the Journeys AI node launch post covers the summarization and scoring work that turns a forty-event batch into one useful send. For the sibling primitive that pairs with throttling in most real setups, How top platforms handle notification quiet hours and delivery windows is worth a read.


Notification throttling is a rule that drops or defers events exceeding a user-level rate limit inside a journey. A throttle node set at ten events per hour per user will pass the first ten through and silently drop everything after that for the next sixty minutes. The default behavior is fine for some streams and actively destructive for others.

The reason this matters in Courier specifically is that product, transactional, and marketing notifications all run in the same Journeys environment. Most teams end up there through consolidation: transactional used to be SendGrid, marketing used to be Customer.io, product was hand-rolled. Once all three are in the same platform, the throttle question changes. Instead of three disconnected systems each with their own rate limits, there is one engagement ceiling per user, and the decision is how to share it across the three streams.

A single throttle across all three is the wrong share. A password reset, a mention from a teammate, and a marketing email are not interchangeable, and treating them as one bucket forces a bad compromise: cap too loose and marketing continues to bombard, cap too tight and password resets get swallowed when volume spikes.

The right configuration uses a throttle per stream, paired with a distinct overflow policy for each. Transactional bypasses. Product overflow batches into a digest. Marketing overflow drops. Because the streams share a platform, the coordination is a configuration problem inside Journeys rather than an integration problem across vendors.

The three streams, in one environment

Courier is built to hold all three notification streams in one place. That is the point of the consolidation. It is also why the throttling question has a coherent answer at all, since the same platform can see the transactional, product, and marketing messages a user is getting and enforce rules across them. Teams running three separate vendors cannot do that without writing glue code between rate-limit APIs that were never meant to coordinate.

Transactional messages are triggered by something the user did and expect a response to: receipts, password resets, 2FA codes, magic links, failed payment alerts. These cannot be throttled without breaking the product. A dropped password reset is a support ticket you did not need to create. Courier treats notification category as a first-class property on a notification, which is what makes "transactional bypasses" a setting and not a workaround.

Product notifications come from in-app activity that concerns the user: comment mentions, task assignments, status changes, ticket updates, deploy alerts. Volume is spiky. A quiet Tuesday can be followed by a team launch where a single user gets forty mentions in an hour. Dropping overflow here means the user comes back on Monday, replies to ten mentions in their inbox, and misses the stakeholder thread they were tagged in.

Marketing and lifecycle messages are sender-driven: onboarding campaigns, feature announcements, winbacks. The user did not trigger them. Volume is predictable because the sender controls it, which is also why marketers always want to push the cap higher than is healthy.

The stream-aware setup below takes advantage of all three living in the same environment. That is the part most guides cannot write, because most stacks cannot do it.

What the throttle node actually does

The throttle node in Courier Journeys takes a scope (user, global, or dynamic), a limit of N events, and a time window of T seconds. Events that fit under the limit pass through. Events over the limit are dropped for the remainder of the window.

Dropping is the right move for marketing. A user who did not open your last three nurture emails is not going to open the fourth one you squeeze in by loosening the cap. Dropping overflow is the cheapest way to protect inbox reputation and the cheapest way to stop marketing from eating every other stream's budget.

Dropping is the wrong move for product notifications. If forty mentions fire in an hour and ten pass, the user has no signal that the other thirty happened. They lose context, not just volume.

The fix is to route throttle overflow into a batch node instead of dropping it on the floor.

The pattern: throttle with auto-batch

The setup looks like this inside a journey:

Event fires
[Fetch Data: user tier, engagement score]
[Branch: VIP or urgent?]
├── Yes ─▶ [Send immediately, bypass throttle]
└── No ─▶ [Throttle: user-scope, 10/hour]
├── Under cap ─▶ [Send single notification]
└── Over cap ─▶ [Batch: max wait 15 min, max events 50]
[AI Node: prioritize and summarize]
[Send digest]

The throttle behaves normally on the first ten events and passes them through untouched. The eleventh event takes the over-cap branch into a batch instead of getting dropped. The batch node accumulates overflow until one of its triggers fires: a period of inactivity, a max event count, or a max wait time. When it releases, the collected payload flows into the next node as a single bundle.

The AI node is what makes the digest usable. A static template dropped on top of forty events produces a forty-bullet email nobody reads. The AI node takes the same payload and does work a static template cannot. Importance scoring runs against the user's recent engagement signals, so a mention from a direct manager outranks a mention from a bot. The output reads as a short prioritized summary in natural language, with tone adjusted by context: urgent items surface at the top with clearer verbs, low-priority items get collapsed into a one-line footer.

The user receives one notification when their inbox would otherwise have received forty, and the one they receive is actually useful.

Using fetch-data to drive bypass decisions

The fetch-data node pulls live details from your backend mid-journey. You define a data contract upfront, and the fields become available downstream for branches, template variables, and the AI node.

Fetch-data is the right place to put the bypass logic for your throttle. Before the throttle fires, pull the signals that decide whether an event is important enough to skip the cap: customer tier, account ARR band, outage severity, failed payment amount, manager-is-sender flag. Branch on those fields and route high-priority events straight to a send node. Everything else falls through to the throttle path.

Done with a static allowlist, the same behavior is a nest of hardcoded conditions nobody wants to own. Done with fetch-data plus a branch, the policy lives where it belongs: in whatever service already knows which customers and events matter.

A simple example of the data contract:

{
"user_tier": "enterprise",
"recent_engagement_score": 0.82,
"is_direct_manager": true,
"event_priority": "high"
}

Any of those fields can drive a branch. When the AI node sits on the batch output, it can read the same fetched payload and use it for per-item prioritization inside the digest. That removes a whole class of custom ML work most teams try to avoid building.

Per-stream setups

Transactional

Transactional messages are a first-class category in Courier. Tag the notification as transactional on the template, and it can be routed outside the throttle without a branch for every flow. Preference checks also respect the category, so a user who turned off marketing still gets their password reset. This is the control that is usually missing when teams try to build the same setup across vendors, and the reason a single platform shared by all three streams makes the transactional story clean.

A subtler variant: time-sensitive product events that look transactional should also bypass. Prod outage alerts, failed-payment warnings on high-value accounts, security events. Either tag them as transactional when that is accurate, or tag them with a priority flag on the payload (or populate it from fetch-data) and branch around the throttle.

Product notifications

Set a user-scope throttle at a reasonable ceiling, ten to twenty events per hour for most teams. Route the over-cap branch into a batch with a short max-wait, ten or fifteen minutes, so the user does not stare at a silent inbox for an hour during a burst.

Place the AI node on the batch output. If you do not have access to the Courier Journeys AI node yet (it is rolling out to enterprise customers first), a static digest template is a workable stand-in. The cost is that you lose priority scoring inside the batch, which matters most when one of the forty events is the one the user actually needed to see.

Marketing and lifecycle

Set a tight user-scope throttle (three to five sends per seven days across all marketing journeys) and do not route overflow to batch. Dropping the overflow is the goal, not the failure mode. Users who opted out of getting twenty marketing emails did not opt into getting one digest summarizing twenty marketing emails either.

For this stream, the throttle is a defense against sender teams, not a delivery mechanism. The work of reducing marketing volume belongs with the people shipping the campaigns. The throttle exists to enforce the number they should already be hitting.

How throttling behaves per channel

The channels doc covers how send nodes dispatch to email, SMS, push, in-app, Slack, Teams, and the rest. Throttle and batch settings should be tuned per channel because users experience them differently.

Email tolerates the longest batch windows. Fifteen to thirty minutes is often fine; the user is not waiting on a live feed. Email is where auto-batch pays off most, because inbox fatigue is the thing you are actually fighting.

In-app Inbox usually does not need batching at all. The Inbox holds every event as a row; there is no inbox overflow the way email has one. Throttle unread-badge pings to avoid constant attention flicker, but let the underlying events land in the Inbox uncapped.

Slack and Teams sit in between. A short batch (two to five minutes) prevents a thread spam storm during a burst, but a fifteen-minute batch makes messages feel stale. Use a tighter window and a lower max-event count here than for email.

Push and SMS should be throttled aggressively and rarely batched. Push notifications lose urgency when stacked and users rarely clear them in order. SMS has a cost per send and a hard irritation curve. Throttle at one or two per hour per user, drop overflow, and route any rolled-up content to email or the Inbox instead.

Courier's channels abstraction means the same journey can branch into different channel-specific flows with their own throttle and batch settings, rather than forcing one configuration across every channel the user is enrolled on.

Where the AI node fits beyond the batch output

The AI node is most valuable as the summarizer on top of a batched digest, but the throttle flow has three other useful spots for it.

At the entry branch of a throttle, the AI node can score whether an incoming event deserves a bypass. The fetch-data node pulls the raw signals; the AI node reasons over them with more flexibility than a hardcoded rule. Priority decisions that would otherwise require ML tooling or a custom service can live inside the journey.

On the single-send branch, the AI node can rewrite channel-specific copy. A notification headed to email reads differently from the same content pushed to Slack Block Kit or the in-app Inbox. The AI node takes the event payload once and produces the appropriate variant per channel, which removes content duplication that otherwise creeps into the template library.

Inside a batch, the AI node can defer or promote individual items. If the batch holds one urgent event surrounded by twenty low-priority ones, the node can surface the urgent event as a standalone send and fold the rest into a follow-up digest. That is how you avoid burying a real incident under a pile of routine status updates.

What to measure

Three numbers tell you whether the setup is working.

Unsubscribe rate broken out by stream is the first. If marketing throttling is working, marketing unsubscribe rate drops and product unsubscribe rate stays flat. If either moves the wrong direction, your caps are off.

Digest open rate compared to individual-send open rate is the second. When digests perform worse than single sends, users are not finding value in the rollup. Usually the AI prioritization is weak or the batch window is too loose and the digest arrives too late to matter.

Missed-urgent count is the third and the one most teams forget. Tag any event that should have bypassed the throttle but did not. Every item in this bucket is a bug in your priority logic, and the number should trend toward zero over a quarter. If it does not, your bypass rules need AI scoring on top of the fetch-data signals rather than a static allowlist.

Measuring volume alone is a trap. Volume will drop with throttling regardless of whether the setup works. Pair it with engagement and unsubscribe rate to know whether the drop came from signal or noise.

What to ship first

The biggest first move is the product stream. Highest volume, most volatility, clearest pain when events get dropped. Stand up throttle plus auto-batch for product notifications, verify the batch is producing digests at a cadence that matches user expectations, then layer fetch-data-driven bypass and AI summarization on top once the basics are stable.

Marketing throttling is usually a configuration change on top of existing journeys and ships in a day. Transactional is largely done once the notifications are tagged correctly, since Courier already treats the category as a bypass signal for both throttling and preferences.

How Courier handles this

Courier Journeys exposes throttle, batch, digest, fetch-data, and the AI node as first-class primitives on the visual builder. The channels documentation covers how each send node routes to email, SMS, push, in-app, Slack, and Teams, which is where per-channel throttle tuning matters most.

Try Courier free.

Similar resources

Your Entire Lifecycle Marketing Department, Run from Claude Fable 5 — cover
AICustomer JourneysGuide

Your Entire Lifecycle Marketing Department, Run from Claude Fable 5

With the rollout of Claude' Fable model, one thing is becoming increasingly clear. Marketing execution (especially the long-tail work), will be done in an AI editor. In Courier, connect your agent to the MCP server or CLI, install Courier Skills, and keep a small folder of markdown context files. From there, one person with a coding agent covers the work that used to require a lifecycle marketer, an email designer, a marketing ops hire, and an engineer: building journeys, shipping templates, auditing every notification, and debugging delivery without opening a dashboard.

By Kyle Seyler

June 09, 2026

Create a customer journey from AI coding agent — cover
Customer JourneysAIEngineering

Create a customer journey from AI coding agent

Use Courier's Journey API to create multistep customer engagement workflows from your coding agent of choice. Describe the kind of journey you'd like to create, answer a few questions, and publish to the platform.

By Kyle Seyler

May 20, 2026

Courier journeys, as code — cover
Customer JourneysProduct News

Courier journeys, as code

Most journeys don't die because they were hard to build — they die because they're hard to change. A day-5 nudge written before a new activation event existed still fires for users who hit the milestone on day two. Courier journeys are now programmable: a public Journeys API with SDKs, a CLI, and an agent skill on top. Describe a flow to your coding agent, get an ASCII diagram, ship it. Full post covers the access points, an example end-to-end, and the one gotcha worth knowing (`output_schema` is mandatory on AI nodes).

By Kyle Seyler

May 18, 2026