Bento

Take Action: Let's Build a Flow That Has Events, Tags, Fields, & Emails!

Create and test a flow that sets tags and fields from passed-in event data, and sends personalized emails.

In the Flow-Driven Sequence Setup lesson, you built a flow that managed sequences. The flow responded to events, but didn't do much with the data those events carried.

This time, we're building a flow that actually uses event data - setting fields, adding tags, and sending personalized emails based on what the event tells us about the subscriber and what they just did.

This is where flows go from "routing logic" to "personalized automation," and it's one of the things Jesse says SaaS companies get most excited about.

For reference, see the Events, Workflows, and Liquid Template Guide docs.


The Two Types of Data in Flow Emails

Before we build, there's one concept worth understanding clearly, because a lot of people don't realize this exists.

When a flow sends an email, that email has access to two types of data:

1. Visitor data ({{ visitor.* }}) - the subscriber's profile fields. First name, email, plan type, any custom field you've set on their record.

This is always available, regardless of how the flow was triggered.

2. Event data ({{ event.* }}) - data that came in with the triggering event. The event type, plus any key-value pairs in the event's details object.

Here's what that looks like in practice:

Hey {{ visitor.first_name | default: "there" }}, Thanks for signing up for the {{ event.details.plan_name }} plan!

visitor.first_name pulls from the subscriber's profile.

event.details.plan_name pulls from the data that was passed in with the event when it fired.

Both work inside the same email, and you can mix them freely.

This distinction matters because event data is contextual - it tells you what just happened right now, while visitor data tells you who the person is in general.

This means that if you need to access data in future emails that live outside this automation, it's important that any data needed for them is stored in the user's profile as fields, since event details are ephemeral and will disappear outside of this Flow chain.


What We're Building

Two chains on the same flow canvas:

The main chain is triggered by a $signed_up event and does three things:

  1. Sets a field on the subscriber's profile from the event data
  2. Adds a tag with a dynamic name based on the event data
  3. Sends a personalized welcome email using both visitor and event data

A test trigger chain is a tiny side chain that lets you test the main flow without needing external tools. You trigger a simple $test_signup_data_flow event on a test subscriber, the test chain fires the $signed_up event with dummy details, and the main chain kicks off automatically.

By the end, you'll have a working example of data flowing from an event, through a flow, and into a subscriber's profile and inbox - plus a reusable pattern for testing event-driven flows from within Bento.


Action Steps

1 - Set the previous lesson's flow to "draft" status

We'll use the same trigger event name here, so it's important to disable the previous flow to avoid double-triggers.


2 - Create a new flow with an event trigger

Go to Flows and create a new flow.

Name it something like "Bento Training - Signup Data Flow."

For the trigger, choose Event Received and set it to listen for the event $signed_up.

Leave the flow in Draft mode for now.

We'll activate it once everything is wired up and tested.


3 - Create and add a personalized email

Now add a Send Email action after the tag step.

You'll need to create an email template for it. Can just stick to Shoji for now.

When creating the email, use both visitor and event data in the content:

Subject line idea:

Welcome to the {{ event.details.plan_name }} Plan, {{ visitor.first_name | default: "friend" }}!

Body example:

Hey {{ visitor.first_name | default: "there" }}, Thanks for signing up for the {{ event.details.plan_name }} plan! We're excited to have you on board. Here's what to do next...

Keep it simple for now.

The point is seeing how both data sources work together in a real email.

The | default: "there" filter is important; it provides a fallback if the subscriber doesn't have a first name set.

Always use defaults for fields that might be empty. (Or use a liquid conditional expression to hide lines when required fields are missing) But don't worry about that yet.

We'll go deeper on Liquid in the How To Use Liquid In Bento For Epic Power lesson. For now, the basics above are all you need.


4 - Add a "Set Field" action

Add a Set Field action as the first step after the trigger.

Set the field name to plan_type.

For the value, use the Liquid expression:

{{ event.details.plan_name }}

This pulls the plan_name value from the event's details and writes it to the subscriber's plan_type field.

So if someone signs up and the event fires with "plan_name": "Professional", their profile will now show plan_type = "Professional".

This is one of the most useful patterns in Bento: using event data to populate subscriber fields automatically, so you don't have to set them separately.


5 - Add an "Add Tag" action

Add an Add Tag action after the Set Field step.

For the tag name, you can use Liquid to make it dynamic:

Signup - {{ event.details.plan_name }} Plan

This would create tags like Signup - Professional Plan, Signup - Free Plan, etc., based on whatever plan name the event carried.

If you'd rather keep it simple, a static tag like Flag - Signed Up works fine too.

Dynamic tags are a power move, not a requirement.

In my setup, I often like to add two tags: One generic "customer" tag that all customers get, regardless of what they bought, to make it easy for me to see all customers, and then a separate one for the specific thing they bought.

So in this case, if I were doing it "for realzies," I'd probably scaffold out the following tags:

  • Flag - Customer
  • Flag - Customer - Pro Plan
  • Flag - Customer - Lite Plan
  • Flag - Lead - Free Plan

