Install & initialize
Install @scalebun/web, initialize it with your client key, and choose a delivery path — npm, a CDN script tag, or Google Tag Manager.
Install the package#
npm i @scalebun/webpnpm add @scalebun/webyarn add @scalebun/webUsing a framework? Also add its adapter — see Framework adapters:
npm i @scalebun/web-react # or -next / -vue / -svelte / -angularInitialize#
Only clientKey and apiBaseUrl are required, and the config object is the same
everywhere. What changes per framework is where the call goes — pick yours:
import ScaleBun from '@scalebun/web';
await ScaleBun.init({ clientKey: 'skb_live_ck_…', apiBaseUrl: 'https://api.scalebun.com/api/v1', environment: 'production', release: '1.4.2',});Call trackScreen() on navigation and captureError() in your error handler —
that is all an adapter does for you.
import { ScaleBunProvider } from '@scalebun/web-react';
<ScaleBunProvider config={{ clientKey: 'skb_live_ck_…', apiBaseUrl: '…' }}> <App /></ScaleBunProvider>;One component: initializes the SDK once, installs the render-error boundary and
provides the in-app client. Pass routeName for screen tracking — React has no
router to read it from.
import { ScaleBunProvider } from '@scalebun/web-next';
export default function RootLayout({ children }) { return ( <html><body> <ScaleBunProvider config={{ clientKey: 'skb_live_ck_…', apiBaseUrl: '…' }}> {children} </ScaleBunProvider> </body></html> );}Drops straight into a Server Component layout — the provider carries its own
'use client'. Routes are automatic. app/error.tsx still needs
reportNextError, and server, RSC and edge errors need instrumentation.ts.
import { ScaleBunPlugin } from '@scalebun/web-vue';
createApp(App) .use(ScaleBunPlugin, { clientKey: 'skb_live_ck_…', apiBaseUrl: '…' }) .mount('#app');Render errors are automatic (the plugin chains app.config.errorHandler).
Routes are not — add router.afterEach(to => ScaleBun.trackScreen(to.name ?? to.path)).
<script> import { onMount } from 'svelte'; import { afterNavigate } from '$app/navigation'; import { setupScaleBun } from '@scalebun/web-svelte';
const scalebun = setupScaleBun({ clientKey: 'skb_live_ck_…', apiBaseUrl: '…' }); onMount(scalebun.start); afterNavigate(scalebun.navigated);</script>Errors go through SvelteKit's handleError hooks — wire both hooks.client.ts
and hooks.server.ts. Only SvelteKit can register those.
import { provideScaleBun } from '@scalebun/web-angular';
export const appConfig = { providers: [provideRouter(routes), provideScaleBun({ clientKey: 'skb_live_ck_…', apiBaseUrl: '…' })],};One provider does everything: routes and render errors are both automatic.
That is the whole setup. Integrations covers the rest of each adapter per framework — error-boundary props, feature-flag hooks, coachmark anchors, in-app slots, and server-side capture for Next and SvelteKit.
Client keys are prefixed so a key visibly declares its blast radius —
skb_test_ck_…, skb_staging_ck_…, skb_live_ck_…. Keys issued before the
prefixed scheme (scalebun_ck_…) remain valid.
Where init() runs#
| Runtime | What happens |
|---|---|
| Browser | Full capture. This is the normal case. |
| SSR render pass (Node) | Deterministic no-op — no network, no observers, no storage. Capture activates on the client after hydration, where your client entry calls init() again. |
| Edge / worker | A lite lane: analytics and config send over fetch with an ephemeral identity. No DOM, so no session, replay or persistence. These runtimes handle a request and never hydrate, so this is the only capture they get. |
You do not configure any of this — the SDK detects the runtime. Every framework adapter inherits the same guard.
Enabling opt-in features#
Most features are on by default. Five are off until you enable them:
replay, profiler, watchdog, inbox, and inapp2 (the In-App Messaging
2.0 engine). Turn one on via features:
await ScaleBun.init({ clientKey, apiBaseUrl, features: { replay: true }, replay: { mode: 'sampled', sampleRate: 1 },});Other delivery paths#
The same runtime ships three ways — one SDK, three delivery paths.
CDN <script> (declarative, CSP-clean)#
Configure with data-* attributes on the tag itself; no inline code required.
<script nonce="abc123" src="https://cdn.jsdelivr.net/npm/@scalebun/web@1/dist/scalebun.min.js" data-client-key="skb_live_ck_…" data-api-base-url="https://api.scalebun.com/api/v1"></script>The tag reads exactly four attributes — data-client-key, data-api-base-url,
data-environment and data-autocapture. Both keys are required for the
auto-init to fire. For anything else, use the loader snippet or the npm package.
Async loader snippet#
The recommended no-build path: an inline stub queues calls made before the bundle loads and replays them in order, so nothing is lost to the race. Full snippet in Plain JavaScript, CDN & GTM.
Google Tag Manager#
Import the ScaleBun custom template and set the Client key and API base URL
fields. The template sets up a loader queue, queues init(), and injects the
CDN bundle — so you get the same SDK without touching app code.
Configuration reference#
Common top-level options and their defaults:
| Option | Default | What it does |
|---|---|---|
clientKey | — | Required. Publishable client key. |
apiBaseUrl | — | Required. Ingestion API base URL. |
environment | — | e.g. production, staging. |
release | — | Version string, used to group errors and sessions. |
autocapture | true | Zero-instrumentation DOM capture. |
flushIntervalMs | 5000 | How often the queue flushes. |
maxBatchSize | 50 | Max items per flush. |
maxQueueSize | 1000 | Max buffered items before drop. |
requireConsent | false | Gate all capture behind setConsent(true). |
tracePropagation | true | Inject W3C traceparent on same-origin requests. |
tracePropagationOrigins | [] | Cross-origin origins to also propagate to. The server must CORS-allow the header. |
sessionTimeoutMs | 30 min | Idle time after which the next load starts a new session. |
sessionMaxDurationMs | 24 h | Absolute cap, so a permanently-open tab cannot report an endless session. |
replayCanvas | false | Capture <canvas> pixels. Opt-in — pixels cannot be masked. |
replayFrameOrigins | [] | Cross-origin replay stitching; both sides must list each other. |
signSessionLane | false | HMAC-sign session and replay batches too. The analytics lane always signs. |
initialConsent | 'unknown' | Pre-known consent from SSR or a cookie. |
debug | false | Verbose SDK logging. |
Nested blocks — errors, network, performance, replay, analytics,
flags, watchdog, exitIntent, push, privacy, bugReportOptions — are
documented on the page for each feature, and in full in the configuration
reference.
Before you use a feature controller#
init() is async. Accessors like ScaleBun.inbox() and ScaleBun.coachmarks()
return a no-op object when the runtime is not built yet, and every method on
it silently does nothing.
await ScaleBun.whenReady(); // resolves once init() has SETTLEDScaleBun.inbox().mount();It resolves on failure as well as success — if init() failed there genuinely is
no SDK, and the no-op accessors are the honest answer, but your code must not
hang waiting for a promise that will never resolve.
This matters most in component trees, where children mount before parents. See Integrations.
Next#
Product analytics — track your first event.
Privacy & consent — consent gating and CSP.
Troubleshooting — if data is not arriving.