Skip to content

Web (Browser) SDK

The Pionne SDK for the browser. Auto-captures JS errors and unhandled promise rejections, enriches every event with browser context (URL, viewport, locale, User-Agent).

Current version: 0.3.6

Terminal window
npm install @pionne/web

Or via CDN with a <script> tag:

<script src="https://unpkg.com/@pionne/web@latest/dist/pionne.umd.js"></script>

Initialise the SDK as early as possible — ideally before your app renders, in main.ts or a <script> at the top of <head>.

import { Pionne } from '@pionne/web';
Pionne.init({
token: 'pio_live_…',
release: '1.0.0',
environment: 'production',
sampleRate: 1.0,
scrubPii: true,
});
Pionne.init(options);
Pionne.captureException(error, { tags, contexts });
Pionne.captureMessage('Something went wrong', { level: 'warning' });
Pionne.setUser({ id: 'user_42' });
Pionne.setTags({ feature: 'checkout' });
Pionne.setEnabled(false); // kill switch
Pionne.addBreadcrumb({ category: 'ui', message: 'Click on #buy' });
Pionne.wrap(fn); // wrap a callback to capture its throws
  • window.onerror — uncaught exceptions
  • window.onunhandledrejection — promises rejected without .catch()
  • User-Agent, viewport (width/height), locale (navigator.language)
  • Current URL, referrer
  • Release, environment
  • console.log / console.warn / console.error
  • fetch() — URL with query string stripped
OptionTypeDescription
tokenstringPionne token (pio_live_…)
releasestringApp version
environmentstringproduction, staging, etc.
sampleRatenumber0.0 — 1.0, fraction of events sent
scrubPiibooleanMask emails, phones, IBANs
beforeSend(event) => event | nullFiltering hook
sendGeographybooleanOpt-in: IP-side geo (city/region/country) attached to every event. Default false.
geographyEndpointstringIP→geo lookup URL. Default https://ipapi.co/json/.

Pionne can attach the visitor’s approximate city/region/country to every event — useful to spot a regression localised to one country or ISP. Off by default for privacy.

Pionne.init({
token: 'pio_live_…',
sendGeography: true, // ← opt-in
});

How it works:

  • A single HTTP call at startup to https://ipapi.co/json/ (4 s timeout).
  • The result (city, region, country, ISO country code) is cached and joined to every event under contexts.geo.
  • If the lookup fails (offline, adblock, rate-limit), the SDK silently keeps shipping events without geo.
  • No GPS coordinates, no persistent tracking — just the visitor’s IP reverse-lookup.

Want your own provider? Pass geographyEndpoint: 'https://geo.yourapi.com/' — any URL returning JSON { city, region, country, country_code } (or country_name) works.

main.tsx
import { Pionne, PionneErrorBoundary } from '@pionne/web';
import ReactDOM from 'react-dom/client';
import App from './App';
Pionne.init({ token: 'pio_live_…' });
ReactDOM.createRoot(document.getElementById('root')!).render(
<PionneErrorBoundary fallback={<p>Oops, we crashed.</p>}>
<App />
</PionneErrorBoundary>
);

Like in React Native, prod builds are minified. To get readable stacks, upload your source maps:

Terminal window
npx @pionne/web upload-sourcemaps \
--release 1.0.0 \
--dir ./dist \
--token pio_live_…

You can also automate via a Vite or Webpack plugin — see the Source maps guide. The concept is universal: only the build tool changes.

Bundle ID pinning is mobile only (iOS/Android/RN/Flutter) — it protects against APK/IPA decompilation. On the web, your token lives in an env var bundled by your bundler (VITE_PIONNE_TOKEN, NEXT_PUBLIC_PIONNE_TOKEN…) and is trivially extractable from the shipped JS — bundle pinning can’t help there.

The “Bundle ID” field is hidden in the mobile dashboard for Web projects. To limit abuse:

  • Regenerate the token (with a 24 h grace period) if you suspect a leak — see Tokens.
  • Per-token rate-limit server-side — see Rate limits.
  • Tags to differentiate deployments / environments:
Pionne.init({
token: import.meta.env.VITE_PIONNE_TOKEN,
tags: { deployment: 'prod', tenant: window.location.host },
});

More details: Bundle ID Pinning → Backends without bundle_id.