Skip to main content

Creating Campaigns

Campaigns are how you send one-shot or scheduled messages to your users - across email, SMS, push, WhatsApp, in-app, and webhook. Every channel runs through the same six-step wizard, so once you've authored one campaign you know how to author them all.

Channels​

ChannelWhat it sends
EmailRich HTML emails with images, links, and full personalization.
SMSText messages, segmented automatically (GSM-7 vs Unicode).
PushMobile push notifications with title, body, image, and click URL.
WhatsAppApproved WhatsApp Business templates with variable mapping.
In-appMessages displayed inside your app via the SDK. See In-App Campaigns for the redesigned trigger picker, evaluation modes, and frequency capping card.
WebhookServer-to-server JSON payload with Liquid-templated body.

The six-step wizard​

Open the wizard from Campaigns → New Campaign. The header shows a numbered stepper with subtitles, connector lines, green checks on completed steps, and an orange ! badge on any step you visited but left with validation errors. Continue and Save Draft live in the header next to the publish action - there's no bottom nav row to hunt for.

#StepWhat you configure
1DetailsName, description, status, tags.
2DeliveryWhen/how the message goes out.
3Compose MessageThe variant builder + per-channel body.
4AudienceMode chooser → filter builder + audience size.
5ConversionPrimary + secondary conversion events.
6SummaryRead-only review before publish.

Each step transition auto-saves your work as a draft, so you can leave and come back without losing anything.

Step 1: Details​

  • Name (required) and optional Description.
  • Status - draft while you're authoring; flips to active on publish.
  • Tags - team-scoping tags that double as suppression-list bypass tags. A campaign tagged transactional, for example, can bypass any suppression list scoped to the same tag. One list, both purposes.

The tag input is a single field - type a tag, press Enter, and it commits as a removable pill underneath. There's no separate Add button.

Step 2: Delivery​

For email, SMS, push, WhatsApp, and webhook campaigns the Delivery step asks you to pick a send type:

Send typeBehavior
immediateSends as soon as you publish.
scheduledSends at a specific date and time.
recurringSends on a schedule (daily / weekly / monthly / custom cron).
triggeredSends to each user when they perform an event (e.g. purchase, signup).
intelligentPer-user Send-Time Optimization - an ML model picks the best time to deliver to each user.
ai_optimizedAI-Optimized - reinforcement learning selects the channel / template per user.

There's no silent default - the step isn't complete until you've picked one. Per-channel fields (push app, WABA, webhook URL/method/headers) render below the picker. Quiet-time and touching-rules overrides also live here. (Email sender / From / Reply-To / BCC are set in the next step, inside the email editor's Settings tab - and are per A/B variant; see Email Configuration.)

Triggered campaigns turn a campaign into an event-driven send. Pick Triggered, then a trigger type: Event tracked (enter the event, e.g. purchase), WhatsApp inbound (fires whenever a contact messages you on WhatsApp), SMS inbound (fires on an inbound SMS reply), Entity changed (an e-commerce entity such as an order or cart changes), Attribute changed (a user attribute changes value), Subscription status (a channel/list subscription changes), or API (manual entry) (fires when your backend enrolls a user via the API). Choose how often a user can re-receive it: every time the event fires (the default), once per user, or once then a cooldown (set the hours). Publishing a triggered campaign activates it rather than blasting - it then sends to each user the moment they trigger it and still match your audience. Frequency caps and quiet hours still apply.

Duplicate addresses: for broadcast/scheduled/recurring sends, if several contacts share an email or phone (e.g. a couple using one inbox), that address gets the message once - the campaign de-duplicates by recipient at send time. (Triggered sends are per-contact, since each one performed the action.)

In-app campaigns get a different Delivery layout - see In-App Campaigns.

Step 3: Compose Message​

