Per-request metadata
Every successful response from the gateway carries a top-level
lowrouter_metadata field:
{
"id": "chatcmpl-...",
"choices": [...],
"usage": {...},
"lowrouter_metadata": {
"provider": "openai",
"region": "eu-west",
"energy_wh": 0.0021,
"carbon_gco2e": 0.00057,
"carbon_intensity_gco2_per_kwh": 270,
"estimation_methodology": "ecologits-calculated",
"routing_mode": "auto",
"routing_reason": "lowest_carbon_intensity",
"fallback_occurred": false,
"providers_attempted": ["openai"]
}
}Two kinds of values appear in this block, and they don’t carry the same weight:
- Recorded — facts about the routing decision LowRouter itself
made:
provider,region,routing_mode,routing_reason,fallback_occurred,providers_attempted,requested_alias. The region is the one whose endpoint we called; what that guarantees about data residency beyond the routing itself is defined by the upstream provider’s own terms. - Estimated — modeled numbers:
energy_wh,carbon_gco2e,carbon_intensity_gco2_per_kwh. Produced per the methodology from annual grid averages, and absent rather than fabricated when we can’t classify the request.
Field reference
provider
The upstream that actually served the request. Matches an id in
GET /providers (a discovery endpoint) and the provider segment of a
model ID.
region
The region the upstream served from. Strings like eu-west,
us-east, us-west. The region is the one encoded in the resolved
model ID’s locode.
energy_wh
Total energy estimated for the request, in watt-hours. Computed from the resolved model’s per-token energy coefficients and the request’s token counts. See methodology.
carbon_gco2e
Total CO₂e estimated for the request, in grams. Derived from
energy_wh, the data-center overhead (PUE 1.20), and the grid
intensity for the serving region.
carbon_intensity_gco2_per_kwh
The grid carbon intensity used for the serving region, in grams of CO₂e per kWh.
estimation_methodology
Identifies how the estimate was produced (e.g. an EcoLogits-based calculation). Present when an estimate was made.
routing_mode
auto when the router chose the route for you (an
auto/<creator>/<model> request), explicit when you named the
provider and region yourself.
routing_reason
Why the router landed where it did. For an auto-routed request this is
one of eu_sovereign_preferred, lowest_carbon_intensity,
lowest_cost, round_robin, or only_route. See routing.
fallback_occurred
true if the route changed after selection. LowRouter does not
silently substitute providers — an explicit ID is a pin and an
auto-routed request commits to the winner of its ranking — so this
reads false on current traffic. It stays on the response, and in
your usage export, because historical rows can carry true.
providers_attempted
The list of providers tried for this request, in order.
requested_alias
Present only when the request addressed a
model alias ("model": "alias/big"). Carries the alias as
sent (alias/big), while the response’s top-level model field
carries the full model ID the alias resolved to. Absent on
non-aliased requests.
Worked scenario: “why did this request go to us-east?”
Your dashboard shows one row served from us-east in a week of
otherwise-EU traffic. The metadata of that response answers it without
guesswork:
"lowrouter_metadata": {
"provider": "openai",
"region": "us-east",
"routing_mode": "auto",
"requested_auto": "auto/openai/gpt-4.1",
"routing_reason": "lowest_carbon_intensity",
"eu_sovereign": false,
"providers_attempted": ["openai"]
}Read it as a trace: you sent auto/openai/gpt-4.1, so the route was
LowRouter’s to choose, and eu_sovereign: false says plainly that no
sovereign route existed for that model — auto-routing prefers
EU-sovereign providers in EU/EEA regions, but falls through rather
than failing when a model has none. routing_reason then names what
decided among what was left. Nothing was misrouted, and nothing was
silently substituted: providers_attempted lists one provider.
If a US route is unacceptable for that workload, this is the signal to
move it from auto/ to a pinned model ID or an alias: an
explicit route fails loudly instead of falling back outside your
constraint. See routing for the pinning syntax.
Headers
The gateway sets an X-Request-ID header on every response. Use it to
correlate a request with your own logs or when reporting an issue.
Streaming
For streamed requests, lowrouter_metadata arrives on the final
chunk (the one before [DONE]), carrying the same fields as the
non-streaming block. Earlier chunks don’t include it. See
first completion → streaming.
When metadata is partial
The eco fields (energy_wh, carbon_gco2e,
carbon_intensity_gco2_per_kwh) can be absent when:
- The resolved model’s parameter count is unknown and we’d rather omit the number than fabricate one.
- The request consumed no tokens (e.g. a non-completion response).
- The upstream returned an error mid-stream that prevented usage accounting.
When they’re missing, the dashboard shows the row with a — for the
carbon column and a note linking to the methodology page. The routing
fields (provider, region, routing_mode, …) are still present.
Privacy
The lowrouter_metadata block contains nothing about prompt or
response content — only the resolved route and the metric estimates. It
is safe to log on the client side; we do.
