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.).
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.

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.

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 draftactive.

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: draftscheduledsendingsent (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