Spanlens
Open-source LLM observability you can turn on in one line. Point your OpenAI, Anthropic, or Gemini client at Spanlens and every call is logged with cost, tokens, latency, and full agent traces. No SDK rewrite, no platform migration. Eleven providers supported, plus native Vercel AI SDK, LangChain, and LlamaIndex integrations, and you can query it all from Cursor or Claude Desktop through the bundled MCP server. Self-hostable in one Docker command. MIT.
Why it exists. I shipped an LLM app on OpenAI and Gemini and hit a wall. The provider dashboards showed total spend and nothing else. I could not tell which feature burned the most tokens, which model was cheapest per task, or what each endpoint actually cost. Spanlens is the layer I wanted. It turns on in one line, stays off the critical path, and is open source so you can self-host the exact code we run.
⭐ If Spanlens is useful to you, please star the repo. It takes a second, and it is the single biggest thing that helps other developers find the project.
Hosted: spanlens.io · npm:
@spanlens/sdk· PyPI:spanlens· CLI:@spanlens/cli· MCP:@spanlens/mcp-server· Status: status.spanlens.io · Changelog: spanlens.io/changelog

Live demo (no signup): spanlens.io/demo/requests


Why Spanlens?
- Helicone was acquired and its roadmap is uncertain.
- Langfuse is powerful but complex to set up and expensive to scale.
- Spanlens ships the 20% of features that cover 80% of real production needs. You get request log, cost tracking, agent tracing, anomaly detection, PII scanning, and prompt versioning with a clean UI, a two-minute setup, and pricing that doesn't punish growth.
| Spanlens | Langfuse Pro | Helicone | |
|---|---|---|---|
| Open source | ✅ MIT | ✅ MIT | ✅ MIT |
| Self-hostable | ✅ Docker one-liner | ✅ | ✅ |
| Free tier | 50K req/mo | 50K events/mo | 10K req/mo |
| Team plan (1M req/mo) | $149/mo | $271/mo | ~$200/mo |
| Agent tracing | ✅ | ✅ | ⚠️ limited |
| LLM-as-judge evals | ✅ | ✅ | ❌ |
| PII + injection scan | ✅ | ❌ | ❌ |
| Model recommendations | ✅ | ❌ | ❌ |
| Prompt A/B experiments | ✅ | ✅ | ❌ |

Predictable bills, no quota cliff. Free hits a hard 429 at 50K requests so a runaway loop in dev can't cost you money. Paid plans use a soft limit with authorized overage (Pro: +$8 / 100K, Team: +$5 / 100K) up to a hard cap you control, so a traffic spike charges you fairly instead of dropping requests.
Seats: Free 1 · Pro 3 · Team 10 · Enterprise unlimited. Unlimited projects on every paid tier.
⭐ Like where this is going? A star helps more developers find a lightweight, open alternative in a space full of heavy, acquired tools.
⚡ Quick start in 30 seconds
TypeScript / JavaScript (Next.js)
npx @spanlens/cli init
The wizard:
- Installs
@spanlens/sdkwith your package manager (npm / pnpm / yarn / bun) - Writes
SPANLENS_API_KEYto.env.local - Rewrites every
new OpenAI({ apiKey, baseURL })intocreateOpenAI()
Paste your Spanlens API key once, confirm two prompts, done. Your LLM calls are now flowing through the Spanlens proxy and visible in www.spanlens.io/requests.
Manual TypeScript setup
import { createOpenAI } from '@spanlens/sdk/openai'
const openai = createOpenAI() // reads SPANLENS_API_KEY, uses Spanlens proxy baseURL
Python
pip install "spanlens[openai]"
from spanlens.integrations.openai import create_openai
client = create_openai() # reads SPANLENS_API_KEY from env
res = client.chat.completions.create(
model="gpt-4o-mini",
messages=[{"role": "user", "content": "Hello"}],
)
For agent tracing in Python (multi-step, async, tool calls) see the Python SDK README.
Framework integrations
Already using an orchestration framework? Plug Spanlens in as a callback. No code rewrites.
Vercel AI SDK (Next.js / edge friendly)
import { SpanlensClient } from '@spanlens/sdk'
import { createSpanlensTracker } from '@spanlens/sdk/vercel-ai'
const tracker = createSpanlensTracker({
client: new SpanlensClient({ apiKey: process.env.SPANLENS_API_KEY! }),
modelName: 'gpt-4o',
})
await generateText({
model: openai('gpt-4o'),
messages,
onStepFinish: tracker.onStepFinish,
onFinish: tracker.onFinish,
})
LangChain JS / LangGraph
import { createSpanlensCallbackHandler } from '@spanlens/sdk/langchain'
const handler = createSpanlensCallbackHandler({ client })
await chain.invoke({ input }, { callbacks: [handler] }) // LangChain
await graph.invoke({ input }, { callbacks: [handler] }) // LangGraph
LlamaIndex TS
import { Settings } from 'llamaindex'
import { registerSpanlensCallbacks } from '@spanlens/sdk/llamaindex'
const unregister = registerSpanlensCallbacks(Settings, { client })
// ... run queries ... unregister() on shutdown
Python: LangChain: from spanlens.integrations.langchain import SpanlensCallbackHandler. Same BaseCallbackHandler contract, works with chains, LCEL, and LangGraph.
More integrations: AWS Bedrock, CrewAI, Flowise, Instructor, LlamaIndex, OpenAI Assistants, MCP server. Full setup walkthroughs at spanlens.io/docs/integrations.
Ollama (local LLMs): Ollama runs on your machine, so it does not go through the hosted proxy. Get a ready client with createOllama() and wrap each call with observeOllama() so the span is logged and tagged as Ollama.
import { SpanlensClient } from '@spanlens/sdk'
import { createOllama, observeOllama } from '@spanlens/sdk/ollama'
const spanlens = new SpanlensClient({ apiKey: process.env.SPANLENS_API_KEY! })
const ollama = createOllama() // points at http://localhost:11434/v1
const trace = spanlens.startTrace({ name: 'chat' })
const res = await observeOllama(trace, 'chat', (headers) =>
ollama.chat.completions.create(
{ model: 'llama3.1', messages: [{ role: 'user', content: 'Hello' }] },
{ headers },
),
)
await trace.end({ status: 'completed' })
What you see

Every request logged with model, provider, latency, tokens, cost, and full prompt + response body. Filter, search, export. Streaming responses reconstructed automatically.
What you get
| Feature | Description |
|---|---|
| Request log | Every LLM call logged with model, tokens, cost, latency, and full request/response body (streaming reconstructed too) |
| Agent tracing | Multi-step workflows as Gantt waterfall span trees with Critical Path highlighted (the longest dependency chain across a fan-out, not just the slowest single span), plus a node-and-edge graph topology view for LangChain / LangGraph callback traces |
| Cost tracking | Per-request cost breakdown with daily rollups and budget alerts. Prompt-cache tokens (cache_read / cache_creation on Anthropic, prompt_tokens_details.cached_tokens on OpenAI) are parsed separately and billed at the discounted rate so you can see actual cache savings, not just sticker price |
| Per-end-user analytics | Tag calls with x-spanlens-user (SDK: withUser() / with_user()) and the /users page shows per-user cost, tokens, errors, models, last seen |
| Anomaly detection | 3σ deviations in latency, cost, or error rate vs. your 7-day bas |