Plugin Setup
Configure the Traceway Vue plugin with createTracewayPlugin.
Basic Setup
import { createApp } from "vue";
import { createTracewayPlugin } from "@tracewayapp/vue";
import App from "./App.vue";
const app = createApp(App);
app.use(createTracewayPlugin({
connectionString: "your-token@https://traceway.example.com/api/report",
}));
app.mount("#app");Plugin Options
| Option | Type | Required | Description |
|---|---|---|---|
connectionString | string | Yes | Your Traceway connection string |
options | object | No | SDK configuration options |
SDK Options
| Option | Type | Default | Description |
|---|---|---|---|
debug | boolean | false | Log events to console |
debounceMs | number | 1500 | Batch delay in milliseconds |
retryDelayMs | number | 10000 | Retry delay for failed uploads |
version | string | undefined | Your application version |
ignoreErrors | Array<string | RegExp> | DEFAULT_IGNORE_PATTERNS | Error patterns to ignore. Pass [] to capture all errors. See Error Filtering |
beforeCapture | (exception) => boolean | undefined | Return false to suppress an error. See Error Filtering |
sessionRecording | boolean | true | Enable the rrweb session recorder |
sessionRecordingSegmentDuration | number | 30000 | rrweb segment length in ms |
recordAllSessions | boolean | false | Always-on session recording. See Sessions |
captureLogs | boolean | true | Mirror console.* calls into the rolling log buffer |
captureNetwork | boolean | true | Record fetch / XHR calls as network actions |
captureNavigation | boolean | true | Record History API push / replace / pop transitions |
Full Example
import { createApp } from "vue";
import { createTracewayPlugin } from "@tracewayapp/vue";
import App from "./App.vue";
const app = createApp(App);
app.use(createTracewayPlugin({
connectionString: "your-token@https://traceway.example.com/api/report",
options: {
debug: import.meta.env.DEV,
version: import.meta.env.VITE_APP_VERSION,
debounceMs: 1000,
},
}));
app.mount("#app");Capture All Errors
By default, 4xx HTTP errors, network errors, and timeouts are ignored. To capture everything:
app.use(createTracewayPlugin({
connectionString: "your-token@https://traceway.example.com/api/report",
options: {
ignoreErrors: [],
},
}));Automatic Error Handling
The plugin automatically installs app.config.errorHandler to capture:
- Component rendering errors
- Watcher errors
- Lifecycle hook errors
// This is handled automatically by the plugin:
app.config.errorHandler = (err, instance, info) => {
// Error is captured and sent to Traceway
};Vue has a single app.config.errorHandler slot, and the plugin assigns it. If your app assigns its own handler after app.use(createTracewayPlugin(...)), it replaces Traceway's and component errors stop reaching the dashboard. To keep both, capture the error yourself inside your handler:
import { captureException, captureMessage } from "@tracewayapp/vue";
app.use(createTracewayPlugin({
connectionString: "your-token@https://traceway.example.com/api/report",
}));
app.config.errorHandler = (err, instance, info) => {
if (err instanceof Error) {
captureException(err);
} else {
captureMessage(String(err));
}
myOwnErrorReporter(err, info);
};Environment-Specific Configuration
const connectionString = import.meta.env.PROD
? import.meta.env.VITE_TRACEWAY_PROD
: import.meta.env.VITE_TRACEWAY_DEV;
app.use(createTracewayPlugin({
connectionString,
options: {
debug: import.meta.env.DEV,
},
}));Custom Attributes
Attach app-level identifiers (userId, tenant, feature flags, etc.) to every session and exception. The useTracewayAttributes composable is the Vue way to do it. Pass a getter and it tracks reactive state, pushes only the keys that changed, and removes the keys it owns when the component unmounts:
<script setup>
import { useTracewayAttributes } from "@tracewayapp/vue";
import { useUser } from "./auth";
const { user, org } = useUser();
useTracewayAttributes(() =>
user.value && org.value
? { userId: user.value.id, tenant: org.value.id }
: null
);
</script>Return null when there is nothing to attach. The composable then removes the keys it had set.
There is a declarative wrapper for the same thing. It renders nothing and removes its keys on unmount:
<script setup>
import { TracewayAttributes } from "@tracewayapp/vue";
import { useUser } from "./auth";
const { user, org } = useUser();
</script>
<template>
<TracewayAttributes
v-if="user && org"
:attributes="{ userId: user.id, tenant: org.id }"
/>
</template>Treat every key you pass to the composable or the component as owned by it. Do not set the same key with setAttribute elsewhere, because the unmount cleanup will remove it.
You can also drive the scope imperatively from watchEffect:
<script setup>
import { watchEffect } from "vue";
import { setAttributes, removeAttribute } from "@tracewayapp/vue";
import { useUser } from "./auth";
const { user, org } = useUser();
watchEffect(() => {
if (user.value && org.value) {
setAttributes({ userId: user.value.id, tenant: org.value.id });
} else {
removeAttribute("userId");
removeAttribute("tenant");
}
});
</script>Use removeAttribute per key here rather than clearAttributes(). clearAttributes() empties the whole global scope, so it also drops keys set by other parts of the app.
The full API (setAttribute, setAttributes, removeAttribute, clearAttributes) is re-exported from @tracewayapp/vue. Layering on each event: defaults < global scope < per-call. See Sessions for the full attribute model.
Manual Injection
For advanced use cases, you can use the injection key directly:
<script setup>
import { inject } from "vue";
import { TracewayKey } from "@tracewayapp/vue";
const traceway = inject(TracewayKey);
traceway.captureException(new Error("Manual capture"));
</script>However, the useTraceway composable is preferred for most use cases.
Vite Configuration
Add your connection string to .env:
VITE_TRACEWAY_CONNECTION=your-token@https://traceway.example.com/api/reportUse in your app:
app.use(createTracewayPlugin({
connectionString: import.meta.env.VITE_TRACEWAY_CONNECTION,
}));Nuxt Integration
For Nuxt 3, create a plugin:
// plugins/traceway.ts
import { createTracewayPlugin } from "@tracewayapp/vue";
export default defineNuxtPlugin((nuxtApp) => {
nuxtApp.vueApp.use(createTracewayPlugin({
connectionString: useRuntimeConfig().public.tracewayConnection,
}));
});Name the file traceway.ts, not traceway.client.ts. A .client plugin never runs during SSR, so the injection key is missing on the server and the first component calling useTraceway() fails the render with useTraceway must be used within a Vue app that has installed the Traceway plugin (HTTP 500). The plugin is safe to run universally: it only installs the browser handlers and the recorder when window exists, so the server pass just provides the injection key.
Add to nuxt.config.ts:
export default defineNuxtConfig({
runtimeConfig: {
public: {
tracewayConnection: process.env.TRACEWAY_CONNECTION,
},
},
});