Import from Braintrust
Connect Braintrust on the Imports page. Metergraph imports spans in a
project’s logs whose span_attributes.type is llm, then keeps the
selected project level with Braintrust on a schedule.
What is imported
Section titled “What is imported”Braintrust reads LLM spans through the POST /btql query endpoint. Task, tool,
function and eval spans are not imported, and scores and evals are never read.
What you need
Section titled “What you need”| Credential | A Braintrust API key, sent as a bearer token |
| Scope | A project name or project id, at most 255 characters (import_connections.py, MAX_SCOPE_LENGTH) |
| Host | https://api.braintrust.dev, the US data plane, by default. Use https://api-eu.braintrust.dev for the EU plane, or your own data plane (import_connections.py, SOURCE_POLICIES; imports.js, baseUrlHelp) |
The hosted importer stores the credential encrypted and does not need a
Metergraph ingest key. The relay appendix is the path that uses an ingest key
(import_providers/__init__.py, module docstring).
Create a Braintrust key
Section titled “Create a Braintrust key”In Braintrust, open Settings, go to Organization > API keys, select
+ API key, give the key a name, and select Create. Copy the key when it
is shown because Braintrust does not show it again. Use the sk-... API key,
not a provider key from AI providers.
The key inherits the creator’s Braintrust permissions, so the creator must have Read permission on the project and its logs. A service token with the same project Read access also works. See Braintrust’s API key and service token instructions and access control documentation.
Connect on the Imports page
Section titled “Connect on the Imports page”-
Select Braintrust
Section titled “Select Braintrust”Open Imports, select Connect, and choose Braintrust.
-
Enter the project and key
Section titled “Enter the project and key”Enter the project name or id and a Braintrust API key with permission to read that project’s logs. The project field is limited to 255 characters (
import_connections.py,MAX_SCOPE_LENGTH). -
Set the range and schedule
Section titled “Set the range and schedule”Import from defaults to 7 days ago and cannot be in the future. On hosted Metergraph it cannot be more than 90 days back; a self-hosted operator can set that floor from 1 to 366 days (
imports.js,defaultInitialSince;config.py,scheduled_imports_max_backfill_days). Run defaults to Every minute. The picker offers Every minute, Every 5 minutes, Every 15 minutes, Every 30 minutes, Every hour, Every 6 hours and Daily. Braintrust has a 1-minute floor and a one-day ceiling (imports.js,INTERVAL_OPTIONS;import_connections.py,CURSOR_MINIMUM_INTERVAL_SECONDS,MAX_INTERVAL_SECONDS,DEFAULT_INTERVAL_SECONDS). -
Set the host when needed
Section titled “Set the host when needed”Leave API base URL blank for the US data plane. Open Self-hosted Braintrust to enter
https://api-eu.braintrust.devfor the EU plane or your own data plane. The endpoint must behttps://and reachable from the public internet (imports.js,baseUrlHelp;import_egress.py,check_url). -
Test and connect
Section titled “Test and connect”Optionally select Test connection. It checks the key and project with the provider within 6 seconds (
braintrust.py,probe,TEST_TIMEOUT_SECONDS). Then select Connect. Connect saves the project and credential without contacting Braintrust. If the workspace already has a checkpoint for the source and project, the connection resumes from it rather than the start date (api/import_connections.py,create_import_connection). -
Check the first rows
Section titled “Check the first rows”On Imports, inspect Imported through, Calls in selected range, Rows pushed per run, Success rate, Next run and Run history. Then open Traces and check the provider, model, tokens, status, route and timestamp.
What lands in Metergraph
Section titled “What lands in Metergraph”| Field | Where it comes from |
|---|---|
| Route | The LLM span’s own name, falling back to braintrust/backfill. The hosted import has no route override. --route is relay-only |
| Timestamp | The span’s created time, kept as the original |
| Provider and model | Inferred from the span |
| Tokens | The span’s metrics, including cache reads, cache writes and reasoning |
| Cost | Braintrust’s estimated_cost |
| Latency | The span’s own start and end |
| Status | error when the span recorded an error, otherwise success |
| Content | The span’s input and output, copied verbatim |
| Tool calls and tool names | Extracted from the span’s output |
| Trace, span and parent span | The span’s root span id, span id and first span parent |
| Tags | Braintrust span tags under braintrust_tags, and the project id under braintrust_project_id |
What does not carry over
Section titled “What does not carry over”- Environment. Braintrust rows arrive with no environment set, so they fall outside any environment filter in the dashboard.
- Function attribution, streaming detail, outcomes and repository identity, as on every import path.
- Task, tool, function and eval spans, scores and evals, which are never read.
Troubleshooting
Section titled “Troubleshooting”| Symptom | Likely cause | What to do |
|---|---|---|
| Test connection says “Braintrust refused the key” | The key is invalid, revoked, cannot read the project, or was sent to the wrong data plane (Braintrust answered 401 or 403) | Check the key, the project’s Read permission, and the base URL, then test again |
| Test connection says “Braintrust could not run the query” | The project name or id does not match a project in the key’s organization (Braintrust answered 400 or 404) | Copy the exact project name or id from Braintrust, then test again |
| A scheduled run says “Braintrust could not run the query” | The project name or id does not match a project in the key’s organization, or the key creator cannot read the project logs | Copy the exact project name or id from Braintrust and verify the creator has Read access to the project and its logs |
| Test connection says “Could not reach Braintrust at” | The base URL is wrong or unreachable | Check the URL and public internet reachability (import_egress.py) |
A failed hosted run says lease released |
The importer released its coordination lease after a provider request failed (metergraphrelay/provider_sync.py) |
Fix the key, project, permissions or data plane, then retry. The lease message is cleanup, not the root cause |
| The endpoint is refused | The hosted egress policy blocks a private, loopback, link-local or metadata address | Use a public endpoint, or use the relay appendix (import_egress.py, module docstring) |
| The query times out | Relay only: a pull has no --since on a large project |
Relay only: bound every pull query with --since |
Every route is OpenAI Chat Completion |
Relay only: the SDK wrapper names spans after the method | Relay only: pass --route |
| Nothing comes back from an EU project | Relay only: the relay is querying the US data plane | Relay only: set BRAINTRUST_BASE_URL=https://api-eu.braintrust.dev |
These are Braintrust errors. A 401 or 403 from Metergraph instead means
the Metergraph token is not an ingest key. See the shared
import troubleshooting.
Appendix: relay commands
Section titled “Appendix: relay commands”Use the relay when the hosted importer cannot reach the Braintrust data plane, or when you need relay-only selector behavior. Set the US or EU base URL in the relay setup as needed.
Backfill: pull, then push
Section titled “Backfill: pull, then push”metergraphrelay pull braintrust --project my-project \ --since 2026-08-01T00:00:00Z --output braintrust.jsonlmetergraphrelay push braintrust.jsonl| Selector | Meaning |
|---|---|
--project |
Required project name or id. Repeatable |
--since / --until |
Bound span created time. --since is inclusive and --until is exclusive |
-n, --count |
Caps spans, not traces. The default is 100 (braintrust.py, PAGE_LIMIT) |
--route |
Relay-only route override |
Scheduled: sync
Section titled “Scheduled: sync”metergraphrelay sync braintrust --source-scope my-project \ --initial-since 2026-08-01T00:00:00Z --project my-project--source-scope is a permanent label for the project and selector set.
--initial-since seeds only the first run. The relay and hosted paths share a
checkpoint for the same source and scope, so do not run both against one
scope. The full contract is in the overview appendix.