--- title: Track any SDK agent description: Two lines of Python capture cost, tokens, latency and errors from any agent built on the OpenAI Agents SDK, LangChain, LlamaIndex, the Vercel AI SDK or httpx. keywords: track LangChain agent cost, OpenAI Agents SDK observability, LLM cost interceptor Python, production agent monitoring eyebrow: Runtimes --- # Track any SDK agent The 27 supported runtimes all write sessions to disk. Your own **production agent** does not — a service built on the OpenAI Agents SDK, LangChain, the Vercel AI SDK, LlamaIndex, E2B or a plain `httpx` loop keeps its state in your application, not in a transcript directory. The interceptor covers that case. It monkey-patches the HTTP client, captures every LLM call, and writes them where the daemon already looks. ## Two lines ```python import clawmetry.track # activate the interceptor clawmetry.track.set_source("support-agent") # name this product ``` That is the whole integration. From here every LLM call the process makes is recorded with its model, provider, token split, latency, cost and error status, attributed to `support-agent`. ## Without touching the code ```bash CLAWMETRY_TRACK=1 CLAWMETRY_SOURCE=billing-agent python my_agent.py ``` `CLAWMETRY_TRACK=1` activates on import of the `clawmetry` package; `CLAWMETRY_INTERCEPT=1` activates it when ClawMetry itself starts. Either works; the environment form is the one to use in a container where you would rather not patch an image to add an import. ## What gets intercepted The interceptor patches `httpx.Client.send` and `requests.Session.send` — the transport both major Python SDK families use underneath — and matches on the request host: | Provider | Host | |---|---| | Anthropic | `api.anthropic.com` | | OpenAI | `api.openai.com` | | Google | `generativelanguage.googleapis.com` | | OpenRouter | `openrouter.ai` | Non-LLM outbound calls are captured separately as **external calls**, which is how the dashboard can show you that your agent spent nine seconds waiting on a third-party API rather than on a model. Loopback and internal hosts are excluded by default, and `CLAWMETRY_INTERCEPT_HOSTS_EXCLUDE` takes a comma-separated list of additional substrings to skip. If neither `httpx` nor `requests` is installed, the interceptor silently no-ops. It never raises into the host application — an observability tool that can crash the thing it observes is worse than no observability tool. ## Naming sources `set_source()` is what makes this useful at more than one agent. Each named source becomes its own first-class line in the dashboard's **out-loop sources** card, with calls, providers, latency and error rate per agent. ```python import clawmetry.track clawmetry.track.set_source("support-agent") # ... later, from anywhere in the process: stats = clawmetry.track.get_stats() # {"calls": …, "input_tokens": …, "cost_usd": …} ``` Set it once, early. A process that never names itself still gets captured; it just lands under a default source, and telling three unlabelled agents apart afterwards is not fun. ## Where it writes The interceptor appends JSONL to the workspace, and the daemon ingests it on its normal cycle — the same DuckDB store, the same rollups, the same end-to-end-encrypted cloud snapshot as every on-disk runtime. There is no separate pipeline to operate. ## Turning it off | Variable | Effect | |---|---| | `CLAWMETRY_NO_INTERCEPT=1` | Opt out even when `clawmetry.track` is explicitly imported | | `CLAWMETRY_INTERCEPT=0` | Do not auto-activate at ClawMetry startup | ## When to use the ingest API instead The interceptor sees *LLM calls*. If you want to record agent structure — runs, steps, tool invocations, a session boundary — push those explicitly: ```python # a run with structure, rather than a stream of model calls POST /api/v1/runs POST /api/v1/runs//events POST /api/v1/runs//end ``` → [Custom runtime ingest](/docs/runtimes/custom-ingest/) Nothing stops you doing both: the interceptor for cost truth, the ingest API for the shape of the run. ## Overhead The patch adds a small amount of work per request — reading the response's usage block and appending a line. Measure it against your own workload rather than a tight loop of no-op calls, which is not a realistic shape and will make the relative overhead look far worse than it is in a real agent that spends most of its wall clock waiting on a model.