How to create dynamic email content in Customerio using custom attributes

If you’re sending the same email to everyone, you’re missing out. People expect at least some effort—like a first name, or content that actually fits their interests. If you’re using Customer.io, good news: you can make your emails way more dynamic with custom attributes. This guide is for people who want to get past “Hello, {{first_name}}” and actually use Customer.io’s tools without overcomplicating things.

Below, I’ll walk you through setting up custom attributes, using them in your emails, and share a few things I wish I’d known before I started. No fluff, just what works.


Step 1: Understand What Custom Attributes Are (and Aren’t)

Before you dive in, let’s set expectations. Custom attributes in Customer.io are extra pieces of data you attach to your users—think “subscription_plan,” “signup_source,” “favorite_color,” whatever makes sense for your business.

  • What they can do:
  • Make emails more personal (“Hi {{first_name}}, ready for your next {{favorite_color}} adventure?”)
  • Control logic—send different content to people on different plans, or who’ve taken certain actions.
  • Help segment your audience for triggered or automated sends.

  • What they can’t do:

  • Run complex logic like a programming language (you’re still limited to Liquid templating).
  • Fix messy or missing data automatically—you need to make sure attributes are set and up to date.

If you’re looking for deep behavioral tracking (like “visited this product page three times in the last week”), you’ll probably need more than just custom attributes.


Step 2: Set Up Your Custom Attributes

You can’t use what you haven’t stored. Here’s how to get your custom attributes into Customer.io.

2.1. Decide What to Track

Don’t just import every bit of data you can think of. Start with what you’ll actually use.

  • Personal details (first name, location)
  • Product info (plan type, last purchase)
  • Engagement data (last login, feature flags)
  • Preferences (newsletter opt-in, favorite topics)

Pro tip:
If you’re not sure you’ll use it in the next 3 months, skip it for now. Too much data just clutters things up.

2.2. Import or Sync Attributes

How you get data into Customer.io depends on your setup:

  • Manual upload:
    If you’ve got a simple list, you can upload a CSV with custom fields.
  • API integration:
    For most SaaS apps, you’ll use Customer.io’s API to keep user data synced. This is worth setting up if you want attributes to stay updated automatically.
  • Third-party integrations:
    Tools like Segment or Zapier can help sync data if your stack is already using those.

What trips people up:
- Make sure attribute names are consistent (e.g., use “plan” everywhere instead of “Plan” or “subscription_plan” in different places). - Don’t use spaces or special characters in attribute names; stick to underscores or camelCase.

2.3. Check Your Data

Before you start building emails, spot-check some user profiles in Customer.io to make sure your attributes are actually there and look right. It’s easy to waste time debugging templates that just need better data.


Step 3: Use Custom Attributes in Your Emails

Now for the fun part: putting those attributes to work.

3.1. Insert Attributes in Email Content

Customer.io uses Liquid templating. To pull in a custom attribute, just use double curly braces:

liquid Hi {{first_name}}, thanks for joining the {{plan}} plan!

If you want to get fancy with fallback values (in case the attribute’s missing):

liquid Hi {{first_name | default: "there"}}, welcome!

3.2. Conditionals: Show or Hide Content

You can do basic if/else logic based on attribute values. For example:

liquid {% if plan == "pro" %} Thanks for being a Pro customer! Here’s your exclusive tip... {% else %} Upgrade to Pro for more features. {% endif %}

A few more ideas: - Different onboarding tips for users who signed up via “web” vs. “mobile.” - Special offers for users with a “last_purchase_date” over 60 days ago.

3.3. Loops: Dynamic Lists

If you store attributes that are arrays (like a list of recent products), you can loop through them:

liquid {% for item in recent_purchases %} - {{ item.name }} on {{ item.date }} {% endfor %}

But in real life, most people don’t go wild with loops in email. Keep it simple.

3.4. Testing and Previews

Always use Customer.io’s preview and test send features. Plug in real user data when you test—don’t trust the “default” preview. You’ll be surprised how often you catch missing or weird data.


Step 4: Segment and Trigger With Custom Attributes

Custom attributes aren’t just for the email body—they power segmentation and triggers too.

4.1. Segments

Create segments in Customer.io based on attribute values:

  • Users on a free plan vs. paid plan
  • People who haven’t logged in for 30 days
  • Anyone who opted in to a specific newsletter topic

Segments let you target emails more precisely, or trigger automated campaigns.

4.2. Triggered Campaigns

You can start automations or drip campaigns when a custom attribute changes. For example:

  • “plan” changes from “free” to “pro” → send onboarding series for Pro users
  • “last_purchase_date” gets updated → send a feedback request

Watch out for:
Make sure your system reliably updates attributes. If your sync or API integration fails, your triggers won’t fire.


Step 5: Keep It Maintainable (and Sane)

It’s tempting to go overboard with personalization. But more dynamic content = more stuff to break (or confuse your users).

A few lessons the hard way:

  • Limit the number of custom attributes you use in emails. Pick what matters most.
  • Document your attributes. If you have a team, write down what each attribute means and valid values. Otherwise, you’ll end up with “plan_type,” “plan,” and “userPlan” all floating around.
  • Test with edge cases. What happens if a user has no “first_name” or an unexpected value? Build in fallbacks.

What to ignore:
- Don’t bother with attributes you don’t control or update regularly. Stale data leads to embarrassing emails (“Hi , we noticed you...”). - Don’t try to build logic that’s too complex for Liquid templates. If you need multi-step workflows or calculations, handle them before the data hits Customer.io.


Step 6: Real World Examples (What Actually Works)

Here are a few simple, high-impact ways to use custom attributes in Customer.io:

  • Onboarding:
    Personalize emails based on signup source. liquid {% if signup_source == "referral" %} Thanks for joining through a friend! Here’s a bonus... {% endif %}

  • Plan-specific messaging:
    Show Pro tips to paid users, upgrade nudges to others.

  • Win-back campaigns:
    Use “last_login” or “last_purchase_date” to target users who’ve gone quiet.
  • Feature announcements:
    Only show announcements to users with a certain feature flag enabled.

Honestly, most of the value comes from just a handful of attributes. Don’t chase hyper-personalization unless you’ve already nailed the basics.


Summary: Iterate, Don’t Overthink It

Dynamic email content in Customer.io is powerful, but you don’t need every bell and whistle to get results. Start with a few meaningful custom attributes, use them for clear personalization and segmentation, and test as you go. Most importantly, keep things simple—if you’re spending hours debugging a Liquid template, you’re probably trying to do too much. Iterate, learn, and let your emails actually help your users (not just show off your templating skills).