Cross-campaign suppression
Cross-campaign suppression is how you stop a contact from receiving messages they shouldn’t — for example, a recent customer who shouldn’t see “first-purchase discount” promotions, or a contact in an active support thread who shouldn’t receive promotional pings.
The mechanic: define a suppression segment once, then attach it to any campaign, journey, or playbook. The platform subtracts those contacts from delivery at send time.
What a suppression segment is
A regular segment with one extra property: it can be referenced as a negative filter during send-time evaluation.
Examples of useful suppression segments:
| Segment name | Rule |
|---|---|
| Recent buyers (7d) | transaction.purchase in last 7 days |
| In support thread | Active inbox conversation, agent assigned |
| Opted out — promotional | consent.promotional is false |
| High frequency cap proximity | Touched 5+ times in last 24h |
| In a competing journey | Currently enrolled in journey X |
| DNC list | Externally maintained do-not-contact list, imported via CSV or API |
You can build any segment as a suppression segment — it’s the attachment that makes it act as a suppression, not the definition.
Attaching suppression to a playbook
Open the playbook drawer
Go to Engage → Automations → {playbook} and open the configuration drawer.
Find the suppression panel
In the drawer, scroll to Suppression segments. Click Add segment.
Pick one or more segments
You can attach multiple suppression segments — they’re combined with OR semantics (a contact in any attached suppression segment is suppressed).
Save
When you save, the playbook stores a snapshot of the suppression segments’ contact members at that moment. From then on, every send through this playbook excludes any contact in the snapshot.
How the suppression is applied
When a journey send node (or campaign delivery, or playbook touch) reaches the dispatcher, the engine:
- Looks up the contact’s identity
- Iterates through every attached suppression segment
- Checks the canonical
aegis.segment_memberstable in ClickHouse for membership - If the contact is in any attached segment, the send is suppressed — recorded with a reason on the contact’s timeline
This is fast (segment membership is indexed) and consistent (the same canonical substrate that powers segments themselves).
Snapshot vs live
Suppression can be configured in two modes:
| Mode | What happens |
|---|---|
| Snapshot (default) | When you attach the segment, its current member list is frozen for the playbook. Subsequent changes to the segment don’t affect this playbook. |
| Live | Membership is re-evaluated at every send. Newly added members are suppressed immediately. |
Snapshot is the default because it’s predictable — the operator sees who’s suppressed at activation time, and the playbook behaves consistently for its lifetime. Live mode is useful for global suppression lists (DNC, opt-outs) that should always be current.
Configure mode per attachment.
Where you’d use this
Recent-buyer suppression
A “new customer welcome” campaign should never go to someone who bought a week ago. Attach a “recent buyers (7d)” suppression segment to the campaign — anyone who purchased in the past week is dropped from delivery.
Cross-journey conflict avoidance
Running two journeys with overlapping triggers? Attach each journey’s enrolled-contacts segment as a suppression on the other. Contacts enter only the first journey that matches.
Support-thread silence
When a contact has an open inbox thread, suppress all promotional sends. Attach “in support thread” to every promotional playbook — sends pause until the thread closes.
External DNC list
Maintain a do-not-contact list outside Active Reach (via API or CSV upload). Sync it into a segment and attach as live-mode suppression on every promotional surface.
In-app suppression via frequency_cap
Playbook-driven in-app touches opt into the same cross-campaign suppression as catalog campaigns via the frequency_cap field on contact_in_app_queue. The signal flows end-to-end:
- Journey send → enqueue with
frequency_capJSONB get_queued_messagesand/v1/in-app/activehonour the capnotifyConversionsilences pending journey-queued cart-recovery touches, not just catalog campaigns
Targeting bypass on already-enqueued rows is preserved by design — once a contact is queued, the original targeting decision stands.
The dead-column anti-pattern (developer note)
Suppression segments were defined as a column on playbook_execution_instances for a long time before being wired end-to-end. The lesson: if a column exists in the schema, it must be reachable from the operator UI and enforced at send time, or it’s a maintenance hazard. Today the wire-up is complete — UI to schema to send-time enforcement.
Visibility on the contact timeline
When a send is suppressed for a contact, the contact’s timeline records:
- The send node / campaign / playbook that was attempted
- The suppression segment that matched
- The mode (snapshot vs live)
- Timestamp
Operators can audit suppression decisions per contact and bulk-export the suppression-events log for compliance / reporting.
What’s next
- Journey-driven dispatch — the dispatcher that reads suppression rules
- Segments overview — how to define segments
- Micro-intent engine — intent-based suppression
- Retargeting cascade — the paid-side equivalent