Skip to main content
Glassray’s metadata convention is three reserved fields with first-class support. They land on every trace as filterable tags, so you can slice flows, deviations, and searches by who a run was for and what it did — and beyond them you can attach any custom attributes and filter by those too:
This is one standard with two ways in: traces pushed by the SDK and traces pulled from Langfuse, LangSmith, or PostHog carry the same three tags, so dashboards and filters work identically regardless of how a trace arrived.
Which project a trace lands in is decided by the ingest key, not by any attribute you set — a trace lands in the project of the source (ingest key) that ingested it. The old environment field no longer routes traces and is ignored; use a separate source per project (prod, staging, …). See Projects.

Defaults at construction, overrides per trace

Set the values that are fixed for the process on the constructor; override the ones that vary per run in the trace’s meta. A per-trace value always wins over the constructor default.
In practice: agent is a constructor default, customer is per-trace (it varies with each run), and flow is optional either way.

What it becomes in Glassray

Each field lands as a trace tag (customer:acme-corp, agent:support-agent, …) at ingest — the same filterable index the rest of the dashboard uses. flow is a hint: Glassray’s own flow classification remains the authority for grouping traces.
On the wire these are the glassray.* resource attributes (with a root-span override), which matters only if you bring your own OTel — the SDK sets them for you.

Custom attributes

The three reserved fields aren’t the whole story: attach any custom attributes and filter your traces by them in the dashboard — by merchantId, branch, region, or whatever your traces already carry. Set per-process defaults on the constructor and add or override per trace in meta.attributes:
Then in the Traces view, Add filter → Attribute lists every custom attribute your traces carry, so merchantId is acme narrows the stream to one merchant.
Values are scalar (string / number / boolean). A per-trace attribute overrides a constructor default of the same key (it rides the root span). Reserved keys — glassray.*, gen_ai.*, and OTel infra prefixes like service.* / session.* — are dropped with a warning so a custom attribute can never shadow a first-class field.
Two ways in, same result. Custom attributes work identically for pulled traces: whatever metadata your Langfuse / LangSmith / PostHog traces already carry is picked up automatically — no SDK required, no re-ingest. High-cardinality id-shaped values (UUIDs, hashes, long ids) are kept on the trace but not offered as filter options, so the picker stays useful.