Updated · 7 min read
Custom attributes: the data design that determines what your program can do
Every lifecycle program accumulates custom attributes — custom_plan, last_purchase_date, subscription_tier, preferred_category. Over time, programs accrete dozens or hundreds of them. Some are used daily; most are stale remnants of campaigns that shipped once and never again. The resulting mess is the single most common reason 'can we segment on X?' becomes a multi-week engineering project instead of a 15-minute one. Here's the design discipline that prevents it.
Justin Williames
Founder, Orbit · 10+ years in lifecycle marketing
The attribute design principles
Custom attributes are infrastructure. Badly named or badly maintained attributes produce segmentation that's unreliable, personalisation that fires on the wrong users, and engineering queues full of "can we fix this attribute" tickets.
Three principles that prevent the mess:
1. Attributes are derived data, not raw data. Don't create an attribute for every column in your data warehouse. Create attributes for the specific segmentation and personalisation decisions the lifecycle program needs to make. "User_is_premium_tier" is useful; "User_plan_internal_id" is clutter.
2. Every attribute has a defined update path. How does this attribute get set? How does it get updated? Who owns it? Attributes without a maintenance plan become stale silently.
3. Retire aggressively. An attribute with no active campaigns using it is clutter. Audit quarterly; remove unused attributes. The cost of having them around isn't zero — they confuse future teammates and bloat the data model.
The naming convention
Without a naming convention, attributes become a free-text mess. Convention that works for most programs:
[domain]_[entity]_[property]_[aggregation]
Examples:
• subscription_plan_tier — user's current subscription tier
• commerce_order_count_lifetime — total orders ever
• commerce_order_count_90d — orders in last 90 days
• engagement_email_open_count_30d — email opens in last 30 days
• preference_category_primary — user's top category
The prefix groups related attributes together in ESP dropdowns. The aggregation suffix ("_lifetime", "_90d", "_count") makes the data shape immediately clear. See the Braze naming conventions guide for the broader naming framework this fits into.
Attribute tiers
Not every attribute is equally important. Organise into tiers with different maintenance standards:
Tier 1: Core attributes. Used across many campaigns, updated frequently, central to segmentation. e.g., subscription_tier, lifetime_order_count, last_engagement_date. These need reliable update pipelines and continuous monitoring.
Tier 2: Program-specific attributes. Used by one or two specific programs. e.g., birthday_month (for birthday emails), preferred_frequency (for frequency management). Owned by the specific program; retired when that program retires.
Tier 3: Computed or temporary attributes. Derived at send time or used for a one-off campaign. Often better handled via Liquid or segment logic at send time rather than persisted attributes.
,
Data freshness and pipeline ownership
Every attribute needs a defined update mechanism:
Real-time (event-driven). Updated when a user action occurs. Fast but requires event pipelines. Best for attributes that drive immediate triggers ("user_is_in_cart").
Batch (nightly or hourly). Computed from data warehouse and pushed to ESP on a schedule. Acceptable lag for most segmentation ("lifetime_order_count", "preferred_category"). Requires reverse-ETL or similar pipeline.
Send-time (computed via Liquid or similar). Computed when the email sends, not stored. Most flexible but requires catalogue / data availability at send time.
Document which mechanism each attribute uses. When an attribute appears to be wrong, the first question is "when was it last updated, by which pipeline". Programs without this documentation spend hours on these debug sessions.
Common failure modes
Stale attributes. An attribute that was useful in 2024 no longer updates. Campaigns still filter on it; results are wrong. Fix: quarterly audit of active attributes, confirmation that update pipelines are running.
Multiple sources of truth. Two attributes tracking the same thing (e.g., "subscription_status" and "is_subscriber"), updated by different pipelines, disagreeing. Fix: designate one as source of truth; remove or compute the other.
Attribute sprawl. 300+ attributes, most unused, nobody knows which ones matter. Fix: audit and retire; establish a creation-approval process.
Privacy-sensitive data over-stored. Detailed personal data (full birthdate, address, income) stored when only a derived attribute (age_bracket, city, plan_tier) is needed. Fix: store the minimum needed for lifecycle; keep raw data in the warehouse where privacy controls are stronger.
treats attribute hygiene as part of quarterly program audit. Most programs discover 20–40% of their attributes are stale or duplicated once they actually audit.
Frequently asked questions
- How many custom attributes should I have?
- As few as enable the lifecycle decisions you need to make. Most programs operate comfortably with 30–80 active attributes; programs with 200+ are usually in sprawl territory. The number is less important than the attribute-to-usage ratio — every attribute should have at least one active campaign or segment using it.
- Should I create an attribute for every column in my data warehouse?
- No — the warehouse is the source of truth; the ESP holds derived attributes for lifecycle decisions. Reverse-ETL copying every column creates attribute sprawl and obscures what's actually used. Copy the specific attributes lifecycle needs; leave the rest in the warehouse.
- What's the right refresh cadence for attributes?
- Depends on use case. Trigger-relevant attributes (cart status, subscription status) need real-time. Segmentation attributes (order count, engagement recency) need daily or hourly. Demographic attributes (country, birthday) can refresh weekly. Over-refreshing wastes pipeline resources; under-refreshing causes wrong sends.
- How do I retire an attribute safely?
- Three-step: (1) audit all campaigns and segments referencing the attribute; (2) remove or redirect those references; (3) after 30 days of no usage, delete the attribute. Removing the attribute before cleaning up references breaks campaigns. Don't skip step 1.
- Should I use camelCase or snake_case for attribute names?
- snake_case is conventional in most ESPs and reads more consistently in templates and queries. Pick one convention and stick to it across the entire program. Mixing conventions (some_attribute and otherAttribute) is a recipe for bugs when authors misremember which format applies.
- What's the difference between a custom attribute and an event?
- Attribute = state (e.g., current subscription tier). Event = occurrence (e.g., user clicked a specific CTA). Use attributes for 'what is the user's current state'; use events for 'did the user do X at time Y'. Most segmentation questions require both — an attribute for current state and an event-based filter for recent behaviour.
Related guides
Browse all →Email dark mode: the four render modes and how to not break any of them
Dark mode in email isn't one thing — it's four different render behaviours depending on the client. Design without knowing which mode you're hitting and your emails will look broken to 40% of your audience. Here's what each client does.
Mobile email design: 65% of opens are on a phone — design for that
Two-thirds of email is opened on mobile. Most email designs still start with a desktop layout and hope it collapses well. Here's the mobile-first rules that reliably produce emails that read, click, and convert on a phone.
Transactional email anatomy: the five sections every transactional needs
Transactional emails get opened at 3–5× the rate of marketing and carry more brand signal per send. Most programs treat them as ops artefacts and miss the leverage. Here's the five-section template that works for every transactional type.
Preheader text: the second subject line most programs ignore
Preheader text is the snippet shown next to the subject line in the inbox preview. Done well, it doubles your hook. Done badly, it says 'View this email in your browser'. Here's how to write preheaders that earn the open.
Email accessibility: the seven rules that make your emails readable by everyone
Email accessibility isn't a compliance tax — it's the difference between reaching 100% of your audience and the 85% who have easy sight, steady hands, and full-volume screens. Here are the seven rules that cover 90% of what actually matters.
Brand voice in lifecycle: how to sound like you — not the generic SaaS CRM voice
Lifecycle emails drift toward a generic 'polished SaaS CRM voice' because it's the default pattern in every template library and every agency deliverable. Here's how to actually write in your brand's voice across an entire lifecycle program.
Found this useful? Share it with your team.