Documentation
Framework guides
Where to initialize Wutbug in Next.js, React, Vue, Nuxt, SvelteKit, Angular and server-rendered sites.
The rule is the same in every framework: call wutbug.init() once, in the browser, as early as possible. Never during server rendering: init() throws an error if there is no window.
In the examples, the key and endpoint come from public environment variables. Use your framework's convention (NEXT_PUBLIC_*, VITE_*, PUBLIC_*, NUXT_PUBLIC_*).
Next.js (App Router)
Create a client component that initializes in useEffect and mount it in the root layout.
'use client';
import { useEffect } from 'react';
import wutbug from '@wutbug/sdk';
export function Wutbug() {
useEffect(() => {
wutbug.init({
projectKey: process.env.NEXT_PUBLIC_WUTBUG_KEY!,
endpoint: process.env.NEXT_PUBLIC_WUTBUG_ENDPOINT,
release: process.env.NEXT_PUBLIC_RELEASE, // optional
});
return () => wutbug.destroy();
}, []);
return null;
}import { Wutbug } from './wutbug';
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<body>
{children}
<Wutbug />
</body>
</html>
);
}The return () => wutbug.destroy() prevents duplicate instances with React's double mount in development. Either way, calling init() again replaces the previous instance.
To identify the user, call wutbug.setUser() from the client component that already knows the session:
'use client';
import { useEffect } from 'react';
import wutbug from '@wutbug/sdk';
export function IdentifyUser({ user }: { user: { id: string; email: string; name: string } | null }) {
useEffect(() => {
wutbug.setUser(user);
}, [user]);
return null;
}Next.js (Pages Router)
import type { AppProps } from 'next/app';
import { useEffect } from 'react';
import wutbug from '@wutbug/sdk';
export default function App({ Component, pageProps }: AppProps) {
useEffect(() => {
wutbug.init({
projectKey: process.env.NEXT_PUBLIC_WUTBUG_KEY!,
endpoint: process.env.NEXT_PUBLIC_WUTBUG_ENDPOINT,
});
}, []);
return <Component {...pageProps} />;
}React with Vite (or any SPA)
An SPA has no server rendering: initialize in the entry file, before mounting the app.
import { createRoot } from 'react-dom/client';
import wutbug from '@wutbug/sdk';
import App from './App';
wutbug.init({
projectKey: import.meta.env.VITE_WUTBUG_KEY,
endpoint: import.meta.env.VITE_WUTBUG_ENDPOINT,
release: import.meta.env.VITE_RELEASE,
});
createRoot(document.getElementById('root')!).render(<App />);To open the form from an error boundary:
import wutbug from '@wutbug/sdk';
function ErrorFallback({ error }: { error: Error }) {
return (
<div role="alert">
<p>Something went wrong.</p>
<button onClick={() => wutbug.open({ description: `Error: ${error.message}` })}>Report the problem</button>
</div>
);
}Vue 3 (Vite)
import { createApp } from 'vue';
import wutbug from '@wutbug/sdk';
import App from './App.vue';
wutbug.init({
projectKey: import.meta.env.VITE_WUTBUG_KEY,
endpoint: import.meta.env.VITE_WUTBUG_ENDPOINT,
});
createApp(App).mount('#app');Nuxt 3 / 4
A plugin with the .client suffix only runs in the browser.
import wutbug from '@wutbug/sdk';
export default defineNuxtPlugin(() => {
const config = useRuntimeConfig();
wutbug.init({
projectKey: config.public.wutbugKey as string,
endpoint: config.public.wutbugEndpoint as string,
});
});export default defineNuxtConfig({
runtimeConfig: {
public: { wutbugKey: '', wutbugEndpoint: '' }, // NUXT_PUBLIC_WUTBUG_KEY, NUXT_PUBLIC_WUTBUG_ENDPOINT
},
});SvelteKit
Initialize in onMount of the root layout (it only runs in the browser).
<script lang="ts">
import { onMount } from 'svelte';
import wutbug from '@wutbug/sdk';
import { PUBLIC_WUTBUG_KEY, PUBLIC_WUTBUG_ENDPOINT } from '$env/static/public';
let { children } = $props();
onMount(() => {
wutbug.init({ projectKey: PUBLIC_WUTBUG_KEY, endpoint: PUBLIC_WUTBUG_ENDPOINT });
return () => wutbug.destroy();
});
</script>
{@render children()}Angular
Initialize in main.ts before bootstrapping the app. If you use SSR, guard the call with isPlatformBrowser or run it in an afterNextRender.
import { bootstrapApplication } from '@angular/platform-browser';
import wutbug from '@wutbug/sdk';
import { AppComponent } from './app/app.component';
import { appConfig } from './app/app.config';
import { environment } from './environments/environment';
wutbug.init({ projectKey: environment.wutbugKey, endpoint: environment.wutbugEndpoint });
bootstrapApplication(AppComponent, appConfig).catch((err) => console.error(err));HTML, WordPress, Rails, Django, Laravel and PHP
On server-rendered sites, use the script tag in the <head> of the base template. If the person is signed in, identify them in the same template using the call queue.
<script>
window.wutbug = window.wutbug || { q: [] };
['init', 'setUser', 'setMetadata', 'open', 'close'].forEach(function (m) {
window.wutbug[m] = window.wutbug[m] || function () { window.wutbug.q.push([m, arguments]); };
});
</script>
<script type="module" src="https://cdn.wutbug.dev/v0/wutbug.js"
data-project-key="pk_your_key" data-endpoint="https://api.wutbug.dev"></script>WordPress
Add the script with wp_head in your child theme's functions.php (or with a code-snippets plugin):
add_action('wp_head', function () {
echo '<script type="module" src="https://cdn.wutbug.dev/v0/wutbug.js" data-project-key="pk_your_key" data-endpoint="https://api.wutbug.dev"></script>';
});Rails
<script type="module" src="https://cdn.wutbug.dev/v0/wutbug.js"
data-project-key="<%= ENV['WUTBUG_KEY'] %>" data-endpoint="<%= ENV['WUTBUG_ENDPOINT'] %>"></script>
<% if current_user %>
<script>
window.wutbug = window.wutbug || { q: [] };
(window.wutbug.setUser || function () { window.wutbug.q.push(['setUser', arguments]); })(
<%= raw({ id: current_user.id.to_s, email: current_user.email }.to_json) %>
);
</script>
<% end %>Django
<script type="module" src="https://cdn.wutbug.dev/v0/wutbug.js"
data-project-key="{{ WUTBUG_KEY }}" data-endpoint="{{ WUTBUG_ENDPOINT }}"></script>Laravel (Blade)
<script type="module" src="https://cdn.wutbug.dev/v0/wutbug.js"
data-project-key="{{ config('services.wutbug.key') }}" data-endpoint="{{ config('services.wutbug.endpoint') }}"></script>Content Security Policy
If your site uses CSP, allow:
script-src: the CDN domain (only if you use the script tag).connect-src: the API endpoint and the object storage that report files are uploaded to (the signed URLs the API returns).img-src:data:andblob:(screenshot).