The Compose step is wrapped in VariantTabs - a channel-agnostic tab strip with one tab per non-control variant (lettered A / B / C…) plus a + Add variant button at the end. Each tab shows a colored dot and a read-only weight chip; allocation is edited in the A/B Allocation card below the tabs. An amber dot means the variant hasn't been authored yet.

The active tab renders a per-channel body inside the same shell. Most channels show a live preview alongside the form - the same component the journey-builder modals use, so the rendered notification / message bubble looks identical across surfaces.

ChannelPer-variant body
Email3-tile method picker (Drag & Drop / HTML editor / Use template) → opens VariantEditorShell with the standard side-rail (Settings / Design / Preview & Test / Spam Check).
SMSMessage textarea + GSM-7/Unicode char-and-segment counter, alongside the iOS / Android / Plain phone preview (the same SmsPhonePreview the canvas SMS modal uses).
PushTitle + body with cross-platform char counters (50 / 120) and per-platform tooltips, URL or scheme, image (Asset Picker), up to 2 cross-platform action buttons, Group key (Web tag / Android collapse_key / iOS thread-id), Sound + Badge (iOS · Android only), Keep on screen + Web site name (Web only). Live iOS / Android / Web preview pane on the right (shared PushPreviewWithToggle).
WhatsAppMessage-type segmented control (Template / Session reply), WABA picker, template picker filtered by WABA, variable mapping rows with sample-value substitution. Live chat-bubble preview on the right (shared WhatsAppChatPreview - same one the templates editor uses).
WebhookMethod + URL row, Authentication picker (None / Bearer / Basic / API key / Signed HMAC), Custom headers rows, Request body (JSON / Form-encoded / None) with valid-JSON indicator, Response handling (JSONPath → user attribute), Retry & timeout overrides, shared Advanced delivery options. Body is sent verbatim - add canvas/user metadata via Liquid ({{ canvas.id }}, {{ user.id }}, etc.). Send test fires the request for a Test contact you pick and switches the result between Response received and Request sent (the exact URL, headers and body, credentials masked).
In-appSame 3-tile picker as email; the authored body writes to customContent.

Email authoring - VariantEditorShell​

Once you pick a method, the email body opens in a full-bleed VariantEditorShell with a 200px side rail:

  • Settings - sender config, list-unsubscribe, preheader, metadata.
  • Design - drag-and-drop editor. The HTML editor is a split view: CodeMirror on the left, sandboxed iframe live preview on the right.
  • Preview & Test - desktop / mobile preview, plus test send.
  • Spam Check - score and heuristics for deliverability red flags.

When you return from the shell, the variant body collapses back to an AuthoredSummary card - a real scaled-iframe thumbnail of your rendered email (no more colored-bar mock), with subject, preheader, and an Edit button. Click the thumbnail to re-open the shell.

Change template and Save as template​

  • Change template - once a template is applied, the variant card offers Change template (Use a template when the content was written by hand). It reopens the same template picker. Picking a template replaces the content: if you edited it since the last template was applied, you are asked to confirm first ("Your edits will be lost"). A subject and preview text you already typed are kept, exactly as on the first pick. Available for email (Drag & drop and HTML), push, in-app and webhook. A WhatsApp template is chosen in its own dropdown, which you can change at any time; SMS and Viber have no template library.
  • Save as template - saves the variant's current content as a new template: email keeps its authoring method (Drag & drop reopens editable in the drag & drop editor, HTML stays HTML) with its subject and preview text; push keeps title, body, link, image and buttons; in-app keeps the layout and the HTML or Drag & drop design. Enter a name (prefilled "campaign name - channel") and optional tags; the confirmation links to the new template. The campaign keeps its own copy and is not linked to the template. Needs permission to edit templates. App style in-app messages and webhook requests cannot be saved as a template.

A/B variants​

The A/B card (allocation + stopping rule + optimization method) shows for every variant-based channel: email, SMS, push, WhatsApp, webhook, and in-app. Total weight across variants must sum to 100%. Control group keeps its configured weight when you add or remove message variants - only the non-control variants are rebalanced.

