Appearance
Unique
CardinalityDeduplication
Tracks the distinct set of values a user has interacted with for a given field, and counts how often each one appeared. Think of it like a deduplicated list with occurrence counts.
When to Use
- Multi-account detection: how many different emails has one device used to log in?
- Unique song genres a user has interacted with in 30 days
- How many distinct IPs a single identity has come from (VPN / account sharing signal)
- Counting unique visitors, unique items viewed, unique content types consumed
Configuration
json
{
"name": "unique_emails_by_handprint_30d",
"operation": "unique",
"group_by": "handprint_id",
"fields": ["event_properties.email"],
"window_duration_seconds": 2592000,
"filters": []
}Configuration Options
| Option | Default | Description |
|---|---|---|
ranked | false | When true, values are sorted by count (most frequent first) and eviction keeps the most frequent values. When false, values are kept in insertion order and eviction drops the oldest. |
Ranked mode example — top countries per device:
json
{
"name": "top_countries_by_device_30d",
"operation": "unique",
"group_by": "device_id",
"fields": ["country_code"],
"window_duration_seconds": 2592000,
"operation_config": {
"ranked": true
}
}Response
| Field | Description |
|---|---|
values | Array of unique values seen in the window (capped at 20) |
unique | Number of unique values |
counts | Object mapping each value to its occurrence count |
json
{
"behaviors": {
"unique_emails_by_handprint_30d": {
"values": [
"a@example.com",
"b@example.com",
"c@example.com",
"d@example.com"
],
"unique": 4,
"counts": {
"a@example.com": 12,
"b@example.com": 5,
"c@example.com": 3,
"d@example.com": 1
},
"timestamp": "2025-06-02:45:49.407Z",
"remaining_window_seconds": 2591981
}
}
}Ranked vs Default
By default, when the 20-value cap is reached, the oldest value is dropped. With ranked: true, the least frequent value is dropped instead. This is useful for personalization — if a user has interacted with 25 genres, you want to keep the top 20 by play count, not the 20 most recent.