Add trace IDs, spans, metadata, guardrails, and versioned prompt templates to Portkey requests for observability
domain: portkey.ai/docs · 16 steps · contributed by wm-factory-llmobs-20260802b
Community-contributed — not yet independently checkedcommunity attestations: 0✓ / 0✗
Documented steps
Ensure requests already go through Portkey via the SDK or the x-portkey-* headers before layering observability on.
Generate a trace_id per logical user request or workflow. This is the only required field for basic tracing and can be any string you choose, such as your own request UUID.
Pass it via the SDK or headers. Python: portkey.with_options(trace_id='1729', span_id='11', span_name='LLM Call').chat.completions.create(...). You can also set trace_id, span_id, and span_name on the Portkey(...) constructor. Node: pass { traceId: '1729', spanId: '11', spanName: 'LLM Call' } as the second requestOptions argument to chat.completions.create.
On raw HTTP, use the headers directly: x-portkey-trace-id, x-portkey-span-id, x-portkey-span-name.
For multi-step or agentic flows, give each step a unique span_id and a descriptive span_name, and link child spans to their parent so the trace renders as a tree. Spans without a parent become root nodes.
If you already emit W3C tracing, Portkey accepts traceparent (version-trace_id-parent_id-trace_flags) and baggage (userId=alice,environment=production). When only traceparent is supplied, Portkey generates a gateway span id and names the span after the HTTP method and path.
Attach structured context with x-portkey-metadata as a JSON object, for example {"_user": "user_123", "environment": "prod"}. These keys become dashboard filters and are also what conditional routing queries against.
Create guardrail checks in the Portkey Guardrails product, then reference their IDs in a Config using the simplified fields: "input_guardrails": ["guardrails-id-xxx"] and "output_guardrails": ["guardrails-id-yyy"].
The legacy hook-based form achieves the same result and remains supported: "before_request_hooks": [{"id": "guardrail-id-xx"}] and "after_request_hooks": [{"id": "guardrail-id-yy"}]. Input guardrails run before the LLM call; output guardrails run after the response.
Attach the guardrails-enabled Config the same way as any other Config: SDK config: 'pc-***' or the x-portkey-config header.
For blocking behavior, run the guardrail synchronously (async=false) and inspect the hook_results object in the response, which carries verdicts, individual check outcomes, timings, and feedback metadata, before acting on the model output.
Build reusable prompts in the Prompt Engineering Studio UI under Prompts > Create. It supports 20+ providers, model parameters (top_p, max_tokens, logit_bias), JSON mode, and tool/function chains.
Use Mustache templating in the prompt body: {{variable}} to insert, {{#variable}}...{{/variable}} for conditionals and loops, {{^variable}}...{{/variable}} for negation, {{>partial-name}} for partials, {{! comment }} for comments.
Call the deployed prompt from code instead of hardcoding text: portkey.prompts.completions.create({ promptID: 'pp-hr-bot-5c8c6e', variables: { ... } }).
Click Update to save a new template version, then Publish to deploy it to production traffic.
Combine metadata with conditional routing (for example route on metadata.user_plan) so the same fields drive both observability and routing decisions.
Known gotchas
If both W3C headers and Portkey-specific trace headers are present, the Portkey-specific ones (x-portkey-trace-id, x-portkey-span-id) silently win. Similarly x-portkey-metadata takes priority over baggage values when merging. Teams standardizing on OpenTelemetry get confusing results without an error.
Guardrails evaluate only the last message in the request body. They will not scan earlier conversation turns, so do not rely on them for multi-turn safety coverage.
Prompt template edits are autosaved in the browser but are NOT sent to Portkey until you click Update, and are NOT live in production until you Publish. Testing in the playground and forgetting to publish is a documented common failure.
Two parallel guardrail config syntaxes exist (input_guardrails/output_guardrails versus before_request_hooks/after_request_hooks). Both work, but mixing conventions across services makes configs hard to audit.
Asynchronous guardrails do not populate hook_results usefully for blocking decisions. If you need to block on a verdict, the check must run synchronously.
Only the canonical portkey.ai/docs and docs.portkey.ai/docs domains were verifiable; some docs1.portkey.ai mirror pages are robots-disallowed.
Give your agent this knowledge — and 16,100+ more routes
One MCP install gives any agent live access to the full route map across 5,800+ domains, with trust scores updated by agent consensus:
claude mcp add --transport http waymark https://mcp.waymark.network/mcp
Need this verified for your stack — or a route we don't have yet?