@devxcommerce/strapi-plugin-audit-log
v1.2.0
Published
End-to-end admin-panel activity audit log (content, media, settings, auth) with an admin UI
Readme
@devxcommerce/strapi-plugin-audit-log
Records end-to-end admin-panel activity for Strapi 5 and exposes an Audit Logs UI (main nav) showing who did what — content changes, settings changes, media, and logins.
Install
bun add @devxcommerce/strapi-plugin-audit-log
# or: npm install @devxcommerce/strapi-plugin-audit-logEnable it in config/plugins.ts:
export default ({ env }) => ({
'audit-log': { enabled: true },
// …other plugins
});Mount the settings/auth/media capture middleware in config/middlewares.ts — before strapi::errors so failed logins are still recorded:
export default [
'strapi::logger',
'plugin::audit-log.audit-http',
'strapi::errors',
// …rest of the default stack
];That's it — the content-change capture, RBAC permission, DB indexes, and retention cron register automatically on boot.
What it captures
| Category | Source | Events |
|---|---|---|
| content | Document-service middleware (all content types) | entry.create / update / delete / publish / unpublish |
| settings | Global admin-route middleware | roles, permissions, admin users, API/transfer tokens, webhooks, SSO |
| media | Global admin-route middleware | uploads, edits, deletes |
| auth | Global admin-route middleware | login (success and failure), logout, password reset |
Each entry stores the acting admin (snapshot), action, a human-readable target label, the sanitized payload, IP, and request id. Deletes also store a snapshot of what was removed.
Architecture
server/capture/document-capture.ts— semantic content capture viastrapi.documents.use.server/middlewares/audit-http.ts— settings/auth/media via admin-route interception (mounted beforestrapi::errorsinconfig/middlewares.ts, so failed logins are recorded). Deliberately skips/content-manager/*(handled by the document middleware) to avoid double-logging.server/services/recorder.ts— single write path; recursively redacts secrets/passwords/tokens, then size-caps the blob; writes via the query engine (bypasses the document middleware → no feedback loop); fail-open (an audit error never breaks the admin action).server/content-types/audit-log— hidden, append-onlyaudit_logstable.admin/— the read-only UI (filter by search/category/status/user/action/date, paginated, CSV export, per-row details with a field diff).
Configuration
All config is optional and set under config/plugins.ts → 'audit-log': { config: { … } }:
| Option | Default | Purpose |
|---|---|---|
| retentionDays | 90 | Daily 03:00 cron prunes entries older than this (batched delete). |
| maxPayloadBytes | 16384 | Cap on a stored payload blob; larger is truncated with a marker. |
| capture | all true | Per-category switch: { content, media, settings, auth }. |
| contentActions | all | Which content actions to record (create/update/delete/publish/unpublish). |
| excludeContentTypes | [] | Content-type UIDs to skip entirely (e.g. high-churn singletons). |
| sensitiveKeys | [] | Extra key names to redact, on top of the built-in secret list. |
- The legacy
AUDIT_LOG_RETENTION_DAYSenv var still works but is deprecated — preferconfig.retentionDays. - Access is gated by the
plugin::audit-log.readRBAC permission (Super Admin by default; grantable per role in Settings → Roles).
Not a tamper-proof ledger
This is an activity log, not a forensic audit trail: the audit_logs table is hidden from the Content Manager but is not cryptographically tamper-evident. Read operations are intentionally not logged. For compliance-grade immutability (hash-chaining / write-only storage), treat that as a bespoke add-on.
Requirements
- Strapi
^5 - Node
>=20 <=24
See examples/ for ready-to-copy config/plugins.ts and config/middlewares.ts snippets.
Links
License
MIT
