Documentación
Guías por framework
Dónde inicializar Wutbug en Next.js, React, Vue, Nuxt, SvelteKit, Angular y sitios renderizados en el servidor.
La regla es la misma en todos los frameworks: llama a wutbug.init() una sola vez, en el navegador, lo antes posible. Nunca durante el renderizado en el servidor: init() lanza un error si no hay window.
En los ejemplos, la key y el endpoint vienen de variables de entorno públicas. Usa la convención de tu framework (NEXT_PUBLIC_*, VITE_*, PUBLIC_*, NUXT_PUBLIC_*).
Next.js (App Router)
Crea un componente cliente que inicialice en useEffect y móntalo en el layout raíz.
'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, // opcional
});
return () => wutbug.destroy();
}, []);
return null;
}import { Wutbug } from './wutbug';
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="es">
<body>
{children}
<Wutbug />
</body>
</html>
);
}El return () => wutbug.destroy() evita instancias duplicadas con el doble montaje de React en desarrollo. De todos modos, llamar a init() de nuevo reemplaza la instancia anterior.
Para identificar al usuario, llama a wutbug.setUser() desde el componente cliente que ya conoce la sesión:
'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 con Vite (o cualquier SPA)
En una SPA no hay renderizado en el servidor: inicializa en el entry, antes de montar la 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 />);Para abrir el formulario desde un error boundary:
import wutbug from '@wutbug/sdk';
function ErrorFallback({ error }: { error: Error }) {
return (
<div role="alert">
<p>Algo salió mal.</p>
<button onClick={() => wutbug.open({ description: `Error: ${error.message}` })}>Reportar el problema</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
Un plugin con sufijo .client solo corre en el navegador.
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
Inicializa en onMount del layout raíz (solo corre en el navegador).
<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
Inicializa en main.ts antes de arrancar la app. Si usas SSR, protege la llamada con isPlatformBrowser o hazla en un 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 y PHP
En sitios renderizados en el servidor, usa la etiqueta script en el <head> de la plantilla base. Si la persona inició sesión, identifícala en la misma plantilla con la cola de llamadas.
<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_tu_key" data-endpoint="https://api.wutbug.dev"></script>WordPress
Agrega el script con wp_head en el functions.php de tu tema hijo (o con un plugin de fragmentos de código):
add_action('wp_head', function () {
echo '<script type="module" src="https://cdn.wutbug.dev/v0/wutbug.js" data-project-key="pk_tu_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
Si tu sitio usa CSP, permite:
script-src: el dominio del CDN (solo si usas la etiqueta script).connect-src: el endpoint de la API y el almacenamiento de objetos al que se suben los archivos del reporte (las URLs firmadas que entrega la API).img-src:data:yblob:(captura de pantalla).