otel-zoneless-context weekly downloads statistics
By adityareddy-dev · npm · Webpack plugins
OpenTelemetry context manager for the browser without zone.js, plus a bundler plugin that rewrites the awaits in your code so the active context comes back after each one
otel-zoneless-context has 191 recorded weekly downloads on npm, ranking #1604 of 2,309 tracked listings.
About otel-zoneless-context
otel-zoneless-context
An OpenTelemetry context manager for the browser, no zone.js, that keeps concurrent flows apart across a native await in code the plugin rewrites, as of 2026-10-08. Zoneless managers already exist. Splunk's RUM SDK and Elastic's EDOT browser both ship one, and they carry the context by patching Promise.prototype.then and the callback APIs. A native await on a native promise doesn't go through the patched then though, so the context is gone after the first await. What this package adds is a bundler plugin that rewrites each await in your code to put the context back when the function resumes. The manager itself is a changed copy of the Apache-2.0 SplunkContextManager from splunk-otel-js-web, see Credit.
Use
npm install otel-zoneless-context
import { WebTracerProvider } from '@opentelemetry/sdk-trace-web'
import { ZonelessContextManager } from 'otel-zoneless-context'
const provider = new WebTracerProvider({ spanProcessors: [/* yours */] })
provider.register({ contextManager: new ZonelessContextManager() })
Then the plugin, here for Vite:
// vite.config.js
import { vite as zonelessContext } from 'otel-zoneless-context/plugin'
export default {
plugins: [zonelessContext()],
}
otel-zoneless-context/plugin also exports rollup, webpack, esbuild, rspack and rolldown, and I haven't tested the last two. Options are include and exclude, a RegExp or a list of them. By default every .js, .mjs, .ts, .mts, .jsx and .tsx file outside node_modules gets rewritten. runtime sets where the helpers get imported from. The manager takes { patch: false } to leave the browser APIs alone.
What the plugin does
This:
async function load(id) {
const res = await fetch(`/items/${id}`)
return res.json()
}
comes out as:
import { settle as __ctxSettle, take as __ctxTake, save as __ctxSave, current as __ctxCurrent, restore as __ctxRestore } from "otel-zoneless-context/runtime";async function load(id) {let __ctxValue, __ctxBack;
const res = __ctxTake((__ctxValue = __ctxSettle(fetch(`/items/${id}`)), __ctxBack = __ctxSave(), __ctxValue = await __ctxValue, __ctxBack(), __ctxValue))
return res.json()
}
It runs before TypeScript and JSX are compiled and takes every async function, top level await and for await included. Files with no await are left alone.
Results
Run on 2026-10-09 on Windows in headless Chromium 156.0.8078.4 with @opentelemetry/api 1.9.1, @opentelemetry/sdk-trace-web and @opentelemetry/context-zone 2.12.0, zone.js 0.16.3, built with esbuild 0.28.2 to esnext so every await stays native. Every case except #5914 runs two flows, A and B, at the same time on timers that cross, and after each await checks that the active context is still its own. The leak row checks from code outside both flows that it sees no context at all. The #5914 row is the repro from that issue with the same function names, its console logs swapped for a check that the repro span is active.
| case | stack manager | zone manager | this one, plugin off | this one, plugin on |
|---|---|---|---|---|
| #5914 | 4/6 | 4/6 | 4/6 | 6/6 |
| two flows | 2/8 | 2/8 | 2/8 | 8/8 |
| leak | 3/3 | 3/3 | 3/3 | 3/3 |
| try catch finally | 0/6 | 0/6 | 0/6 | 6/6 |
| for loop | 0/6 | 0/6 | 0/6 | 6/6 |
| for await | 0/8 | 0/8 | 0/8 | 8/8 |
| nested async arrow | 0/6 | 0/6 | 0/6 | 6/6 |
| Promise.all | 0/4 | 0/4 | 0/4 | 4/4 |
| class method | 0/4 | 0/4 | 0/4 | 4/4 |
| startActiveSpan | 0/4 | 0/4 | 0/4 | 4/4 |
| .then callback | 0/6 | 2/6 | 2/6 | 6/6 |
| library callback | 0/4 | 0/4 | 0/4 | 2/4 |
| reject and resolve in one task, reject first | 0/2 | 0/2 | 0/2 | 2/2 |
| reject and resolve in one task, resolve first | 0/2 | 0/2 | 0/2 | 2/2 |
In #5914 the three others lose the span at test2 and general.end, the same two steps the issue reports. CI runs all of it on pushes to main and on pull requests and prints these tables in the log, the Node ones in their own job. Node has no window, so nothing gets patched there and the .then row stays at 2/6. Built through Rollup 4.64.3 and Vite 8.3.4 the plugin gets the same Node numbers as through esbuild, and through webpack 5.111.1 too. The tests assert the misses of the other managers too, so if one of them starts keeping the context the run goes red and this table gets fixed.
What it misses
- A library the plugin doesn't rewrite, which awaits and then calls back into your code. The callback saw no context in the test (the library callback row).
setTimeoutwith a delay over 34 ms doesn't carry the context. That's Splunk's cut-off and I kept it.- Each await gets one more promise and a closure. I haven't measured what that does to a real app.
- Angular CLI's default builder. I tried Angular 22.2.2 with @angular-builders/custom-esbuild 22.0.1 on 2026-10-09 and nothing got rewritten. That builder adds plugins after Angular's own compiler plugin, and that one loads every
.tsand.jsfile itself, so this plugin never sees the code. The older webpack builder (@angular-devkit/build-angular:browser) turns async functions into generators, which go through the patchedthen. In the same scratch app built that way the manager kept the context with nothing rewritten, 13 of 13 checks on the #5914 steps and two flows. - Not tested yet: rspack, rolldown,
yieldinside an async generator, async code downleveled to generators, and the plugin overnode_modules.
Credit…
Description from the npm listing.
- opentelemetry
- context-manager
- zoneless
- async-await
- browser
- vite-plugin
- rollup-plugin
- webpack-plugin
- esbuild-plugin
README badge
Show your rank in a README or on your website. The badge updates automatically.
Charts
Images: 30d · 1y · all time · 1600×900 dark
Adoption over time
7/30/90-day growth
Ranking history
Listing placement
Listing placement
Filled points are observed values; hollow points come from Internet Archive snapshots of the listing page. Dashed segments span periods with no observations — values between points are not interpolated.
Each band is one page of 20. Weekly downloads on a linear scale. Placement is projected from weekly downloads, so it can differ from the marketplace's own sort order. Hover a dot to see the listing.
Recent observations
Full history (2)Similar npm Webpack plugins plugins
All 20 otel-zoneless-context alternativesData source
Weekly downloads (trailing 7 complete days) come from the official npm downloads API. Downloads include CI and mirrors and are not equivalent to installs or users. npm publishes no ratings.
Listing: https://www.npmjs.com/package/otel-zoneless-context. First seen Oct 18, 2026; last successful collection Oct 20, 2026. See the methodology.