How to Setup Sentry Error Monitoring with SvelteKit

avatar
Cesar Mejia · 11 Apr 2023
4 min read
· 724 words · 13 views
article hero

TLDR

For the impatient, here is the sample repo that illustrates the setup below and the project is deployed here.

Intro

Errors and exceptions are inevitable in any application. However, what separates the brave from the foolhardy is the ability to handle them with grace and elegance. In this guide, I’ll show you how to set up error and exception handling in your SvelteKit project using Sentry.io.

We’ll cover all the bases, from monitoring production server and client errors to uploading source maps to Sentry on build. We’ll even enable Error Replay Tracking so you can see exactly what your users were doing when an error occurred.

So grab your sword and shield, and let’s get started.

Goals

  • Monitor production server/client errors
  • Upload source maps to Sentry on build
  • Enable Error Replay Tracking

Setup

Create SvelteKit App

First things first, we need to create a SvelteKit app. Run the following command to create a new SvelteKit app:

	
zsh
pnpm create svelte@latest sentry-sveltekit

Install Sentry Packages

Next, we need to install the Sentry packages. Run the following command to install them:

	
zsh
pnpm add -D @sentry/node @sentry/svelte @sentry/vite-plugin

Create Environmental Variables

Before we can proceed, we need to create the necessary environmental variables. Add the following variables to your .env file:

.env
	
zsh
PUBLIC_SENTRY_ORG=FOUND_IN_SENTRY_PROJECT_SETTINGS PUBLIC_SENTRY_PROJECT=FOUND_IN_SENTRY_PROJECT_SETTINGS PUBLIC_SENTRY_DSN=FOUND_IN_SENTRY_PROJECT_SETTINGS SENTRY_AUTH_TOKEN=SEE_AUTH_TOKEN_LINK_BELOW

Sentry Auth Token(Required scopes: project:releases and org:read)

Add sentryVitePlugin to Vite Config

We’re almost there! Next, we need to add the sentryVitePlugin to our Vite config. Open vite.config.ts and add the following:

vite.config.ts
	
TypeScript
import { sentryVitePlugin } from '@sentry/vite-plugin'; import { sveltekit } from '@sveltejs/kit/vite'; import { defineConfig, loadEnv } from 'vite'; const config = defineConfig(({ mode }) => { // Only setup Sentry in production const isProduction = mode === 'production'; // Gain access to environmental variables within vite config const env = loadEnv(mode, process.cwd(), ''); return { build: { sourcemap: true // Tell vite to emit source maps }, plugins: [ sveltekit(), // Add the sentry-vite-plugin last isProduction ? sentryVitePlugin({ telemetry: false, // Privacy :-) org: env.PUBLIC_SENTRY_ORG, // can be hardcode project: env.PUBLIC_SENTRY_PROJECT, // can be hardcode authToken: env.SENTRY_AUTH_TOKEN, // must be secret include: './svelte-kit/output' // default build output for source maps. Uploaded to Sentry on deploy }) : '' ], }; }); export default config;

Capture Frontend Exceptions via hooks.client.ts

Now it’s time to capture frontend exceptions. Open hooks.client.ts and add the following:

src/hooks.client.ts
	
TypeScript
import type { HandleClientError } from '@sveltejs/kit'; import * as Sentry from '@sentry/svelte'; import { PUBLIC_SENTRY_DSN } from '$env/static/public'; if (import.meta.env.PROD) { Sentry.init({ dsn: PUBLIC_SENTRY_DSN, // can be hardcoded integrations: [ new Sentry.BrowserTracing(), // Detail trace stack new Sentry.Replay({ // Visual replay of errors (cool!) maskAllInputs: true, // respect user privacy on replays maskAllText: true, blockAllMedia: true }) ], tracesSampleRate: 1.0, // lower settings if swamped with errors replaysSessionSampleRate: 1.0, replaysOnErrorSampleRate: 1.0 }); } export const handleError: HandleClientError = ({ error, event }) => { const errorId = crypto.randomUUID(); // add unique errorId for easy reference // Only emit errors in production if (import.meta.env.PROD) { Sentry.captureException(error, { contexts: { sveltekit: { event, errorId } } }); } return { message: "An unexpected error occurred. We're working on it!", errorId }; };

Capture Backend Exceptions via hooks.server.ts

Similar to the hooks.client.ts, the hooks.server.ts file captures backend exceptions and sends them to Sentry for analysis.

src/hooks.server.ts
	
TypeScript
import type { HandleServerError } from '@sveltejs/kit'; import crypto from 'crypto'; import * as Sentry from '@sentry/node'; import { PUBLIC_SENTRY_DSN } from '$env/static/public'; // Only emit errors in production if (import.meta.env.PROD) { Sentry.init({ dsn: PUBLIC_SENTRY_DSN, tracesSampleRate: 1.0 }); } export const handleError: HandleServerError = ({ error, event }) => { const errorId = crypto.randomUUID(); // Only emit errors in production if (import.meta.env.PROD) { Sentry.captureException(error, { contexts: { sveltekit: { event, errorId } } }); } return { message: 'An unexpected error occurred. I have spoken.', errorId }; };

Now let’s add the errorId as an optional property on the Error object.

src/app.d.ts
	
TypeScript
declare global { namespace App { interface Error { errorId?: string } // interface Locals {} // interface PageData {} // interface Platform {} } } export {}

Wrap Up

There you have it, fellow warriors of the web. With Sentry.io and SvelteKit, you now have the tools to handle errors and exceptions with the grace and elegance of a seasoned warrior. No longer will you be caught off guard by unexpected errors or left in the dark about what your users were doing when an issue occurred.

So take this knowledge and go forth, fearless developers, confident in your ability to handle any error that comes your way. And remember, when in doubt, trust in the power of Sentry and the might of SvelteKit.


Edit on GitHub