SDKs by framework
Bucker's JavaScript framework support is entry points of the two platform SDKs, not a package per framework: nothing new to install, nothing new to publish, and a page pays only for the entry it imports. The browser half lives in @bucker/browser, the server half in @bucker/node. For what npx create-bucker writes for you, see framework guides.
| Framework | Browser | Server |
|---|---|---|
| React | @bucker/browser/react: ErrorBoundary, withErrorBoundary, reactErrorHandler, useRouteBreadcrumb |
|
| React Router / Remix | @bucker/browser/react: useRouteBreadcrumb, captureRouteError |
@bucker/node/remix: remixHandleError |
| Vue | @bucker/browser/vue: buckerVue, attachVueErrorHandler, instrumentVueRouter |
|
| Nuxt | @bucker/browser/nuxt: installNuxt |
@bucker/node/nuxt: nitroErrorHook |
| SvelteKit | @bucker/browser/svelte: buckerHandleError |
@bucker/node/sveltekit: sveltekitHandle, sveltekitHandleError |
| Angular | @bucker/browser/angular: createErrorHandler |
|
| Next.js | see @bucker/node |
For Lambda, Workers, Vercel Edge, Deno, Bun, Hono, Koa and NestJS see Serverless, edge and more frameworks.
Tested against what, honestly. React is tested against the real React 19 and Testing Library. Vue, Nuxt, SvelteKit, Angular, Remix and Nitro are not installed in this repository, so their entries are typed against the host object structurally (they import none of them) and tested with fakes of exactly the shape they read. They have not yet been run inside a real Vue, Nuxt, SvelteKit or Angular app; if one misbehaves, that is the first place to look.
Handled, not crashed. A framework-level handler (an error boundary, Vue's errorHandler, SvelteKit's handleError, Angular's ErrorHandler) catches the error and the page keeps running, so it is captured handled: true: it counts as an error in release health, not as a crash of the session. handled: false stays with window.onerror and unhandledrejection. Server hooks use request.<framework> mechanisms for the same reason: a failed request is not a dead process.
Client errors are not defects. A 4xx (HttpErrorResponse, a SvelteKit 404, an h3 404, a thrown Response with a client status) is not captured, and one error object is captured once even when two hooks see it.
React
import { init } from '@bucker/browser'
import { ErrorBoundary } from '@bucker/browser/react'
init({ dsn, release })
<ErrorBoundary fallback={({ error, eventId, resetError }) => <Oops onRetry={resetError} />}>
<App />
</ErrorBoundary>
fallback is a node or a function of { error, componentStack, eventId, resetError }; eventId is what you hand to captureFeedback. beforeCapture(scope, error, componentStack) edits the scope for that one event. The component stack rides along as extra.componentStack (bounded). react is an optional peer dependency (>=18).
React 19 reports errors an error boundary does not see through createRoot options:
createRoot(el, {
onUncaughtError: reactErrorHandler(),
onCaughtError: reactErrorHandler({ handled: true }),
onRecoverableError: reactErrorHandler({ handled: true }),
})
React Router and Remix
// root.tsx / any route
const { pathname } = useLocation()
useRouteBreadcrumb(pathname, { transactionName: matches.at(-1)?.pathname })
export function ErrorBoundary() {
const error = useRouteError()
captureRouteError(error)
return <Oops />
}
// entry.server.tsx
import { remixHandleError } from '@bucker/node/remix'
export const handleError = remixHandleError(client)
Vue
const app = createApp(App)
app.use(buckerVue) // sets app.config.errorHandler; logs and chains the previous one
instrumentVueRouter(router) // navigation breadcrumbs + the route pattern as the transaction
Nuxt
// plugins/bucker.client.ts
export default defineNuxtPlugin((nuxtApp) => {
init({ dsn: useRuntimeConfig().public.buckerDsn })
installNuxt(nuxtApp)
})
// server/plugins/bucker.ts
import { nitroErrorHook } from '@bucker/node/nuxt'
export default defineNitroPlugin((nitroApp) => {
nitroApp.hooks.hook('error', nitroErrorHook(client))
})
SvelteKit
// src/hooks.client.ts
export const handleError = buckerHandleError()
// src/hooks.server.ts
import { sveltekitHandle, sveltekitHandleError } from '@bucker/node/sveltekit'
export const handle = sequence(sveltekitHandle(client), yourHandle)
export const handleError = sveltekitHandleError(client)
Both handleError helpers take your own handler as an argument and return its result, so the error shape your pages show is unchanged.
Angular
// app.config.ts
providers: [{ provide: ErrorHandler, useValue: createErrorHandler() }]
Angular's default handler logs to the console and providing your own replaces it, so this logs too (logErrors: false to stop). Zone.js { rejection } and { originalError } wrappers are unwrapped before capture; a thrown string or object is wrapped so the event has a type and a value to group on.