Skip to main content

Automation

FunnelFizz automations are workflows — DAGs of Send / Wait / Split steps — that fire when a specific event happens (a profile enters a stage, a trial starts, a subscription activates).

For conceptual overview, see Concepts → Automations. This page is the feature reference.

The canvas editor

Open any stage → Automations tab → Create automation.

You get a ReactFlow canvas with:

  • Step palette (left) — drag any step type onto the canvas.
  • Canvas (center) — arrange steps and connect them with edges.
  • Settings (right, when a step is selected) — configure that specific step.
  • Toolbar — save, validate, activate/deactivate.

Each step is a card with a handle on the left (input) and one or two handles on the right (outputs). Drag from an output handle to another step's input handle to connect them. Splits have two output handles; everything else has one.

Triggers

Pick the trigger when you create the automation:

TriggerWhen it fires
subscription_trialStripe subscription enters status = "trialing"
subscription_paidStripe subscription enters status = "active"
stage_enter (legacy)Profile enters any stage

Only one trigger per automation. If you want the same sequence to fire on both trial and paid events, create two automations.

Steps

SEND_EMAIL

Composes and queues an email send.

Config:

  • Subject — string (supports {{variables}}).
  • Sender — pick from your verified senders.
  • Blocks — the email body (same MJML block system as standalone campaigns).

What happens: the step writes an EmailSend row with status = "QUEUED". The email-queue cron picks it up within a minute and actually sends it.

The step completes immediately after queuing — it doesn't wait for the email to be delivered. If you want the workflow to wait for an open or click, use a WAIT_UNTIL step next.

WAIT

Pauses for a fixed duration.

Config:

  • Months / Days / Hours / Minutes — pick any combination.

What happens: sets nextStepAt = now + delay. The cron re-claims the run when the delay elapses.

WAIT_UNTIL

Pauses until an event fires, with optional timeout.

Config:

  • Event nameemail_opened, email_clicked, pageview, custom event names.
  • Timeout (optional) — "give up after X duration."

What happens: sets status to WAITING_FOR_EVENT. When the event fires on this profile, the run flips back to RUNNING and continues. If the timeout expires first, the run also continues, but you can branch based on which happened via a CONDITIONAL_SPLIT immediately after.

CONDITIONAL_SPLIT

Branches based on a condition.

Config:

  • Condition — examples:
    • email_opened == true
    • pageview_count >= 3
    • country in ['US', 'CA']
    • profile.plan == 'pro'
  • Output A — the "matched" branch.
  • Output B — the "didn't match" branch.

What happens: the cron evaluates the condition against the profile's current state, follows the matching edge.

PERCENTAGE_SPLIT

Deterministic A/B split.

Config:

  • Percent to A — e.g., 50 (other 50% goes to B).

What happens: hash(runId + stepId) mod 100 < percent determines the branch. Same profile always takes the same branch, so you can A/B test variants of downstream content.

Saving, validating, activating

  • Save — writes the DAG to the database. Automation stays in DRAFT.
  • Validate — checks for issues: disconnected nodes, cycles (DAG must be acyclic), missing config on any step.
  • Activate — flips status to ACTIVE. New profiles matching the trigger enter the flow.

Deactivating is symmetric: existing runs keep walking through the graph, but no new profiles enter.

Per-profile runs

When an automation is ACTIVE and the trigger fires for a profile, FunnelFizz creates an AutomationRun row:

  • automationId — which automation.
  • profileId — which profile.
  • currentStepId — where they are in the graph.
  • status — RUNNING, WAITING_FOR_EVENT, COMPLETED, CANCELLED.
  • nextStepAt — when to wake them up.

The cron every 5 minutes claims due runs, advances them by one step, updates the row. Each profile is independent of every other.

Cancellation

A run is cancelled when:

  • The profile unsubscribes from your emails (workspace-wide).
  • You manually pause the automation and explicitly cancel in-flight runs.
  • The profile is deleted (rare; happens on data-export/delete requests).

Common patterns

Trial-to-paid conversion

trigger: subscription_trial

[SEND_EMAIL: "Welcome, here's the quickstart"]

[WAIT: 2 days]

[SEND_EMAIL: "Here are 3 things Pro users do"]

[WAIT: 4 days]

[CONDITIONAL_SPLIT: profile.subscriptionStatus == "active"]
│ │
▼ true (already upgraded) ▼ false
[END] [SEND_EMAIL: "Trial ends tomorrow"]

Churn recovery

trigger: stage_enter CUSTOMER where bucket == "Churned"

[WAIT: 7 days]

[SEND_EMAIL: "Can you tell us why you left?"]

[WAIT_UNTIL: email_clicked (timeout: 14 days)]
│ │
▼ clicked ▼ timed out
[SEND_EMAIL: 20% off comeback] [SEND_EMAIL: 30% off last chance]

A/B test your onboarding

trigger: subscription_trial

[PERCENTAGE_SPLIT: 50% to A]
│ │
▼ A ▼ B
[SEND: variant A] [SEND: variant B]

After enough runs, compare the downstream conversion rates in the campaign dashboard.

Plan limits

FREEHOBBYPRO
Automations per stage015
Max step depth35

Depth is the longest path from trigger to any leaf. A 3-step linear sequence with one branch is depth 3, not 4.

What's not here (yet)

  • Cross-funnel automations. Automations are scoped to one stage in one funnel. Global automations are on the roadmap.
  • Custom HTTP action step. No "make an API call" step today. Use Zapier or n8n for outbound webhooks if you need them.
  • Conditional entry filters. Every profile matching the trigger enters. If you need to filter, put a CONDITIONAL_SPLIT as the first step with an "end" branch for non-matches.

Next: Splitting → — the eight split conditions.