Skip to main content

Overview

Bifrost records two kinds of information about every request. Metadata covers model, provider, token counts, cost, latency, status, and governance attribution. Content is the actual prompts, completions, and tool traffic. Metadata is what dashboards, budgets, and alerts run on. Content is what makes a log useful for debugging, and what compliance regimes care about. Bifrost lets you keep the first without the second.
There is no single switch. Content is stripped independently at each destination, from that destination’s own setting. A log store with content disabled says nothing about what your BigQuery table or Datadog spans contain. This page covers how the layers compose.

What counts as content

Broadly, anything derived from the request or response body:
The categories each destination actually strips are not identical. A setting that removes messages may leave tool definitions or request parameters in place. Check the destination-specific notes below before treating a flag as a guarantee.
Attribution identifiers (user ID, team, customer, business unit, virtual key) are metadata, not content. They are never removed by a content setting. If end-user identifiers are sensitive in your deployment, treat that as a separate concern.

Where content can land


The control layers

1. Global: client.disable_content_logging

The default for the Bifrost log store. Set it to true and log rows keep metadata only.
This governs the log store only. It has no effect on observability connectors.

2. Per virtual key: disable_content_logging on the key

A virtual key can carry its own decision, set in the key’s editor under Content logging, through POST/PUT /api/governance/virtual-keys, or in config.json:
The field is tri-state: The key’s decision is admin configuration and needs no per-request override gate. client.retain_content_in_object_storage applies to a key-disabled request exactly as it does to a client-disabled one. On update, send null to clear the decision back to inherit; omitting the field leaves it unchanged. A request scoped to a project that has its own decision follows the project instead of the key. See the next layer.

3. Per project: disable_content_logging on the project

Enterprise. A project can carry its own decision for the requests scoped to it, set in the project’s editor under Content logging, through POST/PUT /api/governance/projects, or in config.json:
The field is tri-state. A value overrides the virtual key’s decision in both directions: The project’s decision applies once the project admits the request: the caller is one of its members, or the project is open. Like the key’s, it needs no per-request override gate, and client.retain_content_in_object_storage applies to a project-disabled request too. On update, send null to clear the decision back to inherit; omitting the field leaves it unchanged. See Projects for how a request names a project.

4. Per-request: x-bf-disable-content-logging

Overrides the client, virtual key and project settings for a single request, in either direction: true suppresses content for a request that would otherwise be logged, false captures content while the client, key or project setting has turned it off. Per-request overrides are off by default. Enable client.allow_per_request_content_storage_override first. While it is off, the header is ignored, and the client setting, overridden by the virtual key’s own setting and then by the project’s when they have one, is authoritative. See Request Options for headers, context keys, and SDK examples.

5. Per-connector: each connector’s own flag

Every observability connector has an independent disable_content_logging, defaulting to false. It is not inherited from the client setting. A virtual key or project with disable_content_logging: true tightens it for that traffic. Nothing on a key or project can loosen it: a project with false only lifts a key’s tightening. Maxim has no content flag of its own and applies a key’s or project’s off to Agent Gateway traces only. Captured request headers (request_headers on a connector, client.logging_headers on the log store) are exported regardless of any content flag. Only capture headers you intend to export.
For a workload where content must not leave the deployment, set disable_content_logging: true on the client and on every configured connector. Setting only the client flag still exports full content everywhere. Three layers can still put content back into the log store: a virtual key with disable_content_logging: false, a project with disable_content_logging: false, and the x-bf-disable-content-logging: false header while client.allow_per_request_content_storage_override is on. Audit your virtual keys and projects for false and keep per-request overrides off. client.retain_content_in_object_storage keeps the full payload of every content-disabled request in the object storage bucket. If content must not be persisted at all, set it to false. If content may be retained but must not leave the deployment, it can stay on only with that bucket inside the approved deployment boundary.

Retaining content in object storage

Disabling content logging normally drops content permanently. client.retain_content_in_object_storage offers a middle ground: content is kept in the object storage bucket but never served back.
In the UI this is Retain Content in Object Storage, under Logs Settings. The toggle is disabled unless object storage is configured on the logs store. When it is on and a request has content logging disabled, whether by the global setting, its virtual key, its project, or the x-bf-disable-content-logging header, Bifrost:
  • writes a metadata-only database row, with payload fields and the content preview cleared,
  • offloads the complete payload to object storage, marked hidden,
  • and never hydrates that payload back on reads. The Logs UI and the Logs API show metadata only.
The content is readable only by someone with direct access to the storage bucket. That is a different access path, typically governed by your cloud IAM rather than by Bifrost roles. The result is that retention and visibility become separate decisions.

Requirements and behavior


Interaction with other features

Raw byte storage. x-bf-store-raw-request-response only persists raw provider bodies when content logging is on for that request. With content logging off, raw bytes are dropped from the log row even if the header is set. Guardrail redaction. When Enterprise redaction is enabled, redaction runs before persistence and before export, so connectors and object storage receive the redacted or placeholderized values. Reveal mappings stay on the Bifrost log row and are never exported. With disable_content_logging enabled, no reveal data is persisted at all. See Guardrail Redaction. Log exports. Offloaded payloads carry the same fields the log row would have carried. See Log Exports.

Choosing a configuration

Metadata only, everywhere. Set disable_content_logging: true on the client and on every connector. Confirm no connector is capturing headers you did not intend to export. Metadata in Bifrost, content retained for security review. Set disable_content_logging: true and retain_content_in_object_storage: true, with object storage configured. Restrict bucket access to the reviewing team. Content on by default, suppressed for sensitive traffic. Leave disable_content_logging: false, enable allow_per_request_content_storage_override, and send x-bf-disable-content-logging: true on the requests that need it. Content in Bifrost, not in third-party tools. Leave the client setting off and set disable_content_logging: true on each connector. Content off for one piece of work. Set disable_content_logging: true on its project and keep allow_per_request_content_storage_override off. Every request scoped to it is then stored without content and stripped from connector export, whichever virtual key the caller uses. Keep retain_content_in_object_storage off as well if the content must not be persisted at all.