Latitude can route spans to different projects based on how each capture is configured. Most SDKs already set a project at startup; this page covers the additional knobs available when one process needs to emit to multiple projects (for example, a service that runs several agents that should each show up as a distinct Latitude project).Documentation Index
Fetch the complete documentation index at: https://docs.latitude.so/llms.txt
Use this file to discover all available pages before exploring further.
The resolution chain
For every span Latitude ingests, the server applies this order (highest priority first):- Span attribute
latitude.projectSet bycapture({ projectSlug })in the TypeScript SDK orcapture({"project_slug": ...})in Python. The slug travels on the span itself, so a single OTLP export can carry spans for multiple projects. - OTEL resource attribute
latitude.projectFor bare-OpenTelemetry setups: setlatitude.projectonce on the SDK’sResourceand every span inherits it. - HTTP header
X-Latitude-ProjectThe Latitude SDKs send this automatically when aprojectSlugis passed to the constructor. Acts as the per-batch default.
Response contract (OTLP partial_success)
Latitude follows the OTLP specification for
partial-success responses. Customers writing their own exporters can rely on these guarantees:
| Batch shape | HTTP status | Body |
|---|---|---|
| All spans resolve | 200 OK | empty ExportTraceServiceResponse |
| Some spans rejected (mixed) | 200 OK | partialSuccess { rejectedSpans: N, errorMessage: "..." } |
| Every span rejected | 400 | google.rpc.Status shape: { code: 400, message: "..." } |
| Malformed OTLP payload | 400 | { error: "..." } |
partialSuccess only appears on 2xx responses — it means “some spans were
persisted, here is a count of what we dropped”. When nothing was persisted we return a
plain google.rpc.Status-shaped error body so exporters don’t mistakenly treat the rejection
as a partial save.
The errorMessage always points back to this page so an exporter that logs the response
gives operators a single place to look. Don’t move this page without coordinating a
server-side update — the URL is hard-coded in the ingest error response.
Patterns
Three runnable examples ship with each SDK. Start with the one that matches your shape.1. Single-project default (existing setup)
For services that emit to exactly one Latitude project. The ctorprojectSlug is sent on
every export as X-Latitude-Project, and every capture() inherits it.
TypeScript — see examples/test_project_scoping_single.ts:
examples/test_project_scoping_single.py:
2. Multi-project from day 1 (no ctor default)
For services that emit to multiple Latitude projects — e.g. one process that runs several agents. Skip the ctorprojectSlug and set projectSlug on every capture().
TypeScript — see examples/test_project_scoping_multi.ts:
examples/test_project_scoping_multi.py:
capture() that doesn’t set projectSlug AND a SDK that doesn’t have a ctor default →
the spans are rejected with partialSuccess. Pick one of the two so every span has a route.
3. Per-span override on top of a default
Most common when the default project comes from an env var but specific runs need to route elsewhere (e.g. shipping evaluation runs to a separate project). TypeScript — seeexamples/test_project_scoping_env.ts:
examples/test_project_scoping_env.py:
Handling partial_success in custom exporters
If you’re integrating from bare OpenTelemetry (no Latitude SDK) and want to surface
rejections, watch for partialSuccess.rejectedSpans > 0 in the OTLP response body. The
common causes:
- Missing
latitude.projecton the span AND noX-Latitude-Projectheader on the export. - The resolved slug doesn’t exist in your organization (typo, or a stale slug after the project was renamed).