@pionne/web
v0.3.6
Published
Error monitoring SDK for the browser — Pionne. Auto-captures uncaught errors and unhandled rejections, ships client context (UA, viewport, locale), tracks Release Health (crash-free user rate), and exposes a feedback API.
Downloads
1,093
Maintainers
Readme
@pionne/web
Error monitoring SDK for the browser — by Pionne.
Auto-captures uncaught errors and unhandled promise rejections, ships rich client context (UA, OS, viewport, locale, URL), and survives page unloads via navigator.sendBeacon. ~3 KB gzipped, zero dependencies, no source maps required.
Works in any browser app — plain JS, React, Vue, Svelte, Angular, Next.js, Astro, etc.
🎫 Get your token
Pionne is mobile-first: you sign up, create projects, and watch your error feed from the Pionne mobile app, not a web dashboard.
- Download the app:
- 🍎 App Store (coming soon)
- 🤖 Google Play (coming soon)
- Create your account (30 days free, no card required)
- + New project → pick Web → copy the token displayed (
pio_live_…) - Paste it into
Pionne.init({ token })below
⚠️ The token is only shown once at project creation — store it in an env var (VITE_PIONNE_TOKEN, NEXT_PUBLIC_PIONNE_TOKEN, etc.) and never commit it.
Install
npm install @pionne/webUsage
React / Next.js / Vite
// main.tsx (or _app.tsx for Next, root.ts for Remix…)
import { Pionne } from '@pionne/web';
Pionne.init({
token: 'pio_live_xxx',
release: '1.0.0', // optional
// environment auto-detected (localhost → development, else production)
});That's it. JS errors and unhandled promise rejections are now reported automatically.
Manual capture
try {
doRiskyThing();
} catch (err) {
Pionne.captureException(err, { tags: { feature: 'checkout' } });
}
Pionne.captureMessage('user reached empty state', { level: 'info' });User identity (anonymous)
Pionne.setUser('u_42'); // appears on every event afterward
Pionne.setUser(null); // forgetTags
Pionne.setTags({ tier: 'pro', region: 'eu' });Opt-out
Pionne.setEnabled(false);Profiling — preview (coming soon)
Continuous-ish CPU profiling is shipped on @pionne/[email protected]
(Hermes sampler) and is on the roadmap for @pionne/web next. The browser
implementation will use Performance.profile() (Chrome only, behind a flag
in Firefox/Safari) and fall back to Performance.measure()-based manual
spans where the sampler isn't available.
The API will mirror RN exactly so you can reuse the same wrappers across platforms:
// Coming in @pionne/web ~v0.4.0
await Pionne.profile('CheckoutFlow', async () => {
await fetchCart();
await submitOrder();
}, { route: '/checkout' });Same backend (POST /api/profiles), same retention model (raw 7 d,
aggregates 90 d), same flame graph view in the mobile dashboard.
If you need profiling today in a browser, you can post your own samples to the endpoint directly — the JSON shape is documented at pionne.agkgcreations.fr/profiling/intro.
Bundle ID pinning — N/A on Web
The "Bundle ID" anti-token-theft check on Pionne projects is mobile only
(iOS/Android/RN/Flutter). On the web, your token is shipped in the bundled
JS and trivially extractable from the browser — bundle pinning can't help.
The field is hidden in the mobile dashboard for Web projects; don't set
it manually via the API — the SDK does not send a top-level app_id,
so a non-null bundle_id would 403 every event. To limit abuse: regenerate
the token (24 h grace period) if you suspect a leak, and rely on the
per-token rate limit server-side. Use tags for
deployment/tenant differentiation. See the
Bundle ID Pinning docs.
Geography (opt-in)
Approximate visitor location (city, region, country) attached to every event,
just like Sentry. Off by default for privacy — flip sendGeography to enable:
Pionne.init({
token: 'pio_live_xxx',
sendGeography: true,
});Resolved once at startup via a free IP→geo lookup (ipapi.co/json by
default), with a 4 s timeout. If the lookup fails the SDK silently keeps
shipping events without geo. Override the endpoint via geographyEndpoint
if you have your own.
Options
| Option | Type | Default |
| ---------------------------- | -------------------------- | ------------------------- |
| token | string (required) | — |
| endpoint | string | Pionne production |
| release | string | unset |
| environment | string | localhost-detected |
| enabled | boolean | true |
| captureUncaughtErrors | boolean | true |
| captureUnhandledRejections | boolean | true |
| autoContext | boolean | true |
| userIdAnon | string | unset |
| tags | Record<string, string> | unset |
| maxStackFrames | number | 50 |
| beforeSend | (event) => event \| null | unset (drop if null) |
| sendGeography | boolean | false |
| geographyEndpoint | string | https://ipapi.co/json/ |
| releaseHealth | boolean | true |
| maxEventsPerSecond | number | 10 |
Notes
maxEventsPerSecond— token-bucket client. Au-delà, les events sont droppés silencieusement. Protège contre lessetIntervalqui throw en boucle.0désactive (déconseillé).releaseHealth— ouvre une session àinit()pour calculer le crash-free user rate. Désactivable.sendGeography— opt-in : attachecontexts.geo(city/region/country/country_code) résolu IP-side. Pas de geolocation API, pas de permission.
Rate limit serveur
Indépendamment du maxEventsPerSecond client, l'API Pionne applique un rate-limit par token sur tous les endpoints publics. Au-delà → HTTP 429 avec un header Retry-After. Empêche un token leaké de drainer ton quota mensuel. Voir doc rate limits.
License
MIT
