Appearance
Timeline
Audit TrailInvestigation
Builds a chronological log of everything a user or device did within a time window — like a play-by-play activity feed. Each event is recorded with a timestamp and any extra fields you capture.
When to Use
- Abuse investigation: pull a user's timeline to see exactly what happened and in what order
- Compliance audit trails: generate a full record of user activity for regulatory review
- Anomaly investigation: a user flagged by another behavior — what did their session look like?
- Onboarding drop-off analysis: what's the last event users hit before they stop?
Configuration
json
{
"name": "device_activity_timeline_24h",
"operation": "timeline",
"group_by": "device_id",
"fields": ["country_code", "ip_address", "identity"],
"window_duration_seconds": 86400,
"operation_config": {
"max_entries": 50,
"dedupe_consecutive": true
}
}Fields
fields is optional. It specifies additional fields to capture per entry beyond the always-included event_name and event_id. Fields are resolved from the top-level event data first, then fall back to event_properties (e.g., "phone" resolves to event_properties.phone if no top-level phone field exists). Dot notation also works: "event_properties.phone".
Configuration Options
| Option | Default | Description |
|---|---|---|
max_entries | 50 | Maximum entries to retain. Oldest are evicted (FIFO). Summary stats still cover the full window. |
dedupe_consecutive | true | Consecutive events with the same event_name and identical field values are collapsed into a single entry with min_time, max_time, and count. When two events share the same name but differ in any captured field, they are not merged. Set to false for one entry per event. |
Response
| Field | Description |
|---|---|
entries | Array of event snapshots (capped to max_entries, most recent retained) |
entries[].event_name | The name of the event |
entries[].event_id | ID of the first event in a collapsed group |
entries[].min_time | Timestamp of the first event in the entry (when dedupe_consecutive is enabled) |
entries[].max_time | Timestamp of the most recent event in the entry (when dedupe_consecutive is enabled) |
entries[].event_time | Timestamp of the event (when dedupe_consecutive is false) |
entries[].count | Number of consecutive events collapsed into this entry |
summary.count | Total number of events in the window (may exceed entry_count) |
summary.entry_count | Number of entries currently in the timeline |
summary.min_time | Timestamp of the first event in the window |
summary.max_time | Timestamp of the most recent event |
summary.duration_seconds | Time elapsed between first and last event |
summary.events | Per-event-name breakdown with count, min_time, and max_time |
Example (with dedupe_consecutive: true)
In this example, 5 raw events occurred, but the 3 consecutive page_view events were collapsed into a single entry with count: 3:
json
{
"behaviors": {
"device_activity_timeline_24h": {
"entries": [
{
"event_name": "page_view",
"event_id": "a1b2c3",
"min_time": "2025-06-12T14:00:00.000Z",
"max_time": "2025-06-12T14:02:00.000Z",
"count": 3,
"country_code": "US",
"ip_address": "1.2.3.4",
"identity": "wallet_0xabc"
},
{
"event_name": "trade",
"event_id": "d4e5f6",
"min_time": "2025-06-12T14:05:00.000Z",
"max_time": "2025-06-12T14:05:00.000Z",
"count": 1,
"country_code": "US",
"ip_address": "1.2.3.4",
"identity": "wallet_0xabc"
},
{
"event_name": "login",
"event_id": "g7h8i9",
"min_time": "2025-06-12T15:30:00.000Z",
"max_time": "2025-06-12T15:30:00.000Z",
"count": 1,
"country_code": "IR",
"ip_address": "5.6.7.8",
"identity": "wallet_0xabc"
}
],
"summary": {
"count": 5,
"entry_count": 3,
"min_time": "2025-06-12T14:00:00.000Z",
"max_time": "2025-06-12T15:30:00.000Z",
"duration_seconds": 5400,
"events": {
"page_view": {
"count": 3,
"min_time": "2025-06-12T14:00:00.000Z",
"max_time": "2025-06-12T14:02:00.000Z"
},
"trade": {
"count": 1,
"min_time": "2025-06-12T14:05:00.000Z",
"max_time": "2025-06-12T14:05:00.000Z"
},
"login": {
"count": 1,
"min_time": "2025-06-12T15:30:00.000Z",
"max_time": "2025-06-12T15:30:00.000Z"
}
}
},
"timestamp": "2025-06-12T14:00:00.000Z",
"remaining_window_seconds": 81000
}
}
}Deduplication
When dedupe_consecutive is enabled (default), consecutive events with the same event_name and identical captured field values are merged into a single entry. This dramatically reduces timeline size for repetitive actions like polling, page reloads, or heartbeat events — while preserving the full event count in summary.count. If a field value changes (e.g., country switches from US to IR), a new entry is created even if the event_name is the same.
Summary vs Entries
When summary.count exceeds summary.entry_count, it means older entries were evicted from the timeline but the summary stats (including per-event breakdowns in summary.events and duration_seconds) still reflect the full window of activity.