Skip to content

Add event deduplication via id and timestamp params#125

Merged
hownowstephen merged 5 commits intomainfrom
event-deduplication
May 9, 2026
Merged

Add event deduplication via id and timestamp params#125
hownowstephen merged 5 commits intomainfrom
event-deduplication

Conversation

@hownowstephen
Copy link
Copy Markdown
Contributor

@hownowstephen hownowstephen commented May 8, 2026

Summary

  • Change track() and track_anonymous() to accept a data dict instead of **kwargs
  • Add optional id parameter (ULID) for event deduplication
  • Add optional timestamp parameter (epoch seconds) for explicit event timing
  • Invalid timestamps silently dropped; data=None sends empty data dict

This is a breaking change — callers must switch from keyword arguments to a dict for event data attributes:

# Before
cio.track(5, "purchase", type="socks", price="13.99")

# After
cio.track(5, "purchase", {"type": "socks", "price": "13.99"})
cio.track(5, "purchase", {"type": "socks"}, id="01HB4HBDKTFWYZCK01DMRSWRFD")
cio.track(5, "purchase", {"type": "socks"}, id="01HB4HBDKTFWYZCK01DMRSWRFD", timestamp=1561231234)

Mirrors the approach taken in customerio/customerio-ruby#136. Refs #98.

Test plan

  • All 44 tests pass (7 new)
  • id present in request body when provided, absent when not
  • id absent when not provided
  • timestamp set as top-level field when provided
  • Invalid timestamps silently omitted
  • track() with no data sends empty data dict
  • track_anonymous() with id and timestamp

Note

Medium Risk
This is a breaking API change to the public track()/track_anonymous() signatures that will raise TypeError for existing keyword-attribute callers. It also changes event payload shape by introducing optional top-level id and timestamp, which could affect downstream deduplication/timing behavior if misused.

Overview
Adds support for optional top-level event id (for deduplication) and timestamp on CustomerIO.track() and CustomerIO.track_anonymous().

Breaking change: both methods now require custom event attributes to be passed via a data dict (instead of arbitrary **kwargs), defaulting to {} when omitted; invalid timestamp values are silently dropped.

Updates the README/CHANGELOG and expands tests to enforce the new call signatures and validate request bodies for data, id, and timestamp.

Reviewed by Cursor Bugbot for commit e575fbe. Bugbot is set up for automated code reviews on this repo. Configure here.

Change track() and track_anonymous() to accept a data dict instead of
**kwargs, with optional id and timestamp keyword arguments.

The id parameter accepts a ULID for event deduplication. The timestamp
parameter sets the event time (epoch seconds). Invalid timestamps are
silently dropped. Passing data=None sends an empty data dict.

This is a breaking change: callers must switch from keyword arguments
to a dict for event data attributes.

Refs #98
Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 4efee3b. Configure here.

Comment thread customerio/track.py Outdated
@hownowstephen hownowstephen merged commit 756980d into main May 9, 2026
10 checks passed
@hownowstephen hownowstephen deleted the event-deduplication branch May 9, 2026 02:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants