Skip to content

Enterprise

Audit log

What is recorded, how to filter it, and how to export it as CSV or JSON.

Every workspace has an append-only audit log: who did what, when, and from where. Owners and admins read it in Settings → Audit log, export it as CSV or JSON, and agents or scripts can pull it with an API key.

Who can see it

  • Roles: owners and admins. API keys need the audit:read scope.
  • Self-hosted: the licence's audit_export feature grants the whole log (Team and Enterprise editions). Without it, the log is not available.
  • critlab cloud: Enterprise sees the whole log, Team the last 7 days.

These rules limit what can be read, not what is kept; how long events are kept is under Retention.

What is recorded

Each event has a time, an action, the actor (a person, an API key, or the SCIM directory), the subject (a member, prototype, folder…), the request's IP address and user agent, and action-specific details.

AreaActions
Sign-inauth.login, sso.login
Members and invitationsmember.invited, member.invitation_revoked, member.joined, member.role_changed, member.removed, member.folder_granted, member.folder_revoked, member.folder_context_changed
Access requestsaccess.requested, access.approved, access.denied
Prototypes and versionstarget.created, target.access_changed, target.moved, target.status_changed, target.link_comments_changed, target.require_name_changed, target.external_assets_changed, target.site_changed, target.snippet_key_rotated, target.deleted, version.deleted
Foldersfolder.created, folder.renamed, folder.moved, folder.reordered, folder.styled, folder.image_changed, folder.archived, folder.unarchived, folder.deleted, folder.context_added, folder.context_updated, folder.context_removed
Commentscomment.deleted
Single sign-onsso.updated, sso.enabled, sso.disabled, sso.enforcement_changed, sso.provisioned, sso.role_synced, sso.role_sync_skipped, sso.domain_added, sso.domain_verified, sso.domain_failed, sso.domain_removed
Directory syncscim.user_*, scim.group_*, scim.role_synced, scim.role_sync_skipped, scim.token_created, scim.token_revoked
Storagestorage.configured, storage.verified, storage.verification_failed, storage.disconnected
Licence and keyslicense.updated, apikey.created, apikey.revoked
Operator actions (critlab cloud staff)admin.* — recorded in the affected workspace's own log

Tokens, passwords and licence keys are never written to the log.

Filter

In the settings page, or as query parameters on GET /api/workspaces/{id}/audit:

FilterMatches
actorA person, by user id or email
folderA folder by id or path (e.g. Acme/Website), its subfolders and every prototype filed in them
prototypeA prototype by id or slug; a deleted one by id
actionOne action, e.g. member.role_changed
since, untilA time window (ISO 8601)

Filters combine. Pages are cursor-based, so reading while new events arrive never skips or repeats one.

Export

  • CSV: the export button in settings, or ?format=csv.
  • JSON: ?format=json, or from the CLI:
bash
crit audit export --since 2026-09-01T00:00:00Z --folder "Acme/Website" --json

Exports honour every filter.

Retention

Audit events are kept for 13 months, the same for every plan, and then deleted by the retention job, which web runs by itself every hour. Export the log on your own schedule if you need to keep it for longer. A self-hosted install can change the period with RETENTION_AUDIT_MONTHS (0 keeps events forever); see scheduled jobs for how the job runs and how to switch it off.

Operator notes

  • The IP address is the client as your deployment's trust model names it: the entry of X-Forwarded-For that many places from the right as TRUSTED_PROXY_HOPS says (default 1, the last entry, the one your own proxy appended; the entries to its left are whatever the client wrote and are never used), else X-Real-IP when there is no X-Forwarded-For. Set TRUSTED_PROXY_HOPS to the number of proxies of yours in front of the app, each of which must append to X-Forwarded-For rather than replace it (Caddy and ingress-nginx replace by default; see the configuration reference), and TRUST_CF_CONNECTING_IP=1 for a Cloudflare-only origin; without a proxy that sets these headers, events carry no IP address. Reading the source code of a prototype records no address at all for someone who is not a member of the workspace.
  • If writing an event ever fails, the user's action still succeeds and web logs the full event to stderr with console.error. Alert on those lines if the log is part of your compliance evidence; see Health checks, monitoring and logs.