Telemetry Privacy Controls
Control whether Droid telemetry carries per-user identity or message content, and see exactly what reaches Factory versus your own collector.
Two org-managed controls decide what Droid telemetry contains: telemetry.granularity for per-individual identity, and telemetry.logMessageContent for message content. This page covers both, and where each kind of data can go.
What reaches Factory versus your collector
| Data | Factory's collector | Your collector |
|---|---|---|
| Metrics | Yes (never in an airgapped deployment) | Yes, once an endpoint is configured. |
| Spans, including all message content | Never, in any configuration. | Only with a collector of your own, and content only with the opt-in below. |
OTEL_RESOURCE_ATTRIBUTES pairs | Never. | Yes. |
telemetry.granularity applies at the source, before export, so it binds Factory's collector and yours equally. telemetry.logMessageContent only controls whether message content is written to your own span export (Factory never receives spans).
Data granularity
Some organizations operate under a works council agreement or a jurisdictional rule that forbids per-individual analytics. telemetry.granularity is the control for that, applied at the source so identifying data is never written rather than filtered downstream.
| Mode | Behavior |
|---|---|
user (default) | Datapoints carry per-user identity. |
aggregate | user.id, user.email, commit.hash, pr.number, and pr.url are removed from every datapoint on both collectors, and message content is never written regardless of any other setting. |
organization.id survives aggregate mode, because it is the dimension you aggregate over. So do session.id, parent_session.id, model.id, and every workload attribute such as tool.name, repo.*, and skill.name. Data in aggregate mode carries the resource attribute telemetry.granularity: aggregate, so a downstream consumer can tell which mode produced it.
Resolution is most-restrictive-wins, not a precedence order: either telemetry.granularity or OTEL_TELEMETRY_GRANULARITY asking for aggregate yields aggregate, and an organization set to user cannot override a machine set to aggregate. A value that cannot be read resolves to aggregate.
Aggregate mode overrides every content opt-in, including telemetry.logMessageContent: true. It also changes what spans you get:
legacyplusaggregateproduces no spans at all. Thedroid.message.*anddroid.tool.*event spans are per-user by construction, so there is nothing left to strip them down to. Metrics still flow.genaiplusaggregatekeeps the full trace, with the four content attributes stripped. Use this combination if you need trace structure under a compliance mandate.
Message content logging
Message content export is off by default. Metrics fan out to both Factory and your collector; message content does not.
The organization's controls are authoritative:
| Control | Effect |
|---|---|
telemetry.granularity: aggregate in org-managed settings | Content is never exported, overriding every setting below. See Data granularity. |
telemetry.logMessageContent: true in org-managed settings | Content is exported on every member's machine, whether or not they set OTEL_LOG_MESSAGE_CONTENT. |
telemetry.logMessageContent: false in org-managed settings | Content is never exported, even on a machine that sets OTEL_LOG_MESSAGE_CONTENT. |
| Property omitted from org-managed settings | Each machine decides for itself with OTEL_LOG_MESSAGE_CONTENT. |
To enable message content export for the current process (for example, for session auditing) where the organization has left the decision open, set:
export OTEL_LOG_MESSAGE_CONTENT=true # or 1When enabled, Droid emits message content as OTEL trace spans, on the /v1/traces path of your endpoint. Where it lands depends on your export format.
Under legacy, content arrives as four span types:
- User messages (
droid.message.user) - Assistant responses (
droid.message.assistant) - Tool calls and their inputs (
droid.tool.call) - Tool results (
droid.tool.result)
Under genai, the same content arrives as four attributes on the GenAI spans: gen_ai.input.messages, gen_ai.output.messages, gen_ai.tool.call.arguments, and gen_ai.tool.call.result.
Message content is exported raw, with no redaction. There is no PII scrubbing and no secret detection; the only transformation is truncation of any single attribute to 32,000 characters. These spans contain verbatim prompts, responses, tool inputs (including file contents and command arguments), and tool results. Make your data-classification decision accordingly before enabling.
Spans are sent only to the collector you configure. Droid does not fan out any span to Factory's collector.
- A customer endpoint (
telemetry.endpointorOTEL_TELEMETRY_ENDPOINT) is required. With none set, Droid builds no trace pipeline, so content is never written rather than being written and dropped. - If your endpoint resolves to the same URL as Factory's collector, it does not count as a collector of your own: no span is recorded and content logging is disabled. Adding credentials to the URL does not make it distinct.
- Metrics export is unaffected and continues to fan out to both Factory and your collector.