Investigate activity in the audit log
Choose Admin → Audit log in the dashboard bar, or visit /dashboard/audit. You need audit.read; Administrator includes it. If audit.read is your only administration permission, Audit log sits in the bar by itself instead of in the Admin menu. The log brings recorded application activity into one view, with the time, actor, action, outcome, target, and available request or change details. It is useful for answering “who deleted this file?”, “why did processing fail?”, or “which account changed that role?”.
The viewer resets its filters and displayed events when you switch accounts or sign in with a new browser session. When the tab detects sign-out or loss of audit.read, it clears the previous viewer; a refresh rejected for either reason also clears the loaded events. Sign in with an authorized account before reopening the log. These checks do not remove events from the instance’s history.
Find an event
- Open Admin → Audit log. The newest events appear first.
- Start with an investigation preset, or search for an actor name, action, filename, target ID, or request ID. Presets apply immediately; All activity is the starting view and still includes request events.
- Choose Category, Action, and Outcome as needed. Time range defaults to All time, with Last 24 hours, Last 7 days, Last 30 days, and Custom range options. Custom From and To use your browser’s local time; event details also show Timestamp (UTC).
- Expand Filter by actor, target, or request ID when you know an exact identifier. Choose Apply filters, then Previous / Next for older matches. Each page shows up to 50 events. Refresh reloads the currently applied filters.
- Select an event row to expand Recorded details, available request context, and Actor ID, Target ID, and Request ID. Select one of those IDs to apply its exact filter immediately; the other applied filters remain in place.
- Choose Clear filters to return to all instance activity. Manual filter edits remain drafts until Apply filters or a preset is chosen; refreshing uses the applied choices. A message marks unapplied edits, and the activity panel lists the filters it is actually displaying.
Start an investigation
| Preset | Applied criteria |
|---|---|
| All activity | Clears category, action, and outcome. Request events remain included. |
| Failed activity | Outcome failure, across categories and actions. Denied requests are a separate outcome: select Denied under Outcome to investigate access refusals. |
| Sign-ins | Category authentication and action auth.login, with all outcomes. Includes the login attempts Flare recorded, not every operation performed by an identity provider. |
| Account changes | Category accounts, with all actions and outcomes in that category. Authentication, roles, and invitations have their own categories. |
| Requests | Category requests, with all actions and outcomes in that category. This isolates recorded HTTP request outcomes; it is not a complete infrastructure access log. |
Choosing a preset applies your current search, time range, and exact actor/target/request IDs as well; it replaces only category, action, and outcome. The highlighted preset follows the applied criteria, rather than unapplied edits. All activity therefore keeps the rest of an investigation’s scope; Clear filters is the explicit way to clear everything. If a preset has no matches, widen or clear the retained scope. Existing audit events and retention rules are unchanged.
Request events use a compact row: method and path, actor, and local time share one line on a wider screen; actor and time wrap below the request on a phone. Select the row to inspect the full request, exact IDs, and recorded context. Successful events use a quieter presentation without a repeated success badge. Failure and Denied remain visible badges, and every expanded event names its Outcome. The Outcome filter still distinguishes all three results.
File snapshots in Recorded details use the database file-size unit: size is in MiB (1,048,576 bytes), so a small text file can have a fractional value. Timestamps in expanded details are UTC; row times use your browser’s locale.
For recorded database changes, after snapshots use the values returned by that write, so a later concurrent edit is not substituted into the earlier actor’s event. beforeObserved: true marks a before snapshot gathered as pre-write context; it is not a guaranteed immediately preceding version when operations race. changedFields identifies submitted mutation fields, while differences between observed snapshots can also include concurrent changes. Deletion snapshots instead describe rows actually removed; some bulk operations expose only counts without per-record snapshots. Snapshots contain selected fields rather than a complete revision history, and missing fields should not be inferred from the object’s current state.
A successful event describes the recorded application step. It is not proof that every later asynchronous step finished: an uploaded file can have a successful creation followed by a failed OCR or cleanup event. A denied request means Flare rejected that request; it does not prove the actor obtained the content. A request ID helps join work from one request; background work can have different context. Events inserted together can share a timestamp, and overlapping requests have no guaranteed total causal order. Use request/target IDs and the recorded changes rather than relying on row order alone.
What is recorded
The log combines application mutations, selected file-access activity, authentication activity, failed requests, and background work. The exact event rows depend on the operation and what the application can safely identify.
| Area | Useful evidence |
|---|---|
| Files and pastes | Creation, updates, deletion, organization/sharing metadata, available filenames and IDs, and selected access requests. |
| Archives | Browsing, entry reads, extraction, creation, source filenames, and opened member paths where available. |
| Folders, tags, and links | Changes to organization, rules, shares, and shortened-link records. |
| OCR and background work | Processing outcomes and failures, file context where available, expiration and cleanup activity. |
| Accounts and authentication | Sign-in/session events, account changes, credential-management actions, and failed or denied operations where attribution is available. |
| Roles and assignments | Changed roles, permissions, membership, and the acting account. |
| Invites | Invite creation, uses, revocation, account-deletion removal, and the accounts that joined, without invite tokens. |
| Instance configuration | Settings, email, storage, and appearance changes with safe changed-field metadata. |
| Integrations | Credential and webhook configuration/lifecycle activity without secret values. |
Flare records the changes it writes to these records as events named after the record and the database operation, such as file.update, role.upsert, or file_tag.deleteMany: files and pastes (file), folders (folder), tags (tag) and their file assignments (file_tag), accounts (user), roles (role), settings (setting), invites (invite), API tokens (token), upload profiles (upload_profile), webhooks (webhook) and their deliveries (delivery), queued email (mail), short links (link), and passkeys (passkey). A change that marks a webhook delivery or queued email failed, or records an error without cancelling it, has outcome failure. Sign-ins, sessions, storage cleanup, and file expiry record their own events instead. Other records, such as recovery codes, email links, and rate limits, have no change events.
Some operations produce several events: a request result and individual changes made while handling it can both be relevant. Bulk and background operations may provide counts or IDs instead of a separate readable filename for every affected object. Anonymous or unresolvable activity cannot always name an account; background jobs can be attributed to the system. The audit viewer is not a complete HTTP access log or a replacement for application error logs.
A password or sign-in address change records one user.update event for the account, whether the person changes it, an administrator edits it, or a reset or confirmation link applies it.
View, download, and short-link click counters are not change events. Each counted request already has its own request event: a share-page visit is file.view, a raw or /api/files/{path} read is file.read, a download is file.download (including /api/files/{path}?download=true), and a short-link redirect is an http.get event whose target is the link, named by its short code. The totals remain on the file and link records. An update that changes another field together with a counter is still a change event, and its snapshots include the counter. Logs from earlier versions still contain file.update and link.update events whose changedFields list only views, downloads, or clicks; upgrading does not remove or rewrite them. In those earlier logs, short-link http.get events have no link target and ?download=true reads appear as file.read.
Direct S3 requests after a signed URL has been issued, CDN hits, external identity-provider activity, direct database/storage edits, and actions outside the Flare process are outside this audit boundary. File-access events show what the application served or authorized, not proof of a completed download or a person reading a file. A request status is recorded when the handler returns its response; streaming may still be in progress, and a later network disconnect may not produce a second audit event. Use your reverse proxy, provider, and database logs when an investigation crosses those boundaries.
Successful audit-list reads, and the reloads of Profile → Integrations, do not add a new event on every refresh. Earlier versions recorded every Integrations reload, one every five seconds while the panel was open. Failed or denied audit requests can appear as audit.read, so malformed filter checks and access refusals remain visible without the viewer filling itself with successful reads.
Follow an OCR or storage failure
Search the filename or apply its Target ID, then review the event sequence. ocr.started, ocr.completed, and ocr.failed identify recognition work without storing extracted text. file.view, file.read, file.download, and file.thumbnail identify selected access paths; the recorded method/route distinguishes raw, direct, and media responses. file.embed is a link-preview fetcher, such as a chat app's, asking for a share link's embed: it reads the card or is sent on to the file, and adds no view itself. A later storage.delete_failed means a byte-removal attempt failed; successful metadata deletion does not prove the object was erased. Follow the storage cleanup guide and application diagnostics before reconciling remaining objects.
Expiration records use file.expiration.scheduled, file.expiration.cancelled, and file.expiration.applied, retaining the file context and selected expiry metadata. Applied background work is attributed to the system. Scheduling success alone does not prove that the later action ran; inspect the applied event and current file state.
For archive activity, filter Category to archives. archive.browse, archive.entry.read, archive.extract, and archive.create record request outcomes. archive.source.read identifies source files staged for extraction or creation; browsing does not stage files. archive.member.read identifies a member whose preview or download starts at its first byte, with details.size and the bytes being sent in details.bytes; continuing ranges, such as seeking in a video, add only archive.entry.read request outcomes. Earlier versions dropped details.bytes, so older archive.member.read events don't have it. archive.member.extract links a newly published file to its source archive and member path. Source/member read sizes are bytes, unlike file-snapshot sizes. A preview and a later download can produce separate reads. Entry contents and file passwords are excluded, and a successful response still does not prove complete delivery.
For invite links, filter Category to invites. invite.create records the note, creator, use limit, expiry, and granted role IDs. invite.update records a use or a revocation. invite.redeem records the account that joined, with its name and the role IDs it received; registration is anonymous, so its actor is not an existing account. invite.delete appears when deleting an account removes the invites it created. Invite tokens and their digests are never recorded.
Access and privacy
audit.read exposes history across the whole instance, including actors and filenames associated with private or deleted content. It is separate from content.read, users.read, and users.sessions; reading the log does not grant file-content access or the ability to revoke another person's sessions. Ordinary accounts can inspect only their own login history and active sessions.
Only Administrator has this access by default. A role manager with the necessary delegation authority can grant audit.read to a trusted reviewer. Removing the permission takes effect on the next authenticated request, including requests from an already open log page. There is no audit-log editing or deletion control, and neither named API tokens nor the legacy upload credential can read this API.
Authentication events can include a validated client IP and bounded user-agent string, when available. These are request metadata, not verified identities or locations; see trusted proxy configuration for which forwarding headers supply the address.
The logger uses selected metadata, not a dump of request bodies or settings. Passwords, authorization/cookie values, API-token secrets, authenticator/recovery secrets, file contents, OCR text, and raw configuration secret values are not intended audit fields. Actor names, filenames, IDs, and operational metadata can still be sensitive. Restrict access to the database and backups as carefully as access to the viewer. Review event details before sharing a screenshot outside your instance.
Retention and operational limits
Audit events start with this feature's installation; there is no backfill of earlier activity. They are stored in PostgreSQL and survive deletion of the actor account or target file. The viewer does not provide a purge or export button.
By default Flare keeps every audit event. The server operator can set FLARE_AUDIT_RETENTION_DAYS to a whole number of days, such as 365, to delete older events automatically. It is an environment variable rather than a setting on purpose: someone who can change instance settings could otherwise shorten the log to remove evidence of their own actions. Only someone who controls the server's environment can change it, and the change takes effect when Flare restarts.
With the variable set, each Flare process checks about a minute after it starts and then every hour. It deletes events older than the cutoff, oldest first, in batches of 5,000, with at most 100 batches per run; a larger backlog continues a minute later. Only one process deletes at a time. Everything older than the cutoff is removed, including the per-file evidence recorded when an account was deleted. Each run that deletes events records one audit.retention.applied event in category system, attributed to System, whose details give retentionDays, the cutoff timestamp (UTC), the count of events removed, and whether the run reached the cutoff (complete). A run that stops on a database error still records the events it already removed, with complete: false, and the next run continues. Filter Category to system to see when pruning ran.
Deleting events from the live table does not remove them from database backups made earlier. Keep backups for at least as long as you need to investigate past activity, and expire old backups under the same policy. Unset, empty, or 0 keeps every event. A value that is not a whole number from 1 to 36,500 is ignored with an error in the startup log, and every event is kept.
Most audit writes are best effort: a logging failure is reported in application diagnostics and does not deliberately prevent the user's underlying operation. The request event of a read that succeeded, a GET or HEAD such as a library page, a thumbnail or a file view, is written just after its response is sent, together with the others that finished at the same moment, so a screen of thumbnails costs a few database writes instead of one for each image. Changes, refusals and failed requests are still written before their response. A process that is killed can lose the read events it had not yet written: normally a fraction of a second's worth, and never more than 2,000, because once that many wait, each read goes back to recording its event before it answers until the database catches up. Account deletion is an exception: the per-file deletion evidence is inserted in the same database transaction as account removal and cleanup jobs. If that insert fails, the whole deletion rolls back; resolve the database failure before retrying. Transactional change events are buffered until the transaction commits so rolled-back writes are not represented as successful committed changes. An unavailable database, abrupt process termination, logging failure, or activity outside the instrumented application can leave gaps. An empty search result does not prove that nothing happened.
These records are ordinary application database data. Operators with database access can modify them; there is no cryptographic tamper evidence, independent archival service, or guarantee of exhaustive security/compliance evidence. Include the database in backups and restore checks, and retain infrastructure diagnostics appropriate to your own requirements. A database restore restores audit history only to that backup's point in time.
Investigate from a phone
Open the navigation menu, select Audit log under Admin, and use the same filters and event details. Narrowing the result first helps when reviewing a busy instance on a small screen.
Watch the recorded investigation or use the browser-session request examples against a disposable instance.
Troubleshoot missing or confusing activity
| Symptom | Check |
|---|---|
| Audit log is missing from the Admin menu | Confirm your effective roles include audit.read; users.read alone is insufficient. |
| A filename search returns no rows | Clear other filters, widen the time range, search the target ID, and check whether the activity predates installation. Some bulk events retain IDs/counts instead of names. |
| An actor or target no longer exists | Recorded metadata survives deletion; use its ID and neighboring events rather than assuming the current account/file is still present. |
| A file was created but processing failed | Inspect later OCR/background events and application diagnostics; upload acceptance and later processing have separate outcomes. |
| Expected events stop appearing | Check application logs and PostgreSQL health/storage, then reproduce one disposable operation. Do not infer success from missing events. |
| An operation appears more than once | Compare action, request ID, and details; one request can cause multiple recorded changes. |
| Views, downloads, or clicks have no change events | Counter increments are not change events. Filter by the file or link target and look for file.view, file.read, file.download, or the link's http.get request events instead. |