Campaign Opt-Out Keyword Detection (CCM)
This feature enables campaign unsubscribe detection without changing existing inbound behavior. CCM evaluates unsubscribe signals for every inbound message that reaches POST /message/receive, while keeping normal routing, session handling, reply windows, delivery notifications, surveys, and scheduler behavior unchanged.
MVP summary: The feature supports SMS, WhatsApp, MS Exchange Email, and Gmail Email. SMS uses keyword detection, WhatsApp uses Meta user_preferences, and email uses the standard List-Unsubscribe mechanism. All supported opt-out paths update CIM with isSubscribed=false and publish CAMPAIGN_UNSUBSCRIBED after successful opt-out.
Related guide: To configure the customer-facing acknowledgement message that gets sent after a successful opt-out, see Configure a Campaign Unsubscribe Flow in Conversation Studio.
Objective
The objective is to detect customer unsubscribe intent through the default unsubscribe mechanism of each supported channel and apply a customer opt-out in CIM, without disrupting the existing inbound message path.
-
Do not create a new session for unsubscribe-only signals.
-
Do not alter existing inbound routing behavior.
-
Do not introduce reply-window or routing changes.
-
Run unsubscribe checks asynchronously where applicable.
-
Log failures without failing the inbound request.
Core principle
The unsubscribe feature is intentionally additive. Every inbound message that reaches CCM is eligible for the unsubscribe check, including campaign replies, scheduled-activity replies, and normal non-campaign inbound messages. There is no campaign-versus-non-campaign gate.
|
Inbound kind |
Existing behavior |
Unsubscribe check |
Notes |
|---|---|---|---|
|
Normal customer message |
Continues through the existing inbound path. |
Yes |
Run the channel-specific unsubscribe check in parallel without changing routing. |
|
Reply to campaign or scheduled outbound |
Continues as today, including scheduler queue behavior. |
Yes |
Do not add a campaign-versus-non-campaign gate. |
|
Any other inbound message that reaches |
Continues through the existing inbound path. |
Yes |
No-op unless a supported channel rule matches. |
High-level flow
-
Connector sends inbound message to CCM through
POST /message/receive. -
If
header.intentisUNSUB, CCM opts the customer out through CIM and returns without creating a session or following the existing inbound path. -
If the intent is not
UNSUB, CCM continues the existing system flow exactly as today. -
In parallel, CCM applies the default unsubscribe check for the channel.
-
When a supported unsubscribe signal is detected, CCM calls CIM with
isSubscribed=false. -
After a successful CIM opt-out, the system publishes
CAMPAIGN_UNSUBSCRIBEDonVirtualTopic.conversation-topic.
Important: The main request path is never blocked or altered by the unsubscribe check. Async failures are logged only.
Channel strategy
|
Channel |
Default unsubscribe way |
CCM inbound keyword check |
Extra work |
|---|---|---|---|
|
SMS |
Customer texts a configured single-word keyword such as |
Yes, for |
No connector change required. |
|
|
Customer can unsubscribe through either Meta marketing opt-out |
Yes, for customer-typed WhatsApp |
WhatsApp connector still detects Meta |
|
MS Exchange Email |
Email client uses |
No email body parsing. |
Connector stamps headers on campaign outbound, exposes one-click endpoint, and forwards |
|
Gmail Email |
Email client uses the same |
No email body parsing. |
SMTP stamps headers; IMAP poll detects mailto unsubscribe and forwards |
|
Media / DN / other |
Not applicable. |
No. |
No-op. |
SMS keyword detection
SMS is the only channel where CCM performs inbound body keyword matching. The check applies only to inbound SMS messages with body type PLAIN.
Candidate text
-
Use
body.markdownTextfor every inboundPLAINmessage on WhatsApp or any other supported channel where plain-text keyword detection is enabled. -
Trim whitespace.
-
Require a single word.
-
Compare case-insensitively.
-
Optionally strip trailing punctuation.
Configuration
ef.campaign_unsubscribe_enabled=true
ef.campaign_unsubscribe_keywords=STOP,UNSUB,UNSUBSCRIBE,CANCEL,END,QUIT,OPTOUT,OPT-OUT
SMS behavior
|
Check |
Result |
|---|---|
|
|
CIM opt-out and publish |
|
Multi-word SMS |
No-op. |
|
Empty text |
No-op. |
|
Non- |
No-op. |
WhatsApp unsubscribe handling
WhatsApp unsubscribe supports two paths: the default Meta Cloud API user_preferences opt-out and customer-typed opt-out keywords. If the customer types a configured keyword such as STOP, UNSUB, or UNSUBSCRIBE in a WhatsApp PLAIN message, CCM detects it from body.markdownText using the same single-word keyword logic as SMS.
|
Item |
Detail |
|---|---|
|
Default way |
Customer taps WhatsApp built-in marketing message Stop control. |
|
Typed keyword behavior |
If the customer types a configured opt-out keyword such as |
|
Meta signal |
Webhook contains |
|
Connector behavior |
Detect |
|
Do not do |
Do not build a fake |
|
CCM behavior |
For |
WhatsApp connector payload to CCM
-
header.intent=UNSUB -
header.channelData.serviceIdentifier= phone number ID -
header.channelData.channelCustomerIdentifier= WhatsAppwa_id -
body.type=PLAIN
Email unsubscribe handling
Email uses the standard List-Unsubscribe mechanism for both MS Exchange and Gmail. CCM does not scrape email body content for keywords such as STOP.
Outbound email headers
For campaign outbound messages where header.schedulingMetaData is present, the connector stamps the following headers:
List-Unsubscribe: <mailto:{mailbox}?subject=UNSUBSCRIBE>, <{CONNECTOR_PUBLIC_URL}/unsubscribe/one-click?serviceIdentifier=...&channelCustomerIdentifier=...&tenantId=...>
List-Unsubscribe-Post: List-Unsubscribe=One-Click
Agent replies without schedulingMetaData remain unchanged.
Email unsubscribe paths
|
Signal |
Path |
|---|---|
|
Gmail or Outlook one-click unsubscribe |
Email client calls connector |
|
mailto unsubscribe |
Unsubscribe email lands in the channel mailbox; connector poll detects subject |
|
Free-text |
Out of scope. No body scrape. |
Connector public URL
CONNECTOR-PUBLIC-URL on the channel connector provider configuration is the preferred source for the public connector base URL used by Gmail and Outlook one-click unsubscribe. Optional environment fallback is CONNECTOR_PUBLIC_URL.
CIM opt-out API
All supported unsubscribe paths end in the same CIM Customer API call.
GET {ef.cim_customer_api}/customers?channelType={type}&customerChannelIdentifier={id}&isSubscribed=false
|
Parameter |
Source / meaning |
|---|---|
|
|
Resolved from |
|
|
|
|
|
Opt out. CIM backend attaches the system Opt Out label. |
isSubscribed=true or an omitted subscription parameter represents subscribed state and can remove the Opt Out label if present; that path is not used by this CCM unsubscribe flow.
Event: CAMPAIGN_UNSUBSCRIBED
After a successful CIM isSubscribed=false update, CCM publishes CAMPAIGN_UNSUBSCRIBED for every opt-out path: SMS keyword, WhatsApp UNSUB, and email UNSUB.
|
Item |
Detail |
|---|---|
|
Topic |
|
|
Type |
|
|
Envelope |
Standard |
|
Data |
|
|
Supported reasons |
|
Event data
|
Field |
Required |
Notes |
|---|---|---|
|
|
If available |
From CIM response. |
|
|
Yes |
Customer identifier on the channel. |
|
|
Yes |
Channel service identifier. |
|
|
Yes |
Resolved channel type. |
|
|
No |
Inbound message ID, or null for one-click unsubscribe. |
|
|
No |
Matched keyword for SMS, or null for one-click / non-keyword paths. |
|
|
Yes |
|
|
|
No |
Only if already present. |
|
|
Yes |
Event timestamp. |
Conversation Manager behavior
Conversation Manager persists the CAMPAIGN_UNSUBSCRIBED event and posts intent CAMPAIGN_UNSUBSCRIBED to Conversation Studio through {CONTROLLER_URL}/intent. CCM does not need a handler for this intent.
|
Case |
|
Webhook handling |
|---|---|---|
|
Active conversation for customer / channel identifier |
Real conversation and |
Existing conversation path. |
|
No active session |
|
Accept webhook with |
Out of scope
-
Session,
CAMPAIGN_OUTBOUND, or reply-window changes. -
NLP or multi-word opt-out detection.
-
Scraping
STOPfrom email HTML or quoted replies. -
Re-subscribe flow such as
START. -
Creating fake WhatsApp inbound chat messages for Meta opt-out events.
Referenced components
|
Component |
Reference |
|---|---|
|
WhatsApp connector |
Branch |
|
MS Exchange email connector |
Branch |
|
Gmail IMAP email connector |
Branch |
|
Object model |
Version |