Optimization method is locked with a "Needs 2+ variants" pill until you add a second variant. See A/B Testing for the stopping-rule presets (Quick / Standard / Custom) and Statistical Significance for the math.

Step 4: Audience​

The Audience step opens with a mode chooser - two large tiles under "Choose targeting approach":

  • Targeted audience (RECOMMENDED - green badge). Picks the filter-groups builder.
  • Send to everyone - broadcasts to your entire workspace. The tile shows the live workspace reach as a pill.

Once you pick a mode the tiles disappear and a small "Switch to a targeted audience" / "Send to everyone instead" button appears in the card header so you can flip back.

Targeted audience - filter builder v2​

The filter builder is shared 1:1 with the segment editor and uses the new v2 chrome:

  • Numbered colored badges per group - 1 green, 2 amber, 3 blue, 4 pink, 5 purple - replacing the old "Filter Group N" header.
  • AND/OR ConnectorChip between sibling rows AND between groups. The chip is the toggle - no per-group "Match ALL/ANY" header, no top-level "Match ALL groups" radio.
  • + Add condition dashed button at the foot of each group; + Add filter group dashed button below the last group.
  • Confirm modal before deleting a non-empty group - empty groups delete silently.
  • Live count pill per group + a workspace-level pill in the right rail. Pills re-evaluate ~400ms after you stop editing and apply the same channel + subscription gate the right rail uses.
  • Event and attribute pickers are now searchable comboboxes. When you type a name that doesn't exist, the dropdown shows an extra + Create event "<query>" (or + Create attribute "<query>") row that registers the schema entry on the spot - useful for building campaigns ahead of engineering wiring up tracking.

An Exclude block renders below the include block so you can express "include X but remove anyone matching Y" without embedding NOT logic in every group.

Right-rail Audience size​

A 340px right rail tracks audience size live as you edit:

  • A green Live pill in the header.
  • The total matching count, plus the percentage of the workspace it represents, with a 4px progress bar visualizing the percentage.
  • A per-channel breakdown beneath the total: how many of those users have a valid email / SMS / push / WhatsApp address AND are subscribed to that channel.
  • A caption explaining the gates - for example, on an email campaign: "Reflects users matching your filters AND: have a valid email address, subscribed to email."

For in-app campaigns the channel breakdown and subscription caption are hidden - in-app messages have no subscription concept.

Sending options​

Below the builder a Sending options card lets you decide which subscription state to send to. It's a single rich dropdown - each option has a title and a subtitle so the consequences are visible before you click:

  • Subscribed users only (default) - excludes unsubscribed users.
  • Confirmed (double opt-in) - only users who completed double opt-in.
  • Everyone, including unsubscribed - flips the trigger to a red danger style with a USE WITH CAUTION pill. Picking this option fires a confirmation modal walking through the CAN-SPAM / GDPR / sender-reputation risks. Reserved for genuinely transactional sends.

The Sending options card is hidden for in-app campaigns.

"Send to everyone" mode​

If you pick the Send to everyone tile, the builder is replaced by an amber warning callout listing the four reasons broadcasting unfiltered hurts long-term outcomes (lower engagement, higher unsub / spam rates, worse sender reputation, harder to measure). Try the suggested filters in the recommendation paragraph before broadcasting.

Step 5: Conversion​

Pick a primary conversion event that marks a user as converted, plus an attribution window (hours after send) and an attribution model (first_touch / last_touch / linear). You can also add secondary conversion events alongside (e.g. added_to_cart, viewed_pricing) - each with an optional label.

The message goals - Opened email, Clicked email link, Clicked SMS link, Clicked WhatsApp link and Tapped push notification - count only what people did: a bot open or a link scanner's click never converts anyone. Opened email also counts a person who clicked the email, because the click proves the open.

Step 6: Summary​

A read-only review of everything you configured. Validation errors from earlier steps surface here as a banner before publish. Click Publish to flip the campaign from draft → active.

Who will receive it - the control-group split​

The audience count is the people matching your targeting, not the number the campaign sends to. Under the count on the Audience step, and again on the Summary, the wizard states the expected split:

1,000 in audience - about 200 held out as control group (20%) - about 800 will receive it

New campaigns start with a 20% control group (set in the Message step under A/B testing). The control group gets nothing from this campaign, on purpose, so its impact can be measured against them - see Control groups. If the workspace has a global control group, it is applied first (up to 20%, not for transactional sends or exempt tags), and the campaign's control group takes its share of the rest.

The final count is decided at send time: frequency caps (unless the campaign ignores touching rules), quiet hours set to skip, unsubscribes, suppression lists and missing or shared addresses can reduce it. After sending, the Not sent card on the campaign's analytics shows who was skipped and why.

The launch confirmation applies those same rules before you send, the way the send applies them: frequency caps, unsubscribes (channel, category and sending number), suppression lists, addresses that unsubscribed or bounced, the global control group, and quiet hours in each person's own timezone at the scheduled send time (or now, for an immediate send). Each shows as its own line under the skipped count. For audiences over 1,000 people the numbers are estimated from a sample of the first 1,000.

Under 20 people - no control group​

When fewer than 20 people are left to receive a send - after frequency caps, suppression lists, unsubscribes and the workspace control group - the campaign's own control group is not applied, and everyone eligible receives the message. A control group of a few people cannot measure anything: with 2 people, a 20% control group would hold out one of them or both, by chance, and the result would be noise. The Audience step, the Summary and the launch confirmation say so:

Under 20 people - no control group, everyone receives it

  • The workspace global control group still applies at any audience size.
  • The send records that its control group was skipped and why (an audience of 2 is too small to measure). A recurring campaign records this per send. Campaign analytics shows that note instead of an uplift - see No uplift for small sends.
  • It is decided at send time, on the people eligible then: an audience of 25 that loses 6 to unsubscribes is also sent without a control group, and a recurring campaign can have a control group on one send and not on the next.
  • Triggered campaigns (one person per trigger) and one-shot A/B tests that send a test slice first keep their control group at any size.

Reviewing before send​

Before publishing, double-check:

  • Audience size matches your expectations
  • Channel breakdown has a non-zero count for the channel you're sending on
  • Preview & Test renders correctly on both desktop and mobile
  • Personalization variables resolve to real values
  • Schedule uses the right timezone
  • Spam Check score is acceptable (email)

Monitoring performance​

Once a campaign is live, the campaign detail page shows real-time stats:

  • Sent / delivered / opened / clicked / converted / bounced / unsubscribed
  • Per-variant breakdown for A/B tests
  • Bot-flagged events are excluded by default so opens and clicks fired by mailbox-provider link prefetchers and security scanners don't inflate your numbers. See Event Explorer for how to interpret the "Bots excluded" hint.

Campaign states: draft → scheduled → sending → sent (or paused / cancelled).

Best practices​

  • Filter to specific segments instead of broadcasting
  • Test multiple subject lines / CTAs with A/B variants
  • Use timezone-aware sending where applicable
  • Send a test before hitting publish
  • Don't send the same message to everyone
  • Don't pick "Everyone, including unsubscribed" without genuine transactional justification

Common patterns​

Welcome campaign​

Send right after signup. Filter on a signed_up event in the last day. Compose a single email variant with the getting-started CTA.

Re-engagement​

Filter on inactive_30_days behavioral filter, exclude users who already converted in the last 14 days, and offer an incentive.

Abandoned cart​

Filter on added_to_cart performed but purchase_completed not performed within the last 24h.

Product announcement​

Filter on plan = "premium" AND active_last_30_days, send a single email variant with the launch link.

Next steps​