Documentation Index Fetch the complete documentation index at: https://mintlify.com/getsentry/sentry-javascript/llms.txt
Use this file to discover all available pages before exploring further.
The Sentry Cloudflare SDK provides error monitoring and performance tracking for Cloudflare Workers and Cloudflare Pages applications.
Installation
npm install @sentry/cloudflare
Prerequisites
Add the nodejs_als or nodejs_compat compatibility flag to your wrangler.toml or wrangler.jsonc:
wrangler.toml
wrangler.jsonc
compatibility_flags = [ "nodejs_als" ]
# or
# compatibility_flags = ["nodejs_compat"]
The SDK needs AsyncLocalStorage API to work correctly.
Cloudflare Pages
Middleware Setup
Add Sentry as middleware in functions/_middleware.ts:
// functions/_middleware.ts
import * as Sentry from '@sentry/cloudflare' ;
export const onRequest = Sentry . sentryPagesPlugin ({
dsn: 'YOUR_DSN_HERE' ,
// Performance Monitoring
tracesSampleRate: 1.0 ,
});
Multiple Middlewares
Chain multiple middlewares (Sentry should be first):
import * as Sentry from '@sentry/cloudflare' ;
import { authMiddleware } from './auth' ;
export const onRequest = [
// Sentry must be first
Sentry . sentryPagesPlugin ({
dsn: 'YOUR_DSN_HERE' ,
tracesSampleRate: 1.0 ,
}),
authMiddleware ,
// ... other middlewares
];
Access Environment Variables
import * as Sentry from '@sentry/cloudflare' ;
export const onRequest = Sentry . sentryPagesPlugin (( context ) => ({
dsn: context . env . SENTRY_DSN ,
environment: context . env . ENVIRONMENT ,
tracesSampleRate: 1.0 ,
}));
SvelteKit on Cloudflare
// hooks.server.ts
import * as Sentry from '@sentry/cloudflare' ;
export const handle = ({ event , resolve }) => {
const requestHandlerOptions = {
options: {
dsn: event . platform . env . SENTRY_DSN ,
tracesSampleRate: 1.0 ,
},
request: event . request ,
context: event . platform . ctx ,
};
return Sentry . wrapRequestHandler ( requestHandlerOptions , () => resolve ( event ));
};
Cloudflare Workers
Basic Setup
Wrap your worker handler with withSentry:
import * as Sentry from '@sentry/cloudflare' ;
export default Sentry . withSentry (
( env ) => ({
dsn: env . SENTRY_DSN ,
tracesSampleRate: 1.0 ,
}),
{
async fetch ( request , env , ctx ) {
return new Response ( 'Hello World!' );
} ,
} satisfies ExportedHandler < Env >,
) ;
Full Worker Example
import * as Sentry from '@sentry/cloudflare' ;
interface Env {
SENTRY_DSN : string ;
ENVIRONMENT : string ;
}
export default Sentry . withSentry (
( env : Env ) => ({
dsn: env . SENTRY_DSN ,
environment: env . ENVIRONMENT ,
tracesSampleRate: 1.0 ,
}),
{
async fetch ( request : Request , env : Env , ctx : ExecutionContext ) {
try {
const url = new URL ( request . url );
// Add context
Sentry . setContext ( 'request' , {
method: request . method ,
url: request . url ,
path: url . pathname ,
});
if ( url . pathname === '/error' ) {
throw new Error ( 'Test error' );
}
return new Response ( 'Success' , { status: 200 });
} catch ( error ) {
Sentry . captureException ( error );
return new Response ( 'Error' , { status: 500 });
}
} ,
async scheduled ( event : ScheduledEvent , env : Env , ctx : ExecutionContext ) {
// Handle scheduled events
} ,
} satisfies ExportedHandler < Env >,
) ;
Cloudflare D1 Integration
Instrument D1 database operations:
import * as Sentry from '@sentry/cloudflare' ;
interface Env {
DB : D1Database ;
SENTRY_DSN : string ;
}
export default Sentry . withSentry (
( env ) => ({ dsn: env . SENTRY_DSN }),
{
async fetch ( request , env , ctx ) {
// Instrument D1 with Sentry
const db = Sentry . instrumentD1WithSentry ( env . DB );
// Now use the database as usual
// All queries will be tracked automatically
const users = await db
. prepare ( 'SELECT * FROM users WHERE id = ?' )
. bind ( 1 )
. all ();
return Response . json ( users );
} ,
},
) ;
Cron Monitoring
Monitor scheduled tasks with Sentry Crons:
import * as Sentry from '@sentry/cloudflare' ;
export default Sentry . withSentry (
( env ) => ({ dsn: env . SENTRY_DSN }),
{
async scheduled ( event : ScheduledEvent , env : Env , ctx : ExecutionContext ) {
ctx . waitUntil (
Sentry . withMonitor (
'cleanup-job' ,
async () => {
await performCleanup ();
},
{
schedule: {
type: 'crontab' ,
value: '*/30 * * * *' ,
},
checkinMargin: 2 ,
maxRuntime: 10 ,
timezone: 'America/Los_Angeles' ,
},
),
);
} ,
},
) ;
Custom Spans
import * as Sentry from '@sentry/cloudflare' ;
export default Sentry . withSentry (
( env ) => ({ dsn: env . SENTRY_DSN }),
{
async fetch ( request , env , ctx ) {
return await Sentry . startSpan (
{
name: 'http.server' ,
op: 'http.server' ,
attributes: {
'http.method' : request . method ,
'http.url' : request . url ,
},
},
async () => {
const data = await Sentry . startSpan (
{ name: 'fetch-data' , op: 'db.query' },
async () => {
return await env . DB . prepare ( 'SELECT * FROM data' ). all ();
},
);
return Response . json ( data );
},
);
} ,
},
) ;
Context & User Information
Set User Context
import * as Sentry from '@sentry/cloudflare' ;
export default Sentry . withSentry (
( env ) => ({ dsn: env . SENTRY_DSN }),
{
async fetch ( request , env , ctx ) {
// Extract user from request
const userId = request . headers . get ( 'x-user-id' );
if ( userId ) {
Sentry . setUser ({
id: userId ,
});
}
// Your handler code
} ,
},
) ;
Add Context & Tags
import * as Sentry from '@sentry/cloudflare' ;
Sentry . setContext ( 'cloudflare' , {
colo: request . cf ?. colo ,
country: request . cf ?. country ,
city: request . cf ?. city ,
});
Sentry . setTag ( 'edge_location' , request . cf ?. colo );
Sentry . setTag ( 'country' , request . cf ?. country );
Breadcrumbs
import * as Sentry from '@sentry/cloudflare' ;
Sentry . addBreadcrumb ({
category: 'cache' ,
message: 'Cache miss' ,
level: 'info' ,
data: {
key: cacheKey ,
},
});
Cloudflare KV
Track KV operations:
import * as Sentry from '@sentry/cloudflare' ;
interface Env {
KV : KVNamespace ;
SENTRY_DSN : string ;
}
export default Sentry . withSentry (
( env ) => ({ dsn: env . SENTRY_DSN }),
{
async fetch ( request , env , ctx ) {
const value = await Sentry . startSpan (
{
name: 'kv.get' ,
op: 'db.query' ,
attributes: {
'db.system' : 'cloudflare-kv' ,
},
},
async () => {
return await env . KV . get ( 'key' );
},
);
return Response . json ({ value });
} ,
},
) ;
Cloudflare R2
Track R2 operations:
import * as Sentry from '@sentry/cloudflare' ;
interface Env {
BUCKET : R2Bucket ;
SENTRY_DSN : string ;
}
export default Sentry . withSentry (
( env ) => ({ dsn: env . SENTRY_DSN }),
{
async fetch ( request , env , ctx ) {
const object = await Sentry . startSpan (
{
name: 'r2.get' ,
op: 'storage.get' ,
attributes: {
'storage.system' : 'cloudflare-r2' ,
},
},
async () => {
return await env . BUCKET . get ( 'file.txt' );
},
);
return new Response ( object ?. body );
} ,
},
) ;
Durable Objects
Instrument Durable Objects:
import * as Sentry from '@sentry/cloudflare' ;
export class Counter {
private state : DurableObjectState ;
private env : Env ;
private count = 0 ;
constructor ( state : DurableObjectState , env : Env ) {
this . state = state ;
this . env = env ;
Sentry . init ({
dsn: env . SENTRY_DSN ,
});
}
async fetch ( request : Request ) {
try {
return await Sentry . startSpan (
{ name: 'durable-object.fetch' , op: 'function' },
async () => {
this . count ++ ;
return Response . json ({ count: this . count });
},
);
} catch ( error ) {
Sentry . captureException ( error );
return new Response ( 'Error' , { status: 500 });
}
}
}
Source Maps
Configure source map upload:
npx @sentry/wizard@latest -i sourcemaps
Or manually in wrangler.toml:
[ build ]
command = "npm run build"
[ build . upload ]
format = "service-worker"
main = "./dist/index.js"
Best Practices
Middleware First Always place Sentry middleware first in the chain.
Environment Variables Store your DSN in environment variables, not in code.
Instrument Storage Use instrumentD1WithSentry to track database queries.
Monitor Crons Use withMonitor to track scheduled tasks.
Configuration
import * as Sentry from '@sentry/cloudflare' ;
// Cloudflare Workers
export default Sentry . withSentry (
( env ) => ({
dsn: env . SENTRY_DSN ,
// Environment
environment: env . ENVIRONMENT || 'production' ,
release: env . VERSION ,
// Performance
tracesSampleRate: 0.2 ,
// Error filtering
ignoreErrors: [
'AbortError' ,
] ,
beforeSend ( event , hint ) {
// Filter or modify events
if ( event . request ) {
delete event . request . cookies ;
}
return event ;
} ,
}),
{
async fetch ( request , env , ctx ) {
// Your handler
} ,
},
) ;
// Cloudflare Pages
export const onRequest = Sentry . sentryPagesPlugin (( context ) => ({
dsn: context . env . SENTRY_DSN ,
environment: context . env . ENVIRONMENT ,
tracesSampleRate: 0.2 ,
beforeSend ( event ) {
// Filter events
return event ;
},
}));
Common Patterns
API Routes
Authentication
import * as Sentry from '@sentry/cloudflare' ;
const routes = {
'/api/users' : handleUsers ,
'/api/posts' : handlePosts ,
};
export default Sentry . withSentry (
( env ) => ({ dsn: env . SENTRY_DSN }),
{
async fetch ( request , env , ctx ) {
const url = new URL ( request . url );
const handler = routes [ url . pathname ];
if ( ! handler ) {
return new Response ( 'Not Found' , { status: 404 });
}
try {
return await handler ( request , env , ctx );
} catch ( error ) {
Sentry . captureException ( error );
return new Response ( 'Error' , { status: 500 });
}
} ,
},
) ;
import * as Sentry from '@sentry/cloudflare' ;
export default Sentry . withSentry (
( env ) => ({ dsn: env . SENTRY_DSN }),
{
async fetch ( request , env , ctx ) {
const token = request . headers . get ( 'authorization' );
if ( ! token ) {
return new Response ( 'Unauthorized' , { status: 401 });
}
try {
const user = await verifyToken ( token );
Sentry . setUser ({
id: user . id ,
email: user . email ,
});
// Process request
} catch ( error ) {
Sentry . captureException ( error );
return new Response ( 'Invalid token' , { status: 401 });
}
} ,
},
) ;
Next Steps
Cloudflare Docs Official Cloudflare Workers documentation
D1 Database Learn about Cloudflare D1
Source Maps Upload source maps for production
Performance Performance monitoring guide