Drop an AI-agent trace (OTLP, OpenInference or Jaeger JSON, or a zip of them) into your browser and debug the run — nothing uploaded, nothing installed, shareable as a link.
OTLP JSON
Jaeger JSON
OpenInference JSON
Flame graph
Timeline
LLM-aware
Local-first
The trace file viewer for AI agents — private by architecture. Someone hands you a trace file, a CI artifact or a bug-report attachment, and you can't or won't send it to a backend. Open it in WideScope and debug the run in your browser: waterfall, flame graph, conversation and span details, with LLM tokens and costs.
Use it alongside your observability platform: for trace files, CI artifacts, bug-report attachments and data that must not leave your machine.
Built with Rust/WASM and Svelte. The trace is parsed and rendered in your tab.
No backend. No upload. No telemetry. Even sharing is serverless — a small or medium trace travels inside the link. Just your traces, in your browser.
Observability platforms such as Langfuse, Arize Phoenix and LangSmith ingest traces from your running services and keep them for search, evals and dashboards. WideScope is the companion for the cases where a trace exists as a file:
| You have… | Use |
|---|---|
| A trace file from CI, an export, or a bug report, and no backend to ingest it into | WideScope |
| Trace data that must not leave your machine | WideScope (nothing is uploaded) |
| A small or medium trace you want to hand to someone as a link | WideScope (the link carries the trace; a large one falls back to a download or a hosted ?trace= URL) |
| Live traffic your team already ingests, with retention, search and evals | Your observability platform, plus WideScope for traces you export from it as OTLP, OpenInference or Jaeger JSON |
- Open widescope.soumendrak.com and hit Open WideScope (or go straight to /editor/)
- Click Load sample trace (or Sample in the editor drawer)
- Explore the waterfall, flame graph, conversation, and span details
- Or drag in your own OTLP / Jaeger / OpenInference trace JSON
Sample trace files are available in test-fixtures/ if you want to test locally.
- Four synchronized views — canvas flame graph, service-lane timeline (non-LLM traces; LLM traces get a Conversation view in its place), waterfall with critical-path highlighting, and a service dependency graph.
- Fast navigation — span search, attribute queries with operators (
duration>100ms,status=error), filters by service / status / kind / LLM-only, keyboard traversal, zoom, pan, fit/reset, and trace slicing. - Scales to large traces — virtualized timeline rows, level-of-detail collapsing in the flame graph, and progressive loading of multi-MB files behind a phase-by-phase progress bar.
- LLM-aware inspection — resolves OTel GenAI, OpenInference, and LangChain-style attributes into model, token, prompt/completion, and tool-call detail views.
- Cost & token analytics — per-span cost estimates, performance budgets (duration, P95 latency, cost, error and span counts), critical path, a multi-trace stats dashboard (latency, errors, counts), and a latency heatmap mode in the flame graph.
- Trace diff — load two runs side by side and see per-stage deltas; the matrix view compares a batch of runs metric by metric against a baseline, and session grouping groups related traces in the trace switcher.
- Zero backend — a static page plus a WASM binary; served as Cloudflare Workers static assets (
wrangler.jsonc), and deployable to any CDN or static host. There is no server to trust because there is no server at all. - No upload, no telemetry — parsing and rendering happen entirely in your tab. There is no ingest endpoint, no cookies and no analytics, and trace data never leaves the tab. The viewer connects out only when you ask it to: fetching a
?trace=<url>, or streaming spans from a?live=<url>event source. - Sharing without a backend — a share link carries the whole compressed trace in its URL fragment, which browsers never send to any server. See Sharing traces.
- Formats — OTLP JSON (
resourceSpans), Jaeger JSON (data[].spans), and OpenInference JSON (spans). - Flexible loading — drag and drop, file picker, clipboard paste, hosted URL,
.json/.jsonl/.ndjsonfiles or a zip of them, or the built-in JSON editor with live parsing. - Ecosystem — VS Code extension, embed mode for external tools, span annotations, and PNG / SVG export.
WideScope can produce a link that reopens the exact trace, view, and selected span you are looking at.
- Self-contained link — click 🔗 Share in the toolbar. The trace is DEFLATE-compressed — seeded with a dictionary built from representative traces and embedded in the WASM binary, so small traces compress especially well — and packed into the URL
#fragment, which browsers never send to a server, so the data stays private. Best for small and medium traces; large traces are flagged with a one-click Download trace fallback. To rebuild the dictionary after adding fixtures, runjust train-share-dict(see the recipe's notes on the format-tag bump). - Hosted trace — open
https://widescope.soumendrak.com/editor/?trace=<url>to fetch a trace JSON from any HTTPS URL (CI artifact, gist, object storage). - Deep links — both forms accept
view=<flame|timeline|conversation|waterfall|graph|agent|diff|analytics|matrix|dashboard>andspan=<id>to restore the view mode and pre-select a span.matrixanddashboardare multi-trace views: they only apply when more than one trace is loaded, and the ⋯ menu only offers them then. A link opens a single trace, soview=matrixshows a "Load 2+ traces" prompt andview=dashboardsummarizes just that one trace. - Legacy links — share links minted before the viewer moved to
/editor/(e.g./?trace=…or/#trace=…) are redirected there by the landing page, so old links keep working.
AGENTS.md is the single reference for setup (with the tool versions CI pins), the just commands and the standards gate that CI runs. Two notes it doesn't cover:
- Homebrew Rust users: the Homebrew Rust package has no
wasm32-unknown-unknowntarget. Install Rust withrustupinstead (both can coexist; prefix commands withPATH="$HOME/.cargo/bin:$PATH"). wasm-opt(binaryen) is optional. The build succeeds without it, but the.wasmis larger.
GitHub Actions only runs checks; it does not deploy. wrangler.jsonc describes the site for Cloudflare: static assets served from ui/dist/, plus a custom build command that installs the toolchain and runs make build.
-
From your machine:
npx wrangler deployruns that build command and publishesui/dist/. -
From Git: Cloudflare's Git builds do not run the
wrangler.jsoncbuild command, andmake buildon its own fails there: the build image has no Rust orwasm-pack, nothing runsnpm ciforui/, and the repo has no rootpackage.json. In the Cloudflare dashboard, set the build command to the command below, which installs theui/dependencies, Rust with thewasm32-unknown-unknowntarget, andwasm-pack, then runsmake build. Set the deploy command tonpx wrangler deploy.npm ci --prefix ui && if ! command -v cargo >/dev/null 2>&1; then curl https://sh.rustup.rs -sSf | sh -s -- -y; fi && if [ -f "$HOME/.cargo/env" ]; then . "$HOME/.cargo/env"; fi && if command -v rustup >/dev/null 2>&1; then rustup target add wasm32-unknown-unknown; fi && if ! command -v wasm-pack >/dev/null 2>&1; then cargo install wasm-pack --locked; fi && make build
This is
build.commandfromwrangler.jsoncwith the JSON escaping removed (\"becomes"); pasting the escaped string breaks the[ -f "$HOME/.cargo/env" ]check. Keep the two in sync when either changes.
Set a custom domain in Cloudflare if you want the repo website field to use your own domain.
Recommended repo website value after setup: your custom domain, or
https://widescope.<your-subdomain>.workers.dev
- Open
http://localhost:5173in development, or deployui/dist/to Cloudflare or any static host. The marketing landing page is served at/; the trace viewer lives at/editor/. - Load trace JSON by pasting into the editor, clicking Open file, dragging in a
.jsonor.zipfile, or using Load sample trace. - Use Sample, Paste, Clear, and Format in the editor drawer as needed. Parsing is live as you type;
Cmd/Ctrl + Entercollapses the editor. - Switch views from the tabs in the top bar (Waterfall, Flame, Timeline or Conversation for LLM traces, Graph, Diff), with more lenses under ⋯.
- Search spans from the toolbar to highlight matches and jump between them.
- Click any span to inspect details in the resizable right sidebar.
- In the flame graph, use Cmd/Ctrl + scroll to zoom, drag to pan, double-click to zoom to a span, and use
↑↓←→,Enter,Esc,F, and0for keyboard navigation.
widescope/
├── justfile # build automation
├── Cargo.toml # workspace root
├── rust-toolchain.toml # stable toolchain + wasm target
├── crates/
│ ├── widescope-cli/ # headless CLI (analyze, compare, check)
│ └── widescope-core/ # Rust WASM library
│ ├── src/
│ │ ├── lib.rs # wasm-bindgen exports and trace lifecycle
│ │ ├── models/ # span, trace, llm, and layout types
│ │ ├── parsers/ # OTLP, Jaeger, and OpenInference JSON parsers
│ │ ├── conventions/ # convention registry + attribute resolver
│ │ ├── layout/ # flamegraph and timeline layout algorithms
│ │ ├── trace_builder.rs # trace assembly, warnings, self-time, cycles
│ │ └── errors.rs # structured errors returned to JS
│ └── pkg/ # generated by wasm-pack
├── ui/ # Svelte 5 + Vite app shell
│ ├── index.html # marketing landing page (served at /)
│ ├── editor/index.html # trace viewer entry (served at /editor/)
│ ├── src/
│ │ ├── App.svelte # root shell and trace editor workspace
│ │ ├── components/ # toolbar, graphs, sidebar, drop zone, banners
│ │ ├── lib/ # wasm loader, input handling, bundles, TS types
│ │ └── stores/ # trace and selection state
│ ├── public/ # logo, fonts, icons, llms.txt, _headers
│ └── package.json
├── conventions/ # OTel, OpenInference, and LangChain mappings
├── test-fixtures/ # sample traces
└── docs/ # design docs
| Format | Status |
|---|---|
OTLP JSON (resourceSpans) |
✅ Supported |
Jaeger JSON (data[].spans) |
✅ Supported |
OpenInference JSON (spans) |
✅ Supported |
Newline-delimited OTLP JSON (.jsonl / .ndjson, the Collector file exporter's output) |
✅ Supported |
OpenInference JSON traces are now parsed natively. Convention mappings for LLM attribute normalization across OTel, OpenInference, and LangChain are bundled for all formats.
Attribute-to-LLM mappings live in conventions/ and are bundled into the UI at build time. Three mapping files are included:
| File | Covers |
|---|---|
opentelemetry.json |
OTel GenAI semconv (gen_ai.*) |
openinference.json |
OpenInference attributes (llm.*, openinference.span.kind) |
langchain.json |
LangChain attributes (langchain.*) |
Convention resolution is first-match-wins. See conventions/README.md to extend the mapping set.
Contributions are welcome! See CONTRIBUTING.md for the architecture overview, step-by-step guides for adding parsers, views, and conventions, and the PR checklist.
Quick version:
- Open an issue to discuss the change before working on it (optional but appreciated).
- Fork the repo and create a branch:
fix/descriptionorfeat/description. - Run the checks in AGENTS.md before opening a PR.
just checkmust end withSTANDARDS OK. - Open a PR against
mainwith a clear description of what changed and why.
Questions or ideas? Open an issue.
If this project helps you, consider sponsoring my work on GitHub. Your support helps fund maintenance, documentation, and continued development.
