Skip to content
Expedify
7 min

Campaign Send

Three nodes that make a campaign: who it goes to, what it says, and the send. The compliance filtering is the part you would otherwise have to remember every time.

Bulk Send in the last lesson took a list and a body and mailed it. That is enough for a digest and not enough for marketing, because marketing has obligations. Someone unsubscribed last month. Someone's address bounced twice. Someone is in two of the four segments you picked and should not get it twice.

Campaigns in Expedify are three nodes rather than one, and the split is exactly those obligations. One builds the audience and applies the rules. One picks the message. One sends and records what happened. Chain them and the compliance is structural rather than something you remembered.

The audience

audience_ids

What it holds
List of audience/segment IDs to include

exclude_unsubscribed

What it holds
Exclude unsubscribed contacts Defaults to true.

exclude_bounced

What it holds
Exclude contacts with bounced emails Defaults to true.

require_email

What it holds
Only include contacts with valid email addresses Defaults to true.

max_audience_size

What it holds
Maximum number of contacts to include Defaults to 10000.

sampling_method

What it holds
Method for sampling when audience exceeds max size One of: random · recent · oldest · engagement_score Defaults to random.

The exclusions default to on, and that is the point of the node. Unsubscribed and bounced contacts are removed before anything downstream sees them, so no part of your workflow has to know about consent. It also deduplicates across the segments you named — a contact in three of them is one recipient.

Sampling is for testing, and it is the one setting to touch carefully. max_audience_size caps the list and sampling_method decides which ones survive the cap. Set the cap to 50 while you are building and your campaign goes to fifty people instead of five thousand — which is how you want to discover a broken merge field. Just remember to raise it.

The message, and the send

Seven of twenty-six. The rest are batching, retry, campaign bookkeeping and the WhatsApp-specific ids.

channel

What it holds
Communication channel One of: email · sms · whatsapp Defaults to email.

template_source

What it holds
Source of template (manual or input) One of: manual · input Defaults to manual.

template_id

What it holds
Selected template ID (when source is manual)

contact_source

What it holds
Source of contact data One of: input · config Defaults to input.

contact_input_variable

What it holds
Input variable containing contact data

track_opens

What it holds
Track email opens Defaults to true.

track_clicks

What it holds
Track email link clicks Defaults to true.

Two _source fields decide where the node looks. template_source is manual when you picked a template in the panel and input when an upstream node chose it. contact_source is input when the audience node built the list — which is the normal shape and the default.

Personalisation is not a node. There is no Campaign Personalization step, and people look for one because the video for the old version implied it. The merge fields live in the template and are mapped in this node. If a name is not appearing, the mapping is here.

A worked example

A re-engagement campaign, monthly. The segment is named once, the compliance filtering is the audience node's default behaviour, and the template is chosen by a node rather than pasted into the send.

Audience, template, send

Each node hands the next one exactly what it needs, by variable.

tool

Scroll for all 4 steps →

Read the two variables and the chain explains itself. {{audiencesegmentation_1.contacts}} is the filtered list — not the segment, the survivors of it. {{templateselection_1.template.id}} is the chosen template. Neither node knows anything about the other; the send is what joins them.

Putting the template behind its own node looks like ceremony for one field, and it is — until the choice becomes conditional. A Condition ahead of two Template Selections, both feeding one send, gives you a campaign that says different things to different halves of the audience with no duplicated send configuration.

Which sending node

When
One person. Transactional. The content belongs to the workflow.

When
A list, same content, written in the node. No consent rules beyond what you enforce yourself.

When
Marketing. The content is a template someone maintains elsewhere, unsubscribes and bounces must be honoured, and you want opens and clicks recorded against a campaign.

The question that settles it: if this message goes to someone who unsubscribed, is that a problem? If yes, you want the campaign nodes, and you want them even for a small list.

What breaks

Watch out: WhatsApp send needs channel: whatsapp + FOUR ids (template_id, integration_id, workflow_segment_id, workflow_campaign_id).

Also contact_input_variable + a tracking_options.template_parameters typed map (param_N: {type, field, entity}).

A campaign that sends nothing used to report success. When no template resolved, each recipient was skipped in a way that recorded nothing at all — and the summary computed failures as “results minus successes”, which on an empty list is zero. So the run was green, the node was green, and not one message existed. This is fixed: a send that reaches nobody now fails and leaves down the error path. Zero recipients is still a success, because there was nothing to do.

If your Expedify predates that fix, the green run means nothing. Check the campaign's own record — recipients and sends — rather than the workflow's execution status. That is the habit worth keeping regardless of version: the execution log tells you the node ran, and the campaign tells you whether anyone was mailed.

A contact id is not a contact. Pointing contact_input_variable at something like {{trigger_1.new_data.id}} is the natural way to mail whoever fired a trigger, and it used to file the raw UUID as the email address — which the provider then refused. It is now recognised and resolved. Prefer handing this field the audience node's contacts array anyway; it is the shape everything downstream expects.

WhatsApp campaigns need four ids, not one. The warning above is the node's own. It is not a bug — a WhatsApp template send has to be attributed to a campaign and a segment on the provider's side as well as yours — but it does mean a WhatsApp campaign cannot be assembled the same way an email one can. Build the email path first.

Try it

  1. Add an Audience Segmentation, name one segment in audience_ids, and run only that node. Read {{alias.segment_count}} and compare it with the segment's own member count — the difference is your unsubscribes and bounces.
  2. Set max_audience_size to 5 and run it again. This is the setting to have on while you build.
  3. Add Template Selection and Campaign Send behind it, wired as above, and send to that audience of five. Check your own inbox and the campaign record.
  4. Now point template_input_variable at a template that does not exist and run it. The campaign should fail rather than succeed quietly — if it reports success, your deployment predates the fix and you cannot trust a green run.

Next: Voice Response — the first of four nodes about talking to people on the phone, where the reply has to be spoken while they wait.

Related lessons