What are Attributes?
Attributes are facts that describe who a user is, what device they’re on, or what happened in an event. Think of them as the labels on a record — name, email, plan type, device model, event revenue. While events are verbs (actions), attributes are adjectives (descriptions).The Simple Definition
If you can describe it as “This user IS X” or “This event HAS property Y,” it’s an attribute. Examples:- “Sarah’s email is sarah@example.com” → User attribute:
email - “John’s plan type is Enterprise” → User attribute:
plan_type - “This device is an iPhone 15 Pro on iOS 17” → Device attribute:
model,os_version - “This purchase had revenue of $89.99” → Event property:
revenue
Why Attributes Matter
Attributes are essential because they enable:- Personalization: “Hi , your trial expires in days”
- Targeting: Send campaigns only to users matching specific criteria
- Context: Understand who’s behind each event (“This purchase was from an Enterprise customer”)
- Enrichment: Connect user data from your CRM, support system, or other tools
- Current state queries: “How many Pro plan users do we have right now?”
The Key Difference: State vs Action
Attributes store current state (one value that changes over time):- User’s current email:
sarah@example.com→ changes if they update it - User’s current plan:
pro→ changes when they upgrade toenterprise - Last login date:
2026-05-04→ updates every time they log in
- Event:
Updated Emailat2026-01-15→ never changes, always part of history - Event:
Upgraded Planat2026-03-20→ permanent record of this action - Event:
Logged Inat2026-05-04 10:30:15→ specific moment captured
Real-World Example
Sarah’s user attributes:- Attributes show her current state: She’s enterprise now (not pro)
- Events show her complete history: We can see she upgraded on March 20th
- Together they give the full picture: Who she is + What she’s done
Attributes vs Events: The Data Modeling Decision
Events = Actions (verbs) →user.track('Upgraded Plan')Attributes = State (adjectives) →
user.plan_type = 'enterprise'
The Rule
Use attributes when:- You need current state: “What plan are they on right now?”
- You need to personalize: “Hi , your trial ends ”
- It’s a fact about the user: Demographics, account info, preferences
- You need to trigger workflows: “When user upgrades → send thank-you email”
- You need analytics: “How many users upgraded this month?”
- You need history: “When did they last log in?”
- It’s an action: Clicked, viewed, purchased, upgraded
Common Mistake: Tracking State as Events
❌ Wrong:Three Types of Attributes
1. User Attributes
User attributes are facts stored on the user profile, identified byuser_id. They come in two kinds: system-defined fields (always present, set by the platform) and traits (custom key-value data you send via identify() or setProfileAttributes()).
System-Defined Fields
These fields exist on every user profile automatically:| Field | Description |
|---|---|
id | Internal Sonyflake BIGINT primary key |
user_id | Your application’s identifier for this user |
anonymous_id | The anonymous ID before identification |
name | From traits |
email | From traits |
phone | From traits |
timezone | IANA timezone, e.g. America/New_York |
language | ISO 639-1 code, e.g. en |
email_opt_out | Channel opt-out status (1=not opted out, 2=opted out, 3=unknown) |
sms_opt_out | Same 3-state model |
whatsapp_opt_out | Same 3-state model |
rcs_opt_out | Same 3-state model |
push_opt_out | Same 3-state model |
*_opt_out_at | Timestamp when each opt-out occurred |
first_seen_at | Timestamp of first identify call |
last_seen_at | Timestamp of most recent identify call |
last_activity_at | Timestamp of most recent event |
is_deleted | Set to true by User Deleted lifecycle event |
is_suppressed | Set to true by User Suppressed lifecycle event |
deleted_at / suppressed_at | When those states were applied |
first_campaign_source/medium/name/term/content | First-touch UTM attribution |
first_referrer | Referring URL from first visit |
signup_platform | Platform at time of first identify |
creation_source | How the profile was created |
external_id | Optional external system identifier |
customer_created_at | User’s creation time in your own system |
created_at / updated_at / processed_at | System timestamps |
Traits (Custom Attributes)
Anything you pass intraits via identify() or via setProfileAttributes() is stored as a custom trait and merged with existing data:
2. Device Attributes
Device attributes are facts stored on a device record, identified bydevice_id (derived from the push token). Like user attributes, they split into system-defined fields and custom traits.
System-Defined Fields
| Field | Description |
|---|---|
device_id | Internal device ID (derived from token hash) |
token | Push token (FCM/APNs) |
platform | ios or android |
manufacturer | e.g. Apple, Samsung |
model | e.g. iPhone 15 Pro, Pixel 8 |
os_name | e.g. iOS, Android |
os_version | e.g. 17.4.1, 14 |
app_version | Your app’s version string |
sdk_version | Zixflow SDK version |
screen_width / screen_height / screen_density | Display info |
locale | e.g. en-US |
timezone | IANA timezone |
carrier | Mobile carrier name |
active | false after Device Deleted lifecycle event |
push_enabled | Whether the device can receive push |
last_used_at | Last time SDK sent an event from this device |
created_at / updated_at / processed_at | System timestamps |
Traits (Custom Attributes)
Custom key-value data you attach to a specific device:- Target specific app versions: “Send ‘Update Available’ push to devices on v1.x”
- Platform-specific campaigns: “iOS-only feature announcement”
- Notification category filtering
3. Event Properties
Event properties are the custom key-value pairs attached to individual events. Unlike user or device attributes (which describe current state), event properties are immutable — they record the details of a specific moment in time.Anatomy of an Event with Properties
System-Defined Event Fields
Every event has these fields set automatically:| Field | Description |
|---|---|
event_name | The name you pass to track() / screen() / page() |
event_type | Integer: 1=track, 2=screen, 3=page, 4=identify |
user_id | Set if user is identified |
anonymous_id | Set if user is anonymous |
timestamp | When the event occurred (millisecond precision) |
context | Platform, device, OS, app version, locale, timezone — captured by SDK |
workspace_id | Your workspace |
Custom Properties
Theproperties object is fully custom — you define the keys and values:
profile_events, device_logs, profile_identify_events) with separate retention policies — not in the user profile.
Automatic Attribute Discovery
Zixflow automatically learns what attributes exist based on the data you send - no need to define a schema upfront.How It Works
You track an event with properties:- Discovers all the property names (order_id, product_name, revenue, etc.)
- Figures out their data types (order_id is text, revenue is a number)
- Makes them available for querying and filtering
- Segment: “Users who purchased where product_name = ‘Enterprise Plan’”
- Analyze: “Top 10 products by revenue”
- Filter: “Show events where payment_method = ‘credit_card’”
✅ Self-documenting — See what attributes you’re actually using
✅ Type checking — Zixflow warns if data types don’t match
✅ Easy filtering — All attributes available for querying
Reserved Attribute Names
These attribute names are reserved for system use. Don’t use them as custom attributes: User-level:id,workspace_id,user_id,email,anonymous_idcreated_at,updated_at,last_seen_at
device_id,device_token,platform,last_seen_at
- System logs a warning
- Value is ignored (not written)
- Original system value preserved
Next: Understand how events flow through Zixflow → The Data Journey