Activity

The audit trail, what it records, what is redacted, how long it is kept, and the two trails behind one store.

Activity

Settings → Activity is the organization's own read view over the audit trail: who did what, when, and to what, inside this organization.

A standalone system, one-directional

The audit trail is not a table in the product database. It is a separate system (activity-ingestor, activity-api, its own PostgreSQL, its own Kafka topic) that the backend writes to through an outbox and never reads from. That boundary is what lets an audit outage never surface as a failure in the rest of the product: a state-changing request commits its business change and queues an audit event in the same local transaction, and the event reaches the store asynchronously from there.

What gets recorded

Four tiers, not a curated subset:

TierExamples
Organization actionsmember.invited, member.role_changed, monitor.created, service_account.created, api_key.revoked
Auth and identitylogin, login_failed, logout, mfa_enabled, password_changed (ingested from Zitadel's own event log, not the backend)
Platform actionsAnything the up0 platform team does that touches your organization (a suspension, a support data access); visible here for transparency
Sensitive readsViewing or exporting this very activity list is itself recorded

Every event carries who (actor_type, actor_id), what happened (category, action), what it touched (target_type, target_id), when, and whether it succeeded. Filter by any of these plus a free-text search over the event's own metadata, then export to JSONL or CSV. Exporting is itself audited as a data-access event.

The Activity filter panel and export controls

No history before auditing began for your organization

The trail cannot be backfilled. An empty result for a period before this system existed for your organization means nothing was captured then, not that something was captured and lost.

The two trails

One append-only store, two scoped read paths: your organization sees only its own events (visibility = org); the up0 platform team's separate view is a strict superset covering every organization plus platform-only actions. When a platform action targets your organization specifically and you are entitled to know about it (support reading your data, a suspension), it appears in your trail too, for transparency.

What is redacted

Secrets (tokens, passwords, API keys) are stripped before an event ever leaves the backend, and the ingestor separately rejects (to a dead-letter queue) any event whose payload still matches a secret-shaped pattern. Identifiers (UUIDs like event_id, org_id, actor_id) are explicitly exempted from that redaction rule, so an event stays traceable without exposing what it should not.

Retention

Retention is enforced by dropping whole months of data at a time (a metadata-only operation, not a row-by-row scan), on a schedule that is longer for higher-tier plans. Export your own copy before a retention window closes if you need to keep it longer than that.

Owner-only, and why

Reading /settings/activity requires the Owner role. Authorization comes from a short-lived (five-minute) claim the backend mints for the caller, not from anything encoded in the Zitadel login token itself: a real access token from this deployment's Zitadel was verified to carry no organization or role claim at all, so the backend has to vouch for "this caller is the Owner of this org" separately, for every read.

Not deployed on this walk's cluster

This page was walked on the local kind cluster, where the audit-trail services (activity-api, activity-ingestor, their own PostgreSQL and Kafka topic) are not part of the deployed set; kind runs the up0 umbrella chart's product services only. The page itself renders correctly and the filter and export controls work; the events panel stays in its loading state because there is no activity-api to answer it, which is an environment gap rather than a product one. docs/v2/testing/m18-audit-trail.md records the dedicated audit-trail/docker-compose.yml stack this system needs, and its 22 test cases are what a fully wired environment is checked against.

On this page