Notification event design
Events and campaigns are the two surfaces a Notifizz user touches. Together they define what happened, what to do about it, and who it concerns — but each lives in a different place.TL;DR
- An event is what your code emits with
client.track(eventName, properties). No campaign id, no recipient list. - A campaign is a dashboard-defined reaction to an event — its orchestrator code, channels, and content.
- Properties ride on the event; the campaign’s orchestrator (and any registered enricher) turn them into recipients and template values.
- The same event can drive multiple campaigns without code changes.
- In a multi-message sequence, recipients are either recalculated each send (default) or locked to those of the first send — a per-campaign setting on the Recipients card.
Events
An event is a single fact about your application. You name it, you attach properties, you emit it.(eventName, properties, options). The SDK never references workflows, campaigns, or recipients.
Naming events
Events follow adomain.event_name shape — for example order.shipped, user.signed_up, invoice.paid: the domain says where the fact comes from, the name says what happened, in the past tense. Stable names matter: campaigns key on them, and renaming an event after a campaign ships breaks the wire-up.
Properties
Properties are arbitrary JSON-serialisable data — strings, numbers, booleans, nested objects. They serve three jobs:- Recipient identification — the orchestrator extracts
userId,email, or whatever your campaign keys on, directly or via an enricher. - Template substitution —
{{ trackingUrl }}in the notification content resolves to the property. - Routing context — campaigns can branch on properties (e.g. send a different notification when
plan === "pro").
Idempotency
Every event carries an idempotency key. Auto-generated UUIDs are fine for one-off emits; for retried jobs, set a deterministic key derived from your domain:{ duplicate: true }). See Event Tracking reference.
Campaigns
A campaign (the term workflow is used interchangeably in older docs and in some backend code paths) is a dashboard-configured reaction to an event. It owns:- The event name it listens on.
- An orchestrator — generated code that builds the recipient list from event properties + enrichers.
- One or more channels with their templates (Notification Center config, email config, …).
- A status (
Editing/Implementation/Review/Live/Offline/Archived) that controls whether it runs, and in which environment.
order.shipped fires, every campaign listening on order.shipped runs its own orchestrator independently — fan-out is automatic.
One event, many campaigns
This is the common pattern: a single product event drives several distinct notifications. Each campaign decides its own recipients (from event properties or an enricher), its own channel, its own template. Adding a new campaign is a dashboard task — no code change.Versioning and lifecycle
Campaigns move through six statuses —Editing, Implementation, Review, Live, Offline, Archived — and the runtime gate is per-environment: Review sends on non-production environments only, Live sends for real, Archived is terminal. The full status table, runnable filter, and version semantics are in campaigns concept.
Each save creates a new version — in-flight workflow instances run against the version they started on, even if a newer version has shipped since.
Recipients
Recipients are produced by the campaign’s orchestrator, not by the SDK call site. The orchestrator runs server-side, reads the event properties, and returns a list of recipient objects. Each must have at minimum:displayName, locale, timezone, …). The orchestrator can:
- Extract recipients directly from event properties —
{ userId, email }baked into the event. - Resolve them via an enricher — a server-side function the orchestrator calls to fetch user data live (enrichers tutorial).
- Reach an audience the event never names — every admin of a team, every watcher of a document — with an enricher that returns a list (recipients).
Sequences: who receives the follow-up sends
A campaign can carry several messages spread over time — day 0, day 1, day 10. At every send, the orchestrator runs again and resolves the recipients live. That raises one question the platform makes explicit: should someone who enters your audience between two sends receive the follow-ups? The answer is a setting on the Recipients card, with two values:- An invoice reminder sequence (day 3, day 10, day 30 after
invoice.issued) wants recalculated each send: if the billing contact changed between two reminders, the reminder must reach the current contact — the sequence is about the invoice, not about a person. - A three-message activation sequence (welcome, tips, upgrade nudge) wants from the first send: message three makes no sense for someone who never saw message one. A user who signs up on day 9 shouldn’t land in the middle of a story that started without them.
- The setting blocks arrivals, it doesn’t compensate departures. Recipients who appear after the first send don’t receive the rest — and recipients who left your audience in the meantime are not replaced. It’s normal for the second send to reach fewer people than the first; the per-send statistics show the difference, and excluded latecomers appear under their own label, “Not in the first send”.
- Your identifier is what makes someone the same person. Notifizz holds no customer data — the sequence follows each recipient by the identifier your application returns at each send. That’s the direct counterpart of being privacy friendly: a platform that resolves identity across changes can only do it by holding your user base. See how recipients are recognised.
Where each piece lives
FAQ
Can I send to a specific user from the SDK?
Can I send to a specific user from the SDK?
userId in the event properties and let the campaign’s orchestrator return that user as the only recipient. If you find yourself wanting “send this exact notif to this exact user”, model it as a campaign listening on a dedicated event.What happens to in-flight workflow instances when I edit a campaign?
What happens to in-flight workflow instances when I edit a campaign?
I renamed an event — does the old campaign still work?
I renamed an event — does the old campaign still work?
Can two campaigns on the same event interfere?
Can two campaigns on the same event interfere?
How do I model 'cart abandoned after 30 minutes'?
How do I model 'cart abandoned after 30 minutes'?
cart.abandoned from your backend after a server-side timer; or (2) emit cart.created and let the campaign’s orchestrator schedule the delayed step. Option (1) keeps timing logic in your domain; option (2) keeps everything in Notifizz. Both are common.What does 'transactional' vs 'marketing' mean here?
What does 'transactional' vs 'marketing' mean here?
track(). Priority is decided per campaign — transactional campaigns jump the queue.Fewer recipients on the second message than on the first?
Fewer recipients on the second message than on the first?
Someone didn't receive the follow-up although they should have?
Someone didn't receive the follow-up although they should have?
I can't enable 'From the first send'?
I can't enable 'From the first send'?