Skip to content

Data retention

Leatsmap does not delete your data automatically. Retention is a policy decision; the platform exposes the mechanism (and a few sensible defaults) but you control the timeline.

TableDefault retentionConfigurable via
eventsForeverOperator SQL / cron
sessionsForeverOperator SQL / cron
user_profilesUntil GDPR deleteAPI call
identity_linksUntil GDPR deleteAPI call
audit_logForever (append-only)Trigger-enforced
dlq30 daysDLQ_RETENTION_DAYS env on collector
quota_counters13 monthsOperator SQL / cron

The platform is designed for analytics — historical trends, year-over-year comparisons, retention curves. A short retention window defeats the use case. If you want short retention, the right move is:

  • Roll up to aggregate tables (v1.1 will add materialized views for this).
  • Periodically DELETE FROM events WHERE ts < NOW() - INTERVAL '13 months'.

A scheduled cron + the standard Postgres DELETE is the v1.0 answer. The platform deliberately does not ship an “event TTL” feature that would silently delete data — it would conflict with operators who do want forever retention.

DLQ rows are pruned by a maintenance job that runs daily inside the collector. It deletes rows where received_at < NOW() - INTERVAL '$DLQ_RETENTION_DAYS days'. The default of 30 is enough to find producer bugs in normal release cadence; tune up if your release cycle is slower.

Audit rows are append-only. There is a database trigger that refuses DELETE and UPDATE against the table. To purge for storage reasons, operators can:

  • Archive: COPY audit_log TO … and rotate to cold storage.
  • Drop and recreate: requires a deliberate migration step and breaks the “append-only” guarantee for that retention period.

The append-only guarantee is what makes the audit log usable as a compliance artifact.

Per-workspace monthly counters. The platform retains 13 months so year-over-year quota math is possible. Older rows can be pruned by an operator cron.

Backups are operator-managed and not coupled to the application. Standard Postgres practice: at least one backup per day, retained for as long as your DPIA / compliance posture requires (often 30–90 days for warm backups, longer for cold).

For operators who want 13-month event retention:

-- Run nightly:
DELETE FROM events
WHERE ts < EXTRACT(EPOCH FROM (NOW() - INTERVAL '13 months')) * 1000;

(Note: events.ts is unix epoch milliseconds, not a TIMESTAMPTZ.)

The events.raw column carries the verbatim wire payload — including any operator-defined custom props. It is the versioning safety net that lets future migrations backfill new typed columns without re-ingesting from the SDK.

If your retention policy is “delete after N months”, the raw column is deleted with the row — the safety net does not change the retention math.

  • GDPR deletes are unconditional — they purge the affected subject immediately, regardless of retention windows. Retention rules are about storage cost and compliance posture; GDPR is about data-subject rights.
  • DLQ replay is unconditional — replaying an entry re-creates a fresh events row (Path A by design; see Validation). If retention has elapsed since the original, the replay’s events row inherits the replay timestamp by default unless you supply event.ts explicitly.