Documentation Index
Fetch the complete documentation index at: https://langwatch.ai/docs/llms.txt
Use this file to discover all available pages before exploring further.
Ingestion Templates
Status: v1, push-mode templates only. OAuth-redirect and pull-mode (S3, API) shapes are reserved for a future iteration.LangWatch’s Ingestion Templates let you connect tool-specific telemetry sources (Claude Code on Anthropic 20x, Cursor, Claude cowork, …) to your personal workspace without LangWatch ever participating in the upstream tool’s authentication. You install a template, paste a binding token into your tool’s OTLP exporter, and traces land at
/me/traces already shaped into the canonical gen_ai.* form, cost, tokens, and
model populated automatically.
Why ingestion templates exist
If your tool has a LangWatch virtual key, the AI Gateway proxies the request and we ingest canonical traces from the gateway response. Done. But many tools don’t fit that path:- Subscription-bound tools: Claude Code on Anthropic 20x, GitHub Copilot, etc. The user has no API key the gateway can proxy through; the tool authenticates client-side with the upstream provider.
- Native-OTLP tools: Cursor, Claude cowork, Continue.dev, Aider, Cline. They already emit OpenTelemetry traces locally; what they need is a place to ship them.
langwatch.source provenance and lands in the right personal project.
That’s an Ingestion Template:
- Admin/platform side: a curated catalog row (slug, source identifier, credential
schema, optional
ottlRules). Platform-published rows ship emptyottlRules— Claude Code, Cursor, and Claude cowork all emit OpenTelemetrygen_ai.*canonical spans natively, so no transform is needed for the common case. Org admins can clone a platform-default template into an org-authored template and author OTTL via the OttlEditor at/settings/governance/tool-catalog → Ingestion Templates → Clone to customise → Edit OTTL, to adapt a template to their org’s upstream-tool quirks (an internal IDE wrapper, a custom Cursor build, etc). Platform rows are read-only — admins click Clone to customise which callsingestionTemplates.cloneFromPlatform, then Edit OTTL on the new org-authored row to refine the rules. - User side: a binding token (
ik-lw-…) scoped to your personal project. You paste that token into your tool’s OTLP exporter; the tool ships, the receiver attributes- applies the resolved template’s OTTL (empty for platform defaults, admin-authored for org forks).
Worked example: connect Claude Code on Anthropic 20x
This walks through the whole flow end-to-end. By the end you’ll have a Claude Code trace visible at/me/traces with gen_ai.usage.*, gen_ai.response.model, and
langwatch.cost.usd populated.
Before you start: you need a LangWatch account. If you’re brand new, start with the
getting started guide and then sign in to
LangWatch. First-time sign-in completes onboarding and lands you on your personal
workspace (/me). On self-hosted instances the same path works against your own
deployment’s host.
Step 1: open the catalog
Navigate to/me and scroll to the Trace Ingest section (or jump straight to
/me#trace-ingest).

Step 2: install the Claude Code template
Click Install on the Claude Code tile. A drawer slides in headed Connect Claude Code, auto-shaped, with the subcopy “Traces normalized into gen_ai.* canonical. Cost/tokens/model populated automatically by the receiver.”
- OTLP endpoint: read-only, copyable.
- Binding token:
ik-lw-…issued one-time, with a Show/Hide toggle. Copy it while it’s visible; after you dismiss the drawer it’s masked to its first 9 characters. - Snippet preview: pre-wired environment variables for Claude Code:
(Self-hosted: replace the host with your LangWatch base URL. The drawer always shows the correct endpoint for your instance.)
The token is shown one-time. If you lose it, rotate the binding from the tile to mint
a new one. The previous token is invalidated immediately when you rotate (hard-cut v1).
Step 3: fire your first Claude Code action
Open a new terminal so the env vars take effect, then run Claude Code as you normally would. As soon as Claude Code completes its first action, OpenTelemetry exports the span to your LangWatch personal workspace.Step 4: see the trace at /me/traces
Click View traces → on the tile, or navigate directly to/me/traces.

gen_ai.system = "anthropic"gen_ai.request.model = "claude-3-5-sonnet"(or whichever model you ran)gen_ai.usage.input_tokens, emitted directly by Claude Code’s OTel exporter (Claude Code is gen_ai-canonical natively; v1 templates apply no OTTL transform).gen_ai.usage.output_tokens, same.langwatch.cost.usd, derived by the receiver’scanonicalCostExtractorfrom the upstream-emittedgen_ai.usage.*+gen_ai.response.model.langwatch.user.id,langwatch.project.id,langwatch.template.id,langwatch.user_ingestion_binding.id,langwatch.source = "claude_code", all receiver-stamped post-auth (authoritative attribution + template provenance).
Under the hood
This section is for engineering leads, security reviewers who want to understand the trust model and the request flow. End users can skip ahead to Raw OTLP fallback.Anatomy of an Ingestion Template
AnIngestionTemplate row has:
slug(e.g.claude_code), referenced by user bindings.sourceType(e.g.claude_code), which upstream tool this template parses.credentialSchema(closed enum, v1:null,static_api_key,agent_id), what fields the install drawer captures from the user.ottlRules, an optional OTTL transform applied to the span before the receiver’s authoritative re-stamp pass. Platform-default templates ship emptyottlRulesbecause Claude Code, Cursor, and Claude cowork all emit OpenTelemetrygen_ai.*canonical spans natively, there is nothing to reshape for the common case. Org admins can fork a platform-default template into an org-authored template and author OTTL via the OttlEditor in/settings/governance/tool-catalog → Ingestion Templates → Edit OTTL. Forking lets the admin adapt a template to their org’s upstream-tool quirks (an internal IDE wrapper, a custom Cursor build, a corporate Claude Code variant) without filing a request for a platform change.organizationId,NULLfor platform-published templates (visible everywhere); set for org-authored templates (visible only to that org). Forks created via “Edit OTTL” land here.
credentialSchema shapes
| schema | what the install drawer captures | covers v1 |
|---|---|---|
null | nothing, drawer auto-issues the binding token | claude_code, cursor, claude_cowork, raw_otlp_advanced |
static_api_key | one labeled API key field | (deferred to v1.1+) |
agent_id | a labeled agent-identifier text input | (deferred to v1.1+) |
oauth_redirect and s3_bucket are reserved for a future iteration, those require
upstream OAuth refresh, polling, watermark infrastructure that isn’t in the v1 push-only
shape.
Receiver resolution flow
When your tool emits an OTLP payload withAuthorization: Bearer ik-lw-<token>, the
receiver:
- Prefix-discriminates the bearer,
ik-lw-*→ UserIngestionBinding lookup. - Hashes the token (SHA256) and looks up the binding by
bindingAccessTokenHash(B-tree indexed; sub-millisecond on PG). - Defense-in-depth re-verifies that the binding’s project is personal AND its team’s owner is the binding’s user. (This catches row-level integrity-violation scenarios where the binding row has been tampered out-of-band.)
- Sets
tenantIdtobinding.personalProjectId, token-as-scope. This is authoritative. - Applies
template.ottlRulesunder a snapshot+restore principal-field guard. For platform-default templates the rules are empty so this step is a no-op; for org-authored forks the admin’s OTTL runs here under the protection lists below. - Post-auth re-stamps the 19 closed
protectedTemplateAttributeKeys(and, for org-authored OTTL, the tier-of-trust additions covering cost, tokens, model) as receiver-authoritative. If the OTTL tried to write any of those keys, the original value is restored and an audit rowgateway.template_ottl_protected_field_attemptfires with the rejected-key list. - Hands off to the trace pipeline, same path as every other ingest source from here.
What the principal-field guard protects
TheprotectedTemplateAttributeKeys closed list (19 keys, v1):
- The 16
protectedAttributeKeysfrom the base OTTL guard (B6), all attribution shapes:langwatch.user.id,langwatch.team.id,langwatch.organization.id,langwatch.project.id,langwatch.tenant.id, virtual-key shapes, ingestion-source shapes, governance shapes. langwatch.template.id, receiver-stamped provenance.langwatch.user_ingestion_binding.id, receiver-stamped provenance.langwatch.source, receiver-stamped provenance (used for tile filtering at/me/traces).
langwatch.cost.usd,.input,.outputgen_ai.usage.input_tokens,.output_tokens,.total_tokensgen_ai.response.model
canonicalCostExtractor reading upstream-emitted gen_ai.usage.*). Platform-default
templates ship empty ottlRules, so the protected list is dormant on this path.
For org-authored templates (forks created via the OttlEditor) the receiver
applies a tier-of-trust addition: the org-authored OTTL is allowed to reshape
upstream-specific attrs into the canonical keys (that’s the template’s whole job),
but langwatch.cost.usd*, gen_ai.usage.*, and gen_ai.response.model are pinned
to receiver-authoritative values via canonicalCostExtractor to prevent within-org
cost-attribution forgery.
See Security model recap below for the per-tier trust
boundary articulation.
Raw OTLP fallback
If you have a custom telemetry pipeline, your own spans, your own normalisation, your own cost calculations, you don’t want a template’s OTTL rewriting your shape. Use the Raw OTLP (advanced) card on/me Trace Ingest instead.
The card deep-links to the Personal OTLP Endpoint panel at /me/settings#otlp,
which surfaces your personal-project’s existing OTLP endpoint and API key for ad-hoc /
custom telemetry. No template OTTL is applied; your spans land at /me/traces exactly
as you emit them.

When to choose Raw OTLP vs a template
| You should pick | When |
|---|---|
| Claude Code, Cursor, Claude cowork tile | You run that tool and want LangWatch’s catalog OTTL to normalise the spans for you. |
| Raw OTLP (advanced) | You have a custom pipeline, or your spans already follow gen_ai.* conventions, or you want to keep your own field shapes. |
/me/settings → Personal OTLP Endpoint
without going through the catalog tile.
Security model recap
For security reviewers evaluating the feature.Trust boundary
- Token = scope. The
ik-lw-*binding token authoritatively determines which personal project a trace lands in. Payload-level claims about user, team, org, project attribution are advisory and re-stamped post-OTTL. - Cross-bind guard at install is structural:
bindingService.installdoes not acceptpersonalProjectIdas input. The server resolves the user’s personal project viagetPersonalProjectForUser(userId). Cross-user binding is unrepresentable. - Cross-bind guard at receive is the post-OTTL principal-field re-stamp. Forge attempts
emit
gateway.template_ottl_protected_field_attemptaudit rows.
Trust boundary: two tiers
LangWatch v1 ships two distinct template tiers with different trust contracts: Tier 1, Platform-default templates (organizationId IS NULL). Empty ottlRules.
Cost, tokens, model values come directly from the upstream tool’s OTel exporter
(Claude Code, Cursor, and Claude cowork all emit gen_ai.* canonical natively), and the
receiver derives langwatch.cost.usd from those upstream-emitted values via
canonicalCostExtractor. Trust here rides on upstream-tool correctness: we trust
Claude Code, Cursor, and Claude cowork to populate gen_ai.usage.* correctly per the
OTel semantic-conventions spec.
Tier 2, Org-authored templates (organizationId NOT NULL, forked from a tier-1
template via the OttlEditor at /settings/governance/tool-catalog → Ingestion Templates → Edit OTTL). Admins author OTTL to adapt a template to their org’s
upstream-tool quirks. Trust here rides on org-admin review at save time: the
admin who clicks “Save & validate” is accepting within-org responsibility for the
transform’s correctness. Three protection layers prevent admin OTTL from being
weaponized against the org or other orgs:
- The 19-key
protectedTemplateAttributeKeysguard at receive time (attribution + provenance, admin OTTL cannot rewrite who/where/which-template a trace came from). - A tier-2 superset that adds
langwatch.cost.usd*,gen_ai.usage.*, andgen_ai.response.modelto the protected set so admin OTTL cannot forge cost- attribution within the org. - Static analysis at save time, the OttlEditor’s “Save & validate” step rejects OTTL that would write any protected key BEFORE the rules are persisted, with an inline error pointing at the offending line.
scripts/dogfood/emit-otlp.sh, including forge-attempt regressions against both the
19-key and tier-2 protected lists, and (b) a real-user track, admin publishes via
/settings/governance/tool-catalog, a real user installs via /me, the real upstream
tool emits a real trace, and the result is verified end-to-end with cross-user isolation.
Per-template rituals live at langwatch/ee/governance/ingestion-templates/<slug>/dogfood.md.
What is audited
State-change rows only, per-trace activity is tracked vialastSeenAt on the binding
row, not via audit volume.
| Event | When fires |
|---|---|
gateway.user_ingestion_binding.installed | User installs a template via the catalog tile |
gateway.user_ingestion_binding.uninstalled | User uninstalls a binding |
gateway.user_ingestion_binding.integrity_violation | Defense-in-depth re-verify fails (row-level tamper) |
gateway.template_ottl_protected_field_attempt | Template OTTL tried to rewrite a 19-key protected field |
gateway.ingestion_template.updated | (v2 surface) Admin edits a template’s OTTL |
governance_ocsf_events ClickHouse table for
SOC2, ISO27001 evidence collection.
What is not audited
- Per-trace landings (volume reasons;
lastSeenAtcarries the activity signal) - Token rotation (the new token’s installed/uninstalled lifecycle is the audit signal)
- Credential-content edits on
static_api_key,agent_idtemplates (PII boundary, matches the existing API-key edit pattern)
Frequently asked questions
Does LangWatch see my Anthropic OAuth token?
No. Claude Code holds your Anthropic OAuth session locally; LangWatch never participates in that flow. The only credential LangWatch holds is the binding token (ik-lw-…) we
issue you, which is scoped to your personal project.
What happens if I rotate the binding token?
Hard-cut v1: the previous token is invalidated immediately. Update your tool’sOTEL_EXPORTER_OTLP_HEADERS with the new token before continuing. (A grace-period
rotation lands in a future iteration if SOC2 review requests.)
Can my org admin see my personal-workspace traces?
No, not via this feature. Personal-project traces are scoped to your personal project; the admin’s drill-in path (governance dashboards) requires the explicit drill-in flow described in the governance dashboard docs and is logged + persistent-banner’d. Templates do not change that.What if my tool isn’t in the catalog?
For this iteration we ship 3 tool-specific templates (Claude Code, Cursor, Claude cowork) plus the Raw OTLP (advanced) fallback. If your tool emits OTLP natively, the Raw OTLP fallback works today. If you’d like a custom template for another tool, file a request on GitHub Issues and we’ll evaluate.Verifying the contract
The full admin OTTL authoring flow has a Playwright real-user dogfood atlangwatch/e2e/admin-ottl-dogfood.ts (~30s loop), 8 steps end-to-end:
navigate → list 3 platform rows → View OTTL drawer → Clone-to-customise →
Save OTTL → list 4 rows → Edit OTTL → Archive. Pairs with the
service-level integration test at
langwatch/ee/governance/services/__tests__/ingestionTemplate.authoring.integration.test.ts
and the wire-level REST integration test at
langwatch/src/app/api/governance/__tests__/governance-rest-api.integration.test.ts.
If you’re touching the IngestionTemplatesEditor surface, the OttlEditor
component, or the IngestionTemplateService, run the dogfood + both
integration tests locally as a regression playbook before opening a PR.
Related
- Personal Workspace: broader personal-workspace feature surface (Datasets, Evaluations, Annotations, Automations).
- Personas: how admin drill-in works (and why it doesn’t see personal-workspace traces by default).
- Governance REST API: the same IngestionTemplate surface, exposed over Hono REST/JSON for agentic workflows.
specs/ai-gateway/governance/ingestion-templates-catalog.featureand siblings, the BDD specs that lock this feature’s behaviour.