Skip to content

Sum

AggregationNumeric

Accumulates a numeric field value within a time window. Returns the running total along with count, average, min, and max. Optionally partitions the sum by another field for per-item breakdowns.

When to Use

  • Total play duration per user over 30 days
  • Cumulative spend or transaction amounts
  • Aggregated scores, ratings, or quantities
  • Per-item breakdowns: total play time broken down per song

Simple Sum

json
{
  "name": "total_play_duration_by_identity_30d",
  "operation": "sum",
  "group_by": "identity",
  "fields": ["event_properties.playDuration"],
  "window_duration_seconds": 2592000,
  "filters": {
    "field": "event_name",
    "operator": "equals",
    "value": "PauseSong"
  }
}

fields: The first entry is the dot-notation path to the numeric field to accumulate. Events where this field is absent or non-numeric are skipped.

Response

json
{
  "behaviors": {
    "total_play_duration_by_identity_30d": {
      "sum": 2340,
      "count": 18,
      "average": 130,
      "min": 12,
      "max": 480,
      "timestamp": "2025-06-01T09:00:00.000Z",
      "remaining_window_seconds": 2590200
    }
  }
}

Partitioned Sum

Add partition_by to break the total down by another field — for example, total play time per song for a given user. Results are sorted by sum descending.

json
{
  "name": "play_time_by_song_30d",
  "operation": "sum",
  "group_by": "identity",
  "fields": ["event_properties.playDuration"],
  "window_duration_seconds": 2592000,
  "filters": {
    "field": "event_name",
    "operator": "equals",
    "value": "PauseSong"
  },
  "operation_config": {
    "partition_by": "event_properties.songId",
    "n": 20,
    "evict_on": ["DislikeSong"]
  }
}

Configuration Options

OptionTypeDefaultDescription
partition_bystringDot-notation path to the partition field. When set, response includes a by_partition map sorted by sum descending
nnumberallLimits response to top N partitions by sum. All partitions are still tracked internally
evict_onstring[]Event names that hard-delete a partition from tracking. The partition's accumulated sum and count are subtracted from totals

Response (partitioned)

FieldDescription
total_sumGrand total across all partitions
total_countTotal events processed across all partitions
total_averagetotal_sum / total_count
valuesPartition keys sorted by sum descending (capped to n if set)
by_partitionPer-partition stats: sum, count, average, min, max
rejectedNumber of partitions removed via evict_on events
json
{
  "behaviors": {
    "play_time_by_song_30d": {
      "total_sum": 4820,
      "total_count": 31,
      "total_average": 155.5,
      "values": ["song_789", "song_456", "song_123"],
      "by_partition": {
        "song_789": {
          "sum": 2400,
          "count": 12,
          "average": 200,
          "min": 90,
          "max": 480
        },
        "song_456": {
          "sum": 1540,
          "count": 11,
          "average": 140,
          "min": 60,
          "max": 300
        },
        "song_123": {
          "sum": 880,
          "count": 8,
          "average": 110,
          "min": 30,
          "max": 240
        }
      },
      "rejected": 1,
      "timestamp": "2025-06-01T09:00:00.000Z",
      "remaining_window_seconds": 2589600
    }
  }
}

Use Case: Most-Listened Songs

A music streaming platform wants to know which songs each user has spent the most time listening to — powering a "Your Top Songs" feature and feeding data into a recommendation model.

Each time the user pauses or completes a track, the client sends a PauseSong event:

js
honeypot.track('PauseSong', {
  songId: 'song_789',
  playDuration: 240, // seconds listened this session
});
json
{
  "name": "top_songs_by_play_time_30d",
  "operation": "sum",
  "group_by": "identity",
  "fields": ["event_properties.playDuration"],
  "window_duration_seconds": 2592000,
  "filters": {
    "field": "event_name",
    "operator": "equals",
    "value": "PauseSong"
  },
  "operation_config": {
    "partition_by": "event_properties.songId",
    "n": 20,
    "evict_on": ["DislikeSong"]
  }
}

After several sessions:

json
{
  "behaviors": {
    "top_songs_by_play_time_30d": {
      "total_sum": 7200,
      "total_count": 42,
      "total_average": 171.4,
      "values": ["song_789", "song_456", "song_123"],
      "by_partition": {
        "song_789": {
          "sum": 3600,
          "count": 18,
          "average": 200,
          "min": 60,
          "max": 480
        },
        "song_456": {
          "sum": 2100,
          "count": 14,
          "average": 150,
          "min": 30,
          "max": 360
        },
        "song_123": {
          "sum": 1500,
          "count": 10,
          "average": 150,
          "min": 90,
          "max": 240
        }
      },
      "rejected": 2
    }
  }
}

Reading the output:

  • song_789 is the user's most-listened track with 3,600 seconds (1 hour) across 18 sessions
  • rejected: 2 means the user disliked 2 songs — permanently removed from the leaderboard
  • The values array feeds directly into a recommendation engine

sum vs top_n with sum_by — which to use?

Both can accumulate play duration per song. The difference is scope:

  • sum with partition_by: Best when the song (partition) is the primary axis and you want totals across users
  • top_n with sum_by: Best when the user is the primary axis and you want each user's personal top songs ranked by listening time

Use top_n + sum_by for per-user personalization. Use sum + partition_by for aggregate totals across a population.

Use min/max for anomaly detection

The min and max fields per partition reveal listening patterns. A song with max: 480 (8 minutes) but average: 30 suggests the user usually skips it — except once when they let it run. Useful for identifying background listening vs. intentional plays.