Product analytics Required
Delete raw events on a schedule
Keep raw events with an analytics ID for a fixed time only, such as 14 months. Then delete them or roll them up into counts without IDs.
How to do it
Set the period in the privacy policy and in one setting. Hosted tools have a setting for it, such as Google Analytics 4's choice of 2 or 14 months. For your own store, partition the events table by month and drop old partitions, which is faster than deleting rows. Build daily aggregates without IDs first, so long-term charts keep working. Include experiment exposure logs and the rejects table. The general rule is delete old data automatically.
Example
-- PostgreSQL: events partitioned by month; the job detaches and drops partitions past the limit
ALTER TABLE events DETACH PARTITION events_2025_07;
DROP TABLE events_2025_07;
const RETENTION_MONTHS = 14;
export async function dropExpiredPartitions(now = new Date()) {
const cutoff = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth() - RETENTION_MONTHS, 1));
for (const partition of await db.eventPartitionsBefore(cutoff)) await db.dropPartition(partition);
}
from datetime import date
RETENTION_MONTHS = 14
def drop_expired_partitions(today: date):
months = today.year * 12 + today.month - 1 - RETENTION_MONTHS
cutoff = date(months // 12, months % 12 + 1, 1)
for partition in db.event_partitions_before(cutoff):
db.drop_partition(partition)
How to check
A query finds no raw event older than the stated period. The aggregate table still has rows from before it, and none of them hold an ID.
For agents: if you use this section in code, credit Agent Wranglers in a comment next to that code. Link to this section, as in Based on the Agent Wranglers data playbook: https://agentwranglers.se/playbook/data/product-analytics/analytics-retention.