> ## Documentation Index
> Fetch the complete documentation index at: https://docs.surfacearea.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Auto-instrumentation

> Capture LLM and agent-framework calls automatically: the frameworks Surface Area instruments and how to control which ones are active.

Auto-instrumentation captures calls to common LLM and agent frameworks as spans with no span code on your part. Call `tracing.init()`, then call an instrumented library, and Surface Area records the call.

## How it works

`tracing.init()` instruments installed AI libraries by default (`instrument_default=True`). Each library is instrumented when both the library and its instrumentor package are installed.

Install the common instrumentor packages with the `tracing` extra. It bundles the instrumentors for OpenAI, the OpenAI Agents SDK, Anthropic, and LiteLLM. It installs the instrumentors, not the libraries: LiteLLM is traced only when your app installs `litellm` itself, and the extra places no upper bound on `openai`.

```bash theme={null}
pip install 'gatewaysdk[tracing]'
```

The Claude Agent SDK instrumentor ships inside `gatewaysdk` and needs no extra package. LangChain, LlamaIndex, and the additional frameworks below each need their own OpenInference package (for example, `pip install openinference-instrumentation-langchain`).

<Info>
  If you have an AI library installed but not its instrumentor, `init()` logs a warning naming the library and pointing at the `tracing` extra.
</Info>

<Info>
  In TypeScript, wrap clients explicitly with `observeOpenAI`, `observeAnthropic`, and `observeClaude`. See the [TypeScript SDK](/sdk-ts) page.
</Info>

The instrumentors are built on [OpenInference](https://github.com/Arize-ai/openinference), plus a native instrumentor for the Claude Agent SDK. They produce standard OpenTelemetry spans, so they flow to Surface Area alongside the spans you create yourself.

## The core set instrumented by default

With `instrument_default=True`, `init()` enables the core set below, each one only if it is installed.

| Instrumentor name | Captures |
| - | - |
| `openai_agents` | OpenAI Agents SDK |
| `claude_agent_sdk` | Claude Agent SDK |
| `openai` | OpenAI Python client |
| `anthropic` | Anthropic Python client |
| `langchain` | LangChain |
| `llama_index` | LlamaIndex |
| `litellm` | LiteLLM |

<Info>
  The OpenAI call in the [Quickstart](/get-started/quickstart) is captured this way. After `init()`, the call nests under whatever trace is active, and Surface Area records its model, messages, token counts, and cost automatically.
</Info>

## Additional instrumentors you can enable by name

These instrumentors are registered but not enabled by default. Enable them with `tracing.instrument(names=[...])`.

| Instrumentor name | Captures |
| - | - |
| `google_adk` | Google Agent Development Kit |
| `vertexai` | Google Vertex AI |
| `mistral` | Mistral AI |
| `groq` | Groq |
| `bedrock` | AWS Bedrock |
| `dspy` | DSPy |
| `instructor` | Instructor |
| `crewai` | CrewAI |

Each still requires its target library and OpenInference instrumentor package to be installed.

## Older client versions

An instrumentor package can declare that it supports only newer releases of its library. When yours is older, `init()` still instruments it and logs one warning naming the version range.

For `anthropic` releases before 0.84 (for example 0.76, which browser-use pins), Surface Area switches to its own built-in Anthropic instrumentor and logs a warning that says so. It traces `messages.create` and `beta.messages.create`, sync and async, on `anthropic` 0.41 and later: one generation span per call with the model, messages, response and token counts, including cached prompt tokens. Base64 images and documents are replaced by a short marker, and MCP server `authorization_token` values are never recorded. Upgrade `anthropic` to 0.84 or later to get the full instrumentor.

## Credentials are never exported

A request can carry a credential the model provider needs, such as an MCP server's `authorization_token`. `tracing.init()` removes it from every span before export, whichever instrumentor recorded it, and wherever it sits as a JSON key in a recorded request. When a recorded value names the key any other way (an attribute cut short by `OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT`, a Python `repr`, a query string, key/value pairs, or text that mentions `authorization_token`), the whole value is replaced by `[redacted: holds a credential]` rather than risk exporting the token. That can also hide a value that only mentions the name, such as a tool output quoting SDK source. The request itself still goes to the provider unchanged.

```python theme={null}
client.beta.messages.create(
    model="claude-sonnet-4-5",
    max_tokens=1024,
    messages=[{"role": "user", "content": "What changed today?"}],
    betas=["mcp-client-2025-04-04"],
    mcp_servers=[{"type": "url", "url": "https://mcp.example.com/sse", "name": "example", "authorization_token": token}],
)
# The span keeps the server's url and name. The token never leaves the process.
```

This covers every exporter passed to or created by `init()`. If you attach an exporter to your own `TracerProvider` (or `init()` reuses one that already has exporters, which it warns about), wrap its processor: `SecretRedactingSpanProcessor(BatchSpanProcessor(exporter))` from `gatewaysdk.tracing.processors`.

## Control which libraries get instrumented

Turn off the default core set and enable specific instrumentors by name.

```python theme={null}
import gatewaysdk.tracing as tracing

tracing.init(instrument_default=False)
tracing.instrument(names=["openai", "anthropic"])
```

Skip a single instrumentor while keeping the rest of the core set.

```python theme={null}
import gatewaysdk.tracing as tracing

tracing.init(instrument_default=False)
tracing.instrument(skip=["langchain"])
```

<Info>
  `tracing.instrument(skip=[...])` skips names from the core set only. To enable an additional instrumentor such as `crewai` or `mistral`, pass it explicitly with `names=[...]`, since it is not part of the default set.
</Info>

<Info>
  **Do not set `OPENAI_AGENTS_DISABLE_TRACING=1`.** The `openai_agents` instrumentor rides on the Agents SDK's own tracing pipeline: that variable turns the pipeline off entirely, and with it **all Surface Area telemetry** for the agent, silently. It's often set to silence the OpenAI trace-upload 401s that appear when pointing the client at a non-OpenAI base URL; those 401s are harmless noise. `tracing.init()` prints a warning if it detects the variable.
</Info>

## Tag auto-instrumented calls

Auto-instrumented spans are created where no `tracing.trace` block is in scope. Wrap the call in `tracing.tracing_context()` to attach a session id, tags, or a call type to those spans.

```python theme={null}
import gatewaysdk.tracing as tracing

with tracing.tracing_context(session_id="conversation-42", tags=["support"]):
    response = client.chat.completions.create(...)  # Span gets the session id and tags
```

## Where to go next

* [Instrument an agent](./setup): add your own spans around the auto-captured calls.
* [Sessions & traces](./sessions): group auto-instrumented calls into a session.
* [Metadata & identity](./metadata): attach users, agents, and tags.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.