Skip to content

Build Tool Plugins

hakka-browser ships build-tool plugins as subpath exports — hakka-browser/vite, hakka-browser/webpack, and hakka-browser/rspack — built on unplugin, so the same plugin logic targets every bundler from one source. Each plugin injects start() from hakka-browser into the page during dev. Production builds are untouched by default.

For an overview of the web SDK see /web/overview/.

hakka-browser is the only package you need — the Vite plugin is a subpath export, not a separate package.

Terminal window
npm install hakka-browser

Peer requirement: vite >=5.0.0.

vite.config.ts
import { defineConfig } from 'vite'
import hakka from 'hakka-browser/vite'
export default defineConfig({
plugins: [hakka()],
})

That is all the configuration needed for most projects.

The plugin uses Vite’s transformIndexHtml hook (order: post) to append a <script type="module"> tag to the page body. The script imports start from hakka-browser and calls it with the options you pass.

When devOnly is true (the default), the plugin sets apply: 'serve', so it runs only during vite serve and is excluded from vite build entirely. No Hakka code reaches the production bundle.

Terminal window
npm install hakka-browser html-webpack-plugin

html-webpack-plugin is required — the webpack plugin injects the overlay script into the HTML it generates.

webpack.config.js
const HtmlWebpackPlugin = require('html-webpack-plugin')
const hakka = require('hakka-browser/webpack').default
module.exports = {
plugins: [new HtmlWebpackPlugin(), hakka()],
}
Terminal window
npm install hakka-browser html-webpack-plugin

rspack’s plugin also requires html-webpack-plugin for the same reason as webpack.

rspack.config.js
const HtmlWebpackPlugin = require('html-webpack-plugin')
const hakka = require('hakka-browser/rspack').default
module.exports = {
plugins: [new HtmlWebpackPlugin(), hakka()],
}

Bundlers without an HTML pipeline (esbuild, rollup) don’t get a plugin — use the one-line manual setup instead:

import { start } from 'hakka-browser'
if (import.meta.env.DEV) start()
hakka({
devOnly: true, // default — omit from the production build
start: {
// forwarded verbatim to hakka-browser start()
overlay: 'launcher',
console: true,
captureBeacons: true,
},
})
Option Type Default Description
devOnly boolean true Restrict injection to dev mode. Set false to also inject into the production build (rarely needed).
start Record<string, unknown> {} Options forwarded verbatim to hakka-browser’s start().
server boolean false Vite only — auto-register hakka-node server-side capture. See below.

These keys are accepted in the start bag and passed through to hakka-browser:

Key Default Description
overlay 'launcher' 'launcher' shows a small button; true opens the inspector immediately; false hides it (call show() manually).
resourceTiming true Enrich captures with the Performance Timeline (DNS, TLS, connect, TTFB).
captureBeacons true Capture navigator.sendBeacon calls.
console true Capture console.log/warn/error/info/debug output.
logToConsole false Mirror each captured request to the browser DevTools console.
maxRequests — Maximum requests to keep in the store (forwarded to hakka-core).
maxAge — Maximum age in ms before a captured request is evicted.
ignoreHosts — Array of hostnames to ignore.
ignorePatterns — Array of URL patterns to ignore.
redactHeaders — Array of header names to redact from captures.
maxBodySize — Maximum body size in bytes to capture.
hakka({ start: {}, server: true })

server: true auto-registers hakka-node (an optional peer — install it with bun add -D hakka-node if you use this) so the Vite dev server’s own requests (SSR loaders, API routes) show up in the overlay alongside client traffic, with no manual instrumentation.ts/register() call needed. register() carries its own dev-only gate, so this is a no-op outside development regardless.

This option only exists for Vite, and only because of a real asymmetry: Vite’s dev server runs in-process, so the plugin’s configureServer hook can reach in and register capture directly. webpack and rspack’s dev servers front a separate bundling process that doesn’t own the app’s actual server runtime — there’s no server for a configureServer-style hook to instrument — so their plugins silently ignore server: true rather than fake support for it.

The XHR interceptor patches XMLHttpRequest. Requests go through as normal — response bodies are captured where the browser exposes them. There is no proxy; traffic never leaves the browser.

With the default devOnly: true, the Vite plugin registers itself with apply: 'serve', so transformIndexHtml never runs during vite build and the production bundle contains no Hakka code at all. The webpack and rspack plugins apply the same dev-only gate. Only set devOnly: false if you intentionally want the inspector in a staging or preview build.

Hakka is local-first: no cloud, no accounts. Captured traffic stays in the browser tab.