Trace inlets
A trace inlet is a connector that pulls trace data out of a tracing tool you already run — Langfuse or Braintrust — into Neens on a schedule. Each external trace is mapped into the Neens Session / Span / Tool-call model and fed through the normal ingest path, so clustering, judges, scores, remediations, and every other Neens feature run on top of it with no change to how your agent is instrumented.
This is the brownfield on-ramp: keep your tracing tool, add the Neens brain. You don’t re-instrument your agent or move off your incumbent observability stack — you point Neens at it and Neens starts diagnosing failures from the traces that already exist.
Inlets pull in; external API scoring reaches out. These are opposite directions and easy to confuse. An inlet is inbound — Neens fetches traces from Langfuse/Braintrust into your tenant. An external API judge/enrichment is outbound — Neens calls out to a third-party HTTP API to score a trace it already has. Use an inlet to get traces in; use external API scoring to attach a signal.
At a glance
| Where | Settings → Trace inlets (admin-only tab) |
| Providers | Langfuse, Braintrust |
| Key API | GET/POST /trace-inlets, PATCH/DELETE /trace-inlets/{id}, POST /trace-inlets/{id}/test, POST /trace-inlets/{id}/sync |
| Direction | Inbound — Neens polls the provider and ingests new traces on a schedule |
| Auth to the provider | Langfuse: Public key + Secret key · Braintrust: API key + Project ID (encrypted at rest) |
| Scope | Agent-scoped — traces land in the connector’s agent, exactly like a direct ingest |
| Egress safety | Every fetch is SSRF-gated; provider cloud hosts work out of the box |
Add a connector
Adding a connector is admin-only — inlet credentials are sensitive external-system secrets, so the tab and its API require the admin role.
Open Settings → Trace inlets
Go to Settings → Trace inlets and click Add. Pick the provider — Langfuse or Braintrust.
Fill in the common fields
Every connector, whatever the provider, has:
| Field | Meaning |
|---|---|
| Name | A label for this connector in the list. |
| Base URL | The provider API origin (see the per-provider setup below). |
| Poll interval (minutes) | How often Neens syncs this connector. Default 15. |
| Backfill days | How far back the first sync reaches. Default 7. |
| Enabled | Off by default — a new connector is created disabled so you can Test it before it starts syncing. |
Add the provider credentials
Enter the provider-specific keys (below). Credentials are write-only: they’re encrypted the moment you save and are never shown again. When you edit a connector later, leave a credential field blank to keep the stored secret; type a new value only to replace it.
Test before you enable
Click Test. Neens makes one bounded, SSRF-gated call to the provider and reports an honest
result — ok with a small sample count, or the real error (401 for a bad key, a timeout, or a
blocked host). Fix any problem, then turn Enabled on.
Enable and let it sync — or sync now
Once enabled, the connector syncs automatically on its poll interval. To pull immediately, click Sync now; Neens runs one bounded sync and shows how many traces were ingested.
Langfuse setup
| Field | Value |
|---|---|
| Base URL | https://cloud.langfuse.com for Langfuse Cloud, or your self-hosted Langfuse origin (e.g. https://langfuse.internal). |
| Public key | Your Langfuse project’s Public Key (pk-lf-…). |
| Secret key | Your Langfuse project’s Secret Key (sk-lf-…). |
Find both keys in Langfuse under Project Settings → API Keys. Neens authenticates to the
Langfuse public API with HTTP Basic auth (public key as username, secret key as password) and reads
traces and their observations from the /api/public/traces endpoints.
What maps. Each Langfuse trace becomes a Neens trace; each observation becomes a span:
- A
GENERATIONobservation → an LLM span, carrying the model name and prompt/completion token counts. - A tool-like
SPANobservation → a TOOL span. - Other observations → CHAIN / AGENT spans.
- An observation at
ERRORlevel marks its span as failed and carries the status message as the error.
A self-hosted Langfuse URL resolves to a private/internal address, so it’s refused by the SSRF
gate — see Security. Langfuse Cloud
(cloud.langfuse.com) is a public host and works with no extra configuration.
Braintrust setup
| Field | Value |
|---|---|
| Base URL | https://api.braintrust.dev (Braintrust Cloud), or your self-hosted Braintrust API origin. |
| API key | A Braintrust API key. |
| Project ID | The Braintrust project whose logs to pull. |
Neens authenticates with a bearer token (Authorization: Bearer <api key>) and fetches from the
project-logs API (/v1/project_logs/{project_id}/fetch).
What maps. Braintrust log events are grouped by their root span id into traces, and each event becomes a span:
- An event whose type is
llm→ an LLM span, with model and token counts from its metrics. - An event whose type is
toolorfunction→ a TOOL span. - Other event types → CHAIN spans.
How syncing works
Neens periodically syncs the enabled connectors that are due — whose last run is older than
their poll interval (default 15 minutes, set per connector).
- First sync — backfill. The first sync of a connector reaches back backfill days (default
7) and pulls the traces in that window. - Incremental syncs. After that, each sync fetches only traces newer than the last successful high-water mark (with a small overlap so nothing on the boundary is missed), advancing an opaque provider cursor as it goes. A failed sync does not advance the cursor, so the next run retries the same window — you never lose traces to a transient error.
- Idempotent re-ingest. Ingested traces keep their stable provider trace/span ids, and the Neens ingest path is idempotent on those ids. Re-pulling an overlapping window (or re-running a sync) never duplicates data — the same trace resolves to the same session.
- What lands. Ingested traces appear on the Traces & sessions page and flow into clustering, continuous evaluation, and everything downstream — indistinguishable from traces sent directly.
The connector list shows each connector’s last status (ok / error / never), when it last
synced, how many traces the last run ingested, and the last error inline if a sync failed.
Security
Inlets are built to be a zero-migration, zero-new-egress-risk on-ramp:
- Credentials encrypted at rest. Every provider secret (the Langfuse secret key, the Braintrust API key) is Fernet-encrypted before it’s stored and is never returned by any API — the connector responses report only whether a credential is set, never its value.
- SSRF egress gate. Every outbound fetch (and the Test probe) is validated against the same
gate as the other Neens outbound integrations: the host is resolved and pinned, redirects are not
followed, and a private, loopback, link-local, or reserved address is refused. Provider cloud
hosts (
cloud.langfuse.com,api.braintrust.dev) are public and reachable out of the box; a self-hosted provider on a private address is gated by default and an operator must allowlist its host. - No data leaves your tenant. An inlet only pulls in. Traces are ingested straight into the connector’s agent inside your tenant; nothing about your traces is sent back out to the provider or anywhere else.
Limits
Each sync is bounded so a single connector can never overwhelm a worker or the broker: a connector ingests up to 500 traces per run (a larger backlog drains across several runs), each provider response body is capped at 8 MiB, and a single outbound HTTP call is allowed 30 seconds.
Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
Test returns 401 | Wrong or revoked provider keys. | Re-copy the keys from the provider’s project settings and re-save (leave a field blank to keep the stored one). |
| Test says the URL is blocked | A self-hosted provider resolves to a private address. | Ask an operator to allowlist the host — a provider on a private address is gated by default. |
| Connector is enabled but nothing ingests | It isn’t due yet, or the first backfill window predates your traces. | Click Sync now, or raise Backfill days and sync again. |
| The Trace inlets tab isn’t there | You’re not an admin. | Ask an admin. |
A sync shows error with a real message | A transient provider/network failure. | The cursor didn’t advance — the next sync retries the same window; fix the root cause shown in the last error. |
See also Send traces for direct ingest and the framework quickstarts if you’d rather instrument your agent to send to Neens natively.