Skip to main content
Metadata makes a trace findable. Stamp the agent, user, session, tags, and your own attributes on spans, and Surface Area displays them in the dashboard and filters on them.

Semantic conventions hold the attribute keys

The tracing.semconv module holds attribute-key constants in the gateway.* namespace. Set them on a span with set_attribute().
The constants used most often:
Setting input= on a tracing.trace(...) block sets TRACE_INPUT for you, and input= on tracing.span(...) sets OBSERVATION_INPUT. Set the output constant explicitly inside the block.

Declare the agent once

One process runs one agent. Pass it to tracing.init(agent=...) and the SDK stamps every trace with the agent. You never hand-stamp the agent per span.
Pass a dict (or an AgentIdentity) to add a name and version alongside the id.
The agent also resolves from the environment when you do not pass it: GATEWAY_AGENT_ID, GATEWAY_AGENT_NAME, and GATEWAY_AGENT_VERSION. Declaring an agent also registers it with the Surface Area control plane in the background, so it appears on the Agents page before its first trace.

Attach the user

Call gatewaysdk.identify() to attribute the current trace, and every span that runs after it in the same context, to an end user. One call from your request handler tags the whole request.
Pass profile fields alongside the id to enrich the user record. Surface Area merges the attributes into the user’s profile in the background, which suits slow-changing facts like plan or account value.
The profile update needs GATEWAY_HOST, GATEWAY_PUBLIC_KEY, and GATEWAY_SECRET_KEY to reach the platform. Trace attribution (tagging spans with the user id) works without them.

Set the user without identify()

The user is also ambient: it resolves from the GATEWAY_USER_ID environment variable and is stamped on every span. Set the USER_ID attribute on a span to override the ambient default for that span.
Set GATEWAY_USER_ID for single-user processes: a CLI or a per-user worker. For a multi-tenant service, leave it unset and call identify() (or set the USER_ID attribute) per request from your auth context.

Tag traces and set environment

Tags label traces for filtering. Set them across a block with tracing.tracing_context(tags=[...]), which applies to every span created inside, including auto-instrumented LLM calls.
Set the environment label at init so it applies to the whole process, or per block with tracing_context(environment=...).
The environment label lands on the trace’s resource attributes and powers the Environment filter in the sessions and traces tables.

Add custom metadata

Set any key/value attribute directly on a span for data the built-in constants do not cover.
You can also pass extra attributes as keyword arguments when you open a span or tool.
To make custom metadata filterable in the sessions and traces tables, prefix the key with gateway.trace.metadata., since Surface Area hoists prefixed attributes into trace metadata that the tables query. For example, s.set_attribute("gateway.trace.metadata.tenant", "acme") adds a filterable tenant field.

Screenshots on spans

A span can carry an image: upload the bytes and put the returned reference into the span’s input or output. The trace view shows it inline.
The reference looks like @@@langfuseMedia:type=image/png|id=…|source=bytes@@@. TypeScript has the same MediaUploader in @withgateway/sdk/tracing. Native computer use does this for you: each computer action is a computer.<action> span whose output holds the screenshot after it.

Where to go next