A note on routing: in a real setup, you might want different outcomes based on the plan name - a "Premium" tag for premium signups, a "Free" tag for free ones.

Bento gives you a few ways to handle that: field-value splits (branch based on whether a field equals a specific value), simple if/else conditions, or magic splits using Liquid expressions.

In the video I briefly show a field-value split on screen so you can see the shape, but we'll dig into magic splits properly in the How To Use Liquid In Bento For Epic Power lesson.

Screenshot of a dark, node-based workflow builder canvas (titled "Example - Split Based on Plan …") showing an automation flow where a "New Event: Plan purchased" trigger connects to a "Field Switch: Switch on plan purchased" block that branches into three paths labeled "plan_a," "plan_b," and "Other," leading respectively to "Add Tag: Flag - Customer - Plan A," "Add Tag: Flag - Customer - Plan B," and "Send Internal Email: Plan not found!"; the Plan A and Plan B paths then merge into "Add Tag: Flag - Customer" and continue to a "Create Event" step, with no arrows or highlight annotations present.

For now, the simple "one tag, one action" pattern we're building here is the right starting point.


6 - Build a test trigger chain

Here's a practical pattern you can reuse for any event-driven flow: instead of needing external tools to fire test events with specific data, build a tiny test chain right on the same flow canvas.

Add a second trigger to your canvas: Event Received, listening for $test_signup_data_flow or whatever you want.

Connect it to a single action: Create Event, which fires $signed_up with the following details:

{ "plan_name": "Professional" }

Screenshot of a "Create Event" configuration page in a dark-themed workflow app, with the top tabs showing Settings selected (and Stats, Logs, and Manual Run inactive), where the "Event Type" field is set to "$signed_up" and the Details section contains one key-value row "plan_name" = "Professional" with an "+ Add Row" button below, while the Fields section is empty with its own "+ Add Row" button.

That's the whole test chain. When $test_signup_data_flow fires on a subscriber, the chain fires the $signed_up event with those dummy details, which kicks off the main chain.

This is a variation of the "passing event data downstream" pattern we covered in the Events & Flows Overview lesson - except here, you're specifying static test data instead of forwarding data from a previous event.


7 - Test the flow

First, use Bento's built-in flow test suite to verify the logic routes correctly.

You'll need the flow published first. Then in the flow editor, click Start a task > Test.

Screenshot of the Bento workflow builder canvas showing a signup automation flow with nodes for "New Event: Fire Test - $signed_up" leading to "Create Event: Trigger $signed_up" and a separate "New Event: Signed_up" leading to "Send Email: Thanks for signing up," with two large pink arrows pointing to the top-right toolbar at the "Run" button and the "Live" status toggle next to "Draft" (above the blue "Save" button).

Then choose "Manually add user."

Screenshot of a dark workflow automation builder showing a simple flow on the left ("New Event: signed_up" connected to "Send Email: Thanks for signing up") and a "Run Flow" slide-out panel open on the right with an empty Run Log; a large pink arrow points to the first action option in the panel, "Manually Add User," indicating where to click to add a single user to test/run the flow.

Choose your test-firing event, add a test email that you can check, and run it.

If the test email maps to one of your already-created subscribers with a first_name set, it'll display their already-set first name; otherwise it'll use the "friend" fallback.

Screenshot of a workflow automation builder canvas titled "Bento Training - Signup Data Fl…" with two flow branches; on the right, the "Run Flow" sidebar is open showing "Start User" fields with the Email Address set to "yourtestaddress@whatever.com," the Starting Trigger dropdown set to "Fire Test - $signed_up," and a "Start Session" button, all emphasized by pink arrows pointing to the email field, the starting trigger dropdown, and the Start Session button.

You'll see the event move through each step of your flow, which is great for catching logic mistakes before real subscribers hit it.

The test chain fires $signed_up with the dummy details, the main chain picks it up, and you should see:

  • plan_type set to "Professional" on the subscriber's profile
  • The tag applied (either dynamic or static, depending on what you chose)
  • The welcome email sent with personalized content

And you should also see the email in your inbox with the event details correctly passing in to the template:

Screenshot of an opened email in Gmail showing the message "Welcome to the Professional plan, friend!" with pink highlight boxes around the words "Professional" and "friend!" in the subject line, around the greeting "Hey there," in the email body, and around the word "Professional" in the line "Thanks for signing up for the Professional plan!" indicating the emphasized text.

Check the subscriber's profile afterward to confirm everything landed.

For the full rundown on the test suite, see the How to Test Email Flows guide.

We'll practice branching with magic splits, field switches, and dynamic event dispatching in the Build & Test Advanced Flow Branching lesson.


When to move on

  • You've built a flow with a main chain triggered by a custom event
  • The flow sets a field from event data ({{ event.details.* }})
  • The flow adds a tag (static or dynamic)
  • The flow sends an email that uses both {{ visitor.* }} and {{ event.details.* }}
  • You've built a test trigger chain that fires the main event with dummy details
  • You've tested the flow end-to-end using the test trigger
  • You understand the difference between visitor data and event data in flow emails