How to use Sentry with Vue
Integrating Sentry with Vue applications provides real-time error tracking, performance monitoring, and detailed stack traces for production debugging. As the creator of CoreUI with over 12 years of Vue.js experience since 2014, I’ve integrated Sentry into numerous production Vue applications. Sentry captures errors automatically with context including user actions, browser info, and breadcrumbs leading to errors. This approach helps identify and fix production bugs quickly with comprehensive error data and alerting.
Install @sentry/vue and initialize in main.js to capture errors with context and source maps for production debugging.
Basic Sentry setup:
// main.js
import { createApp } from 'vue'
import App from './App.vue'
import * as Sentry from '@sentry/vue'
const app = createApp(App)
Sentry.init({
app,
dsn: 'https://[email protected]/0',
integrations: [
Sentry.browserTracingIntegration(),
Sentry.replayIntegration()
],
// Performance Monitoring
tracesSampleRate: 1.0,
// Session Replay
replaysSessionSampleRate: 0.1,
replaysOnErrorSampleRate: 1.0,
environment: import.meta.env.MODE,
enabled: import.meta.env.MODE === 'production'
})
app.mount('#app')
Advanced configuration:
// sentry.config.js
import * as Sentry from '@sentry/vue'
import { router } from './router'
export function initSentry(app) {
Sentry.init({
app,
dsn: import.meta.env.VITE_SENTRY_DSN,
integrations: [
Sentry.browserTracingIntegration({ router }),
Sentry.replayIntegration({
maskAllText: false,
blockAllMedia: false
})
],
tracesSampleRate: import.meta.env.MODE === 'production' ? 0.2 : 1.0,
replaysSessionSampleRate: 0.1,
replaysOnErrorSampleRate: 1.0,
environment: import.meta.env.MODE,
release: import.meta.env.VITE_APP_VERSION,
enabled: import.meta.env.MODE !== 'development',
beforeSend(event, hint) {
// Filter out specific errors
if (event.exception) {
const error = hint.originalException
if (error && error.message && error.message.includes('ResizeObserver')) {
return null
}
}
return event
},
ignoreErrors: [
'Non-Error promise rejection',
'ResizeObserver loop limit exceeded',
'Network request failed'
]
})
// Set user context
const user = getUserFromStorage()
if (user) {
Sentry.setUser({
id: user.id,
email: user.email,
username: user.username
})
}
}
Error boundary component:
<script setup>
import { ref, onErrorCaptured } from 'vue'
import * as Sentry from '@sentry/vue'
const hasError = ref(false)
const errorMessage = ref('')
onErrorCaptured((err, instance, info) => {
hasError.value = true
errorMessage.value = err.message
// Send to Sentry with context
Sentry.captureException(err, {
contexts: {
vue: {
componentName: instance?.$options?.name,
propsData: instance?.$props,
info
}
}
})
// Prevent error from propagating
return false
})
</script>
<template>
<div v-if="hasError" class="error-boundary">
<h2>Something went wrong</h2>
<p>{{ errorMessage }}</p>
<button @click="hasError = false">Try Again</button>
</div>
<slot v-else />
</template>
Manual error reporting:
// api.service.js
import * as Sentry from '@sentry/vue'
export async function fetchUserData(userId) {
try {
const response = await fetch(`/api/users/${userId}`)
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`)
}
return await response.json()
} catch (error) {
// Add breadcrumb
Sentry.addBreadcrumb({
category: 'api',
message: 'Failed to fetch user data',
level: 'error',
data: { userId }
})
// Capture exception with context
Sentry.captureException(error, {
tags: {
api_endpoint: '/api/users',
user_id: userId
},
contexts: {
response: {
status: error.response?.status,
statusText: error.response?.statusText
}
}
})
throw error
}
}
Performance monitoring:
// router/index.js
import { createRouter, createWebHistory } from 'vue-router'
import * as Sentry from '@sentry/vue'
const router = createRouter({
history: createWebHistory(),
routes: [
// routes
]
})
router.beforeEach((to, from, next) => {
// Start performance transaction
const transaction = Sentry.startTransaction({
name: to.name,
op: 'navigation',
tags: {
from: from.name,
to: to.name
}
})
// Attach transaction to route meta
to.meta.sentryTransaction = transaction
next()
})
router.afterEach((to) => {
// Finish transaction
const transaction = to.meta.sentryTransaction
if (transaction) {
transaction.finish()
}
})
export { router }
Custom breadcrumbs:
<script setup>
import { onMounted } from 'vue'
import * as Sentry from '@sentry/vue'
const props = defineProps({
userId: String
})
onMounted(() => {
Sentry.addBreadcrumb({
category: 'ui',
message: 'User profile mounted',
level: 'info',
data: {
userId: props.userId
}
})
})
const handleAction = () => {
Sentry.addBreadcrumb({
category: 'user-action',
message: 'Button clicked',
level: 'info'
})
// Perform action
}
</script>
Source maps for production:
// vite.config.js
import { defineConfig } from 'vite'
import { sentryVitePlugin } from '@sentry/vite-plugin'
export default defineConfig({
build: {
sourcemap: true
},
plugins: [
sentryVitePlugin({
org: 'your-org',
project: 'your-project',
authToken: process.env.SENTRY_AUTH_TOKEN,
sourcemaps: {
assets: './dist/**',
ignore: ['node_modules']
}
})
]
})
Best Practice Note
Enable Sentry only in production to avoid noise during development. Upload source maps for readable stack traces in production. Use breadcrumbs to track user actions leading to errors. Set user context for better debugging. Filter out benign errors like ResizeObserver. Use performance monitoring to track slow routes. Tag errors with relevant context (API endpoints, user IDs). This is how we integrate Sentry in CoreUI Vue applications—comprehensive error tracking with context, source maps for debugging, performance monitoring, and filtered alerts ensuring we catch critical production issues without alert fatigue.



