Skip to content

Observe agent activity

Before you can enforce a policy on an agent action, you need to know which agents are running, who runs them, and what they do. Arcjet ingests agent activity without a code change, through three paths:

  • Coding agent hooks, where Claude Code or GitHub Copilot calls Arcjet at each lifecycle event. This is the only path that can also refuse a tool call. For more information, see Secure coding agents.
  • OpenTelemetry, where a client you already run exports to Arcjet. It pushes with low latency and carries host metadata and token usage.
  • The Claude Compliance API, where you paste one key and Arcjet polls Anthropic for your organization’s activity and session transcripts. It needs no client configuration and covers clients you never configured.

All three render in the same Console views. OpenTelemetry and Compliance API activity is context, not enforcement: it records what an agent did. To decide whether an action runs, add an enforcement point with agent guards or install the hooks.

Arcjet accepts OpenTelemetry (OTLP) exports over HTTP at https://decide.arcjet.com and records each record as an Arcjet capture event. Point any OTLP exporter at it.

Set these environment variables to export Claude Code’s security and audit telemetry:

Terminal window
export CLAUDE_CODE_ENABLE_TELEMETRY=1
export OTEL_LOGS_EXPORTER=otlp
export OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf
export OTEL_EXPORTER_OTLP_ENDPOINT=https://decide.arcjet.com
export OTEL_EXPORTER_OTLP_HEADERS="Authorization=Bearer ARCJET_KEY"
export OTEL_LOG_USER_PROMPTS=1
export OTEL_LOG_TOOL_DETAILS=1

Replace ARCJET_KEY with the key for the site the activity belongs to.

OTEL_LOG_USER_PROMPTS and OTEL_LOG_TOOL_DETAILS enrich the audit trail with prompt text and tool arguments. Leave them unset if that content shouldn’t leave the machine.

To enable ingest for everyone rather than relying on each person’s shell, ship the same configuration through Claude Code managed settings:

{
"env": {
"CLAUDE_CODE_ENABLE_TELEMETRY": "1",
"OTEL_LOGS_EXPORTER": "otlp",
"OTEL_EXPORTER_OTLP_PROTOCOL": "http/protobuf",
"OTEL_EXPORTER_OTLP_ENDPOINT": "https://decide.arcjet.com",
"OTEL_EXPORTER_OTLP_HEADERS": "Authorization=Bearer ARCJET_KEY",
"OTEL_LOG_USER_PROMPTS": "1",
"OTEL_LOG_TOOL_DETAILS": "1"
}
}

Three details decide whether this works:

  • Every value is a string, including "1".
  • Put a literal space after Bearer. OTEL_EXPORTER_OTLP_HEADERS is baggage-encoded, so Claude Code’s exporter sends that space as %20. Arcjet decodes the header before parsing it, so either a literal space or %20 works. Don’t encode it twice.
  • Point OTEL_EXPORTER_OTLP_ENDPOINT at the host with no port. Port 4317 is the gRPC port, which Arcjet doesn’t accept. The exporter appends the OTLP HTTP paths itself.

The same managed settings file can carry the coding agent hooks, but use one or the other for a given site.

SignalPathWhat happens
LogsPOST /v1/logsThe primary signal. Each log record becomes one capture event.
TracesPOST /v1/tracesEach span becomes a capture event, best effort.
MetricsPOST /v1/metricsAuthenticated and acknowledged, but not recorded.

Arcjet acknowledges metrics rather than rejecting them so that an exporter also sending metrics to another backend doesn’t error. Aggregate counters aren’t discrete auditable events, so there’s nothing to record.

Both OTLP wire formats work: http/protobuf and http/json. gRPC on port 4317 doesn’t.

Each record maps onto a capture event:

OTLPCapture event
Event nameaction, verbatim. Claude Code sends names like claude_code.tool_decision.
session.idcorrelationId, which joins the activity in one session.
Every other attributemetadata, with types preserved. A duration stays a number and a tool argument object stays an object.
service.nameThe sender identity. Claude Code reports claude-code.

Metadata limits follow OpenTelemetry conventions: 128 keys, 32 KiB per serialized value, and a depth of 10. Past the cap, Arcjet keeps the security-relevant keys first and records what it dropped on the event, so a truncated event is never silently truncated.

Ingest is fire and forget. A 200 means Arcjet received the export, not that it’s queryable yet.

Instead of configuring an exporter on every client, connect one key and Arcjet polls Anthropic for your organization’s activity and session transcripts.

Your Anthropic organization decides which credential you can create, and the two differ in what Arcjet can import:

Compliance Access KeyAdmin API key
Prefixsk-ant-api01-sk-ant-admin01-
Who can create itA Claude Enterprise primary owner or organization ownerA Claude Console organization admin
Arcjet importsActivity and session transcriptsActivity only

An Admin API key reaches the activity feed and nothing else, so you get which sessions ran, when, and by whom, but no prompts, tool calls, or transcripts. Arcjet detects the key type and skips the transcript requests rather than spending your organization’s shared rate budget on calls that can’t succeed.

Ask for read-only scopes: read:compliance_activities and read:compliance_user_data. A key can also carry delete:compliance_user_data, which permits hard-deleting chats, files, and projects. Arcjet never calls a delete endpoint.

For more information about the two credentials, see Anthropic’s Compliance API access documentation.

  1. In the Arcjet Console, open your team, then go to Settings > Integrations > Claude Compliance.
  2. Select which Claude product your organization uses.
  3. Enter the key and select the destination site. A team with one site skips this choice.
  4. Select Connect. Arcjet validates the key against Anthropic before storing it, so a key that doesn’t work is never stored.

A team admin has to do this, because the credential is a team resource: one key, one connection, one destination site. You can change the destination later without reconnecting. The connection keeps its position in the feed, so ingest continues where it left off, but events already imported stay with the site that received them.

The key never comes back from any API, never returns to the browser after you submit it, and is never written to Arcjet’s databases. Arcjet stores a masked form and a salted fingerprint.

Recording isn’t retroactive, and Anthropic doesn’t backfill, so nothing from before you enabled the Compliance API is available. Turning it off later stops recording, and that gap can’t be recovered.

These are also absent, whichever key you connect:

  • Claude Code authenticated with a Console API key, or run through Amazon Bedrock, Google Vertex AI, or Microsoft Foundry.
  • Claude Code on the web.
  • Organizations with HIPAA readiness enabled, and any session under zero data retention.
  • Thinking blocks, images, and other binary content.
  • The system prompt. A marker message stands in for it.

Tool inputs and results are truncated to 10,000 bytes each.

The integration panel shows the last sync, how far through the feed it has read, the last error, and whether the connection is rate limited.

What you seeWhat it means
Status is needs_reauthThe key was revoked or the connection is gone. Reconnect.
Reconnected, still not syncingAnthropic rejected the stored key. Only a different key clears this. Resubmitting the same one isn’t a rotation.
Activity but never any transcriptsThe connection uses an Admin API key. Transcripts need a Compliance Access Key.
Sessions but no transcriptsThose sessions predate enablement, so their content was never captured.
Lagging with no errorsYour organization’s shared rate budget is being consumed by your own tooling.
Nothing at allConfirm the Compliance API was enabled before the period you’re looking for.

Ingested activity appears in the Console under the site’s Activity, alongside the guard and protect decisions Arcjet made. Each row carries the sender, the asserted principal, and the correlation ID that joins the events of one session, so you can follow a session from its first prompt to its last tool call.

An ingested event is asserted context, so an action that appears in the activity with no decision beside it is an action nothing enforced. That gap is the point of the view. Use it to find the actions worth guarding, then add an enforcement point and a policy for each, or install the coding agent hooks where the sessions are Claude Code or Copilot.

Ingested activity is untrusted context. Arcjet records it, correlates it, and shows it, but it can never satisfy a protection requirement: a capture event is what a client said happened, not something Arcjet adjudicated.

Session transcripts carry raw prompts, source code, and any credential someone pasted into a session. Neither Anthropic nor Arcjet masks that content at ingest. Prompt and tool-detail capture is opt-in on the OpenTelemetry path, through OTEL_LOG_USER_PROMPTS and OTEL_LOG_TOOL_DETAILS. On the Compliance API path it arrives organization-wide with no per-client opt-in, which is worth weighing before you connect it.

For what Arcjet retains and for how long, see the privacy documentation.