Near real-time audit logs
Near real-time audit logs
Near real-time audit logs overview
Near real-time audit logs give you a continuous record of API activity against your Contentful organization. Each event describes a single Contentful Management API (CMA) request: who made it, what it addressed, and how Contentful responded.
Events are delivered in near real time to your configured storage destination, where they can be processed, analyzed, or retained using your existing tools. As with all Enterprise observability log sources, Contentful handles the delivery, while you manage storage, access, and downstream processing.
Events use the Open Cybersecurity Schema Framework (OCSF) version 1.3.0 and are emitted as API Activity events, so any SIEM that understands OCSF can ingest the feed without a custom parser.
Audit logs cover both writes and reads. Unlike the daily audit log exports, GET requests are part of the feed.
Audit logs as a log source
Audit logs are a log source within log streaming, alongside the Content Delivery API and GraphQL API sources. The storage destinations, credentials model, authentication flow, and delivery model are the ones you already use for your other Contentful logs.
Audit logs extend that setup rather than replace it. Because they are their own log source, each destination you want them delivered to is configured explicitly. This lets you route audit logs to a different bucket, container, or account than your API logs, and lets you enable or disable audit log delivery independently.
Delivery guarantees and best-effort delivery
Audit log streaming follows the same at-least-once, best-effort delivery model as every other log streaming source. See Delivery guarantees and Best-effort delivery for how that model works.
Specific to audit logs:
- Use
metadata.correlation_uidas your deduplication key. It identifies the originating request, so two events carrying the same value describe the same call. - Because delivery is best-effort, the absence of an event is not proof that the corresponding request did not happen.
Frequency and file output
Logs are sent every few minutes. The exact interval is not configurable. Each delivery cycle may produce multiple files.
Files are delivered in NDJSON format, compressed as .jsonl.gz, with one OCSF event per line. Each file follows the same structured naming convention as other log sources:
log_source=audit_logs/organization_id=<org_id>/year=YYYY/month=MM/day=DD/compacted-audit-logs-<uuid>.jsonl.gz
Example:
log_source=audit_logs/organization_id=274qvl9SkVAlToItncE81X/year=2026/month=05/day=28/compacted-audit-logs-b6afdaef-8bce-4f21-a8c2-72abfd3ba15c-166.jsonl.gz
Files are partitioned by organization and by the UTC date of the event. The log_source=audit_logs prefix keeps audit logs separate from your other log sources when they share a destination. There are no configuration options for delivery frequency, interval, batch size, or file format.
Events are targeted to reach your destination within 5 minutes of the originating request, subject to your destination’s own ingest latency.
Setting up audit log streaming
Audit logs are delivered to the same destinations as other log sources: Amazon S3, Google Cloud Storage, and Azure Blob Storage.
Prerequisites and limits
Before setting up audit log streaming, ensure you have:
- An Enterprise plan subscription.
- Organization owner or admin role in Contentful.
- A storage destination prepared. The provider setup steps for Amazon S3, Google Cloud Storage, and Azure Blob Storage are the same for audit logs, and a destination you already use for other log sources can receive audit logs as well.
Configuration limits: audit logs count as their own log source, so the standard limit applies independently. You can have a maximum of 2 audit log configurations per storage destination per organization, in addition to your Content Delivery API and GraphQL API configurations.
Static IP addresses
Contentful uses the same static egress IP addresses for audit logs as for other log sources. If your organization requires IP allowlisting, configure your firewall or network settings to include them. The addresses vary by data residency region.
For the full list, read Audit Logs: Static IP addresses.
Configure audit log streaming in Contentful
After preparing your cloud storage destination, complete the configuration in the Contentful web app.
- Go to Organization settings → Observability.
- Click Create new configuration.
- Select Audit logs as the Log source.
- Select a Storage provider: Amazon S3 Bucket, Google Cloud Storage, or Azure Blob Storage.
- Enter a Configuration name. This is a descriptive label to identify this configuration (e.g.
audit-logs-siem). - Click Save to begin streaming audit logs to your configured destination.
Audit logs are delivered under their own log_source=audit_logs prefix, so pointing an audit log configuration at a destination that already receives other log sources will not overwrite anything.
What happens next
- After successful configuration, your organization is enabled automatically. Events will begin arriving within 5–15 minutes.
- You can monitor delivery status in Organization settings → Observability in the Contentful web app, or use the delivery status API to check programmatically.
- Delivery operates on a best-effort basis, meaning logs are sent as quickly as possible, typically within minutes.
- If delivery fails, Contentful retries automatically and notifies organization owners and admins by email; undelivered logs are permanently discarded after 24 hours of continued failure — see Monitoring delivery below.
Audit log schema
Use the following schema to understand the structure of each audit log event. Each event represents a single CMA request and response, described using OCSF attributes.
When building parsers, expect that additional attributes may be added. Reference by attribute name instead of field position, and dispatch on class_uid rather than on file path so that any event class added in the future is additive for your parser.
Fields defined by OCSF but not listed below are not populated.
class_uid 6003), while daily audit log exports use OCSF Web Resources Activity (class_uid 6001). This is an intentional change for the near real-time feed — see Event shape for the full comparison.Classification fields
Actor fields
The whole actor object is omitted for requests where no identity was established. See Identifying actors.
Metadata fields
Request and response fields
authorization header value is redacted. It keeps a short prefix and suffix around a [REDACTED] marker, which is enough to attribute activity to a specific token, and to recognize the same token across events, without exposing the token itself.Resource fields
resources holds up to three entries, in the order space, environment, entity. It is omitted for endpoints with no space context, such as organization-level and user-level endpoints, where metadata.tenant_uid still identifies your organization.
Enrichment fields
enrichments carries context that the HTTP layer alone cannot express, for the requests that produce it. See Enrichments for the payload of each enrichment type.
Example events
Entry update by an authenticated user:
Organization-level request, with no space context and no identified actor:
Interpreting audit log events
The following behavior is intentional and stable.
Identifying actors
Identify actors by actor.user.uid for users and actor.app_uid for apps. These are stable identifiers and the right keys for correlation, grouping, and detection rules.
The email_addr and full_name fields carry the user’s profile as it stood when the event was emitted. Because they are a point-in-time snapshot, a profile that was just changed can take a short while to come through, so events for the same user may carry differing values before converging on the current profile.
The actor object is omitted entirely for requests where no identity was established. Audit logs capture every request that reaches the Management API surface, from any client, which includes malformed requests and requests from clients you do not operate. A missing actor does not make an event invalid.
Missing values
Empty values are omitted rather than filled in. A serialized 0 means the value really was zero, never that Contentful did not capture it. Optional fields and objects such as duration, http_response.length, actor, resources, and enrichments are absent from the JSON when they do not apply.
Two request fields are exceptions and are delivered as empty strings when the client sent nothing: http_request.referrer and http_request.url.query_string.
Severity and detections
severity_id is always 1, Informational. Audit logs are an event stream, not a security signal. Build detections on status_id, activity_id, api.operation, and resource patterns, so that transport failures such as HTTP 5xx responses are not conflated with security incidents.
Unknown values use OCSF sentinels: activity_id 0 for Unknown and 99 for Other both come from the specification. Contentful does not invent enum values.
Activity IDs and content operations
activity_id reflects the HTTP method, not the content operation. Publish, unpublish, archive, schedule, and workflow transitions are usually expressed as PUT and therefore appear as activity_id 3 (Update). Some, notably unpublish, can also be expressed as DELETE, so the same logical action can arrive with a different value depending on the client.
Match on api.operation when a rule needs to detect a specific content operation.
Resource types
resources[].type is space, environment, or entity. The Management API exposes many specific object types, including entries, assets, content types, tags, releases, roles, webhooks, and API keys, and all of them appear as entity so that the schema stays stable as the API grows. Parse http_request.url.path if you need the specific type.
GET requests don’t include an entity resource. Audit logging captures what a request changed, and a read changes nothing, so resources for a GET request holds only space and environment. Parse http_request.url.path if you need the addressed object’s ID for a read.Enrichments
Some requests carry information that the HTTP layer alone cannot express. A bulk action names every entity it addressed in its request body, and an AI action invocation records which model produced which output. Contentful delivers that context on the same event, in the OCSF enrichments array, so there is no second event to correlate.
Two enrichment types are populated today:
- Bulk actions,
typeBulkActionEnrichment: the operation performed and the full set of entities it addressed, whichresourcesdoes not list individually. - AI actions,
typeAiActionEnrichment: the invocation, the AI action and entry involved, and the model that served it.
A request can produce more than one entry, including entries of different types. Read data.payload according to type and data.type_version. Both the set of enrichment types and the fields inside data.payload may grow over time, so ignore payload fields you do not recognize rather than rejecting the entry.
enrichments appears only on requests that produce this data, so most events do not carry it.Bulk actions
data.payload is an array of action and entities pairs. action is the bulk operation, such as publish, unpublish, validate, or duplicate. entities lists the addressed items as Contentful links.
On a bulk action request, resources identifies the space, the environment, and the bulk action itself. The entries the action addressed are in enrichments[].data.payload[].entities[].
AI actions
data.payload is an array of invocations, each recording the AI action invoked, the entry and field affected, and the model that served the request.
Migrating from daily audit log exports
If your organization already consumes daily audit log exports, the near real-time feed differs in ways that require changes to your ingest pipeline. Re-validate your parsers and detection rules against the tables below.
Coverage and file format
Consuming the near real-time feed means decompressing gzip and parsing line by line, rather than parsing one JSON document per file.
Event shape
If you previously joined audit events to other logs on metadata.uid, switch that join to metadata.correlation_uid.
Actors
Near real-time audit logs use the OCSF value type_id 1 for a user, where the daily export emits 2.
Resources and enrichments
Bulk and AI action entries stay in enrichments, close to the shape you already parse. Within an entry:
So code reading enrichment.data[0].entities reads enrichment.data.payload[0].entities, code reading enrichment.created_time as a string receives an integer, and code reading enrichment.data.created_time as a string also receives an integer. Those three are the only breaking changes within an entry.
Monitoring delivery
Audit log configurations appear in Organization settings → Observability alongside your other log source configurations, and are monitored the same way. Delivery statuses, email notifications to organization owners and admins, automatic retries, and the 24-hour window before undelivered logs are discarded all behave as described in Monitoring delivery and Troubleshooting log delivery failures.
Receiving duplicate events
Duplicate events are expected. Audit log streaming uses an at-least-once delivery model by design. Use the metadata.correlation_uid field to deduplicate events in your downstream pipeline.
Logs are missing for a past time period
If audit log delivery was not enabled and configured during that period, those logs cannot be recovered. Contentful does not backfill historical audit logs.
Limitations
resourcesdoes not list the entities a bulk operation addressed. For endpoints such as bulk actions,resourcesidentifies the space, the environment, and the bulk action itself. The entities are inenrichments.api.operationcan be absent. When no route pattern is resolved for a request, theapiobject is omitted. The rest of the event, including the concrete request path, is unaffected.