Vue.js
Plugin Setup

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

OptionTypeRequiredDescription
connectionStringstringYesYour Traceway connection string
optionsobjectNoSDK configuration options

SDK Options

OptionTypeDefaultDescription
debugbooleanfalseLog events to console
debounceMsnumber1500Batch delay in milliseconds
retryDelayMsnumber10000Retry delay for failed uploads
versionstringundefinedYour application version
ignoreErrorsArray<string | RegExp>DEFAULT_IGNORE_PATTERNSError patterns to ignore. Pass [] to capture all errors. See Error Filtering
beforeCapture(exception) => booleanundefinedReturn false to suppress an error. See Error Filtering
sessionRecordingbooleantrueEnable the rrweb session recorder
sessionRecordingSegmentDurationnumber30000rrweb segment length in ms
recordAllSessionsbooleanfalseAlways-on session recording. See Sessions
captureLogsbooleantrueMirror console.* calls into the rolling log buffer
captureNetworkbooleantrueRecord fetch / XHR calls as network actions
captureNavigationbooleantrueRecord 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/report

Use 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,
    },
  },
});