Claude Code for Sentry: Error Monitoring and Performance Tracing — Claude Skills 360 Blog
Blog / Tooling / Claude Code for Sentry: Error Monitoring and Performance Tracing
Tooling

Claude Code for Sentry: Error Monitoring and Performance Tracing

Published: March 24, 2027
Read time: 8 min read
By: Claude Skills 360

Sentry captures unhandled errors, performance bottlenecks, and user session replays. Sentry.init({ dsn, environment, release, tracesSampleRate }) initializes the SDK. Sentry.captureException(error) sends a caught error with full stack trace. Sentry.withScope(scope => { scope.setExtra("key", value); Sentry.captureException(e) }) enriches errors with contextual data. Sentry.setUser({ id, email }) associates errors with users. Sentry.addBreadcrumb({ message, category, level }) adds trail markers. startSpan({ name, op }) creates performance spans. tracesSampleRate controls the percentage of transactions sampled. beforeSend(event) filters or augments events before sending. withSentryConfig wraps the Next.js config for source map uploads. Session replay records user interactions for visual debugging. Claude Code generates Sentry initialization, error boundaries, performance instrumentation, source map configuration, and filtering patterns for production error monitoring.

CLAUDE.md for Sentry

## Sentry Stack
- Version: @sentry/nextjs >= 8.0, @sentry/node >= 8.0
- Init: Sentry.init({ dsn, environment, release, tracesSampleRate: 0.1 })
- Next.js: sentry.client.config.ts, sentry.server.config.ts, sentry.edge.config.ts
- Capture: Sentry.captureException(error, { extra: { context } })
- User: Sentry.setUser({ id, email, username }) — after auth
- Span: Sentry.startSpan({ name: "db.query", op: "db" }, async span => { ... })
- Filter: beforeSend: (event) => event.level === "info" ? null : event
- Source maps: withSentryConfig(nextConfig, { org, project, authToken })

Sentry Initialization

// sentry.client.config.ts — browser initialization
import * as Sentry from "@sentry/nextjs"

Sentry.init({
  dsn: process.env.NEXT_PUBLIC_SENTRY_DSN,
  environment: process.env.NEXT_PUBLIC_ENVIRONMENT ?? "development",

  // Performance — sample 10% of transactions in prod
  tracesSampleRate: process.env.NODE_ENV === "production" ? 0.1 : 1.0,

  // Session replay — capture 10% of sessions, 100% on error
  replaysSessionSampleRate: 0.1,
  replaysOnErrorSampleRate: 1.0,

  integrations: [
    Sentry.replayIntegration({
      maskAllText: false,
      blockAllMedia: false,
      maskAllInputs: true,  // Privacy: always mask form inputs
    }),
  ],

  // Filter noisy/irrelevant errors
  beforeSend(event, hint) {
    // Drop network errors from ad blockers
    if (event.exception?.values?.[0]?.type === "TypeError") {
      const msg = event.exception.values[0].value ?? ""
      if (msg.includes("Failed to fetch") || msg.includes("Load failed")) {
        return null  // Don't send
      }
    }

    // Drop errors from known browser extensions
    const frames = event.exception?.values?.[0]?.stacktrace?.frames ?? []
    if (frames.some(f => f.filename?.includes("chrome-extension"))) {
      return null
    }

    return event
  },

  // Add user-defined tags to all events
  initialScope: {
    tags: {
      app_version: process.env.NEXT_PUBLIC_APP_VERSION ?? "unknown",
    },
  },
})
// sentry.server.config.ts — Node.js server initialization
import * as Sentry from "@sentry/nextjs"

Sentry.init({
  dsn: process.env.SENTRY_DSN,
  environment: process.env.ENVIRONMENT ?? "development",
  tracesSampleRate: process.env.NODE_ENV === "production" ? 0.1 : 1.0,

  // Profile 10% of sampled transactions
  profilesSampleRate: 0.1,

  integrations: [
    // Auto-instrument Prisma queries (or your ORM)
    Sentry.prismaIntegration(),
  ],

  beforeSend(event) {
    // Scrub sensitive values from server errors
    if (event.request?.data) {
      const data = event.request.data as Record<string, unknown>
      delete data.password
      delete data.creditCard
      delete data.ssn
    }
    return event
  },
})

Error Capture Patterns

// lib/error-reporting.ts — typed error capture utilities
import * as Sentry from "@sentry/nextjs"

interface ErrorContext {
  userId?: string
  orderId?: string
  operation?: string
  extra?: Record<string, unknown>
}

// Capture with rich context
export function captureError(error: unknown, context: ErrorContext = {}) {
  Sentry.withScope(scope => {
    if (context.userId) scope.setUser({ id: context.userId })
    if (context.orderId) scope.setTag("orderId", context.orderId)
    if (context.operation) scope.setTag("operation", context.operation)
    if (context.extra) Object.entries(context.extra).forEach(([k, v]) => scope.setExtra(k, v))

    scope.setLevel("error")
    Sentry.captureException(error)
  })
}

// API route error wrapper
export function withErrorReporting<T>(
  fn: () => Promise<T>,
  context: ErrorContext
): Promise<T> {
  return fn().catch(error => {
    captureError(error, context)
    throw error  // Re-throw after reporting
  })
}

// Add navigation breadcrumb (call on route changes)
export function addNavigationBreadcrumb(from: string, to: string) {
  Sentry.addBreadcrumb({
    message: `Navigate from ${from} to ${to}`,
    category: "navigation",
    level: "info",
    data: { from, to },
  })
}

// Record user actions for replay context
export function trackUserAction(action: string, data?: Record<string, unknown>) {
  Sentry.addBreadcrumb({
    message: action,
    category: "user",
    level: "info",
    data,
  })
}

React Error Boundary

// components/ErrorBoundary.tsx — Sentry React error boundary
"use client"
import * as Sentry from "@sentry/nextjs"
import { Component, type ReactNode, type ErrorInfo } from "react"

interface Props {
  children: ReactNode
  fallback?: ReactNode | ((error: Error, reset: () => void) => ReactNode)
  onError?: (error: Error, errorInfo: ErrorInfo) => void
}

interface State {
  error: Error | null
  eventId: string | null
}

export class SentryErrorBoundary extends Component<Props, State> {
  state: State = { error: null, eventId: null }

  static getDerivedStateFromError(error: Error): Partial<State> {
    return { error }
  }

  componentDidCatch(error: Error, errorInfo: ErrorInfo) {
    const eventId = Sentry.captureException(error, {
      extra: {
        componentStack: errorInfo.componentStack,
      },
    })
    this.setState({ eventId })
    this.props.onError?.(error, errorInfo)
  }

  reset = () => this.setState({ error: null, eventId: null })

  render() {
    if (this.state.error) {
      if (typeof this.props.fallback === "function") {
        return this.props.fallback(this.state.error, this.reset)
      }
      if (this.props.fallback) return this.props.fallback

      return (
        <div className="flex flex-col items-center justify-center p-8 text-center">
          <h2 className="text-lg font-semibold mb-2">Something went wrong</h2>
          <p className="text-muted-foreground text-sm mb-4">
            Error ID: {this.state.eventId}
          </p>
          <button
            onClick={this.reset}
            className="px-4 py-2 bg-primary text-white rounded text-sm"
          >
            Try again
          </button>
          <button
            onClick={() => Sentry.showReportDialog({ eventId: this.state.eventId! })}
            className="mt-2 px-4 py-2 border rounded text-sm"
          >
            Report this issue
          </button>
        </div>
      )
    }

    return this.props.children
  }
}

Performance Tracing

// lib/tracing.ts — custom spans for performance
import * as Sentry from "@sentry/nextjs"

// Trace a database query
export async function traceDbQuery<T>(
  queryName: string,
  query: () => Promise<T>
): Promise<T> {
  return Sentry.startSpan(
    { name: queryName, op: "db.query", attributes: { "db.system": "postgresql" } },
    () => query()
  )
}

// Trace an external API call
export async function traceExternalCall<T>(
  service: string,
  operation: string,
  fn: () => Promise<T>
): Promise<T> {
  return Sentry.startSpan(
    {
      name: `${service}.${operation}`,
      op: "http.client",
      attributes: { "peer.service": service },
    },
    () => fn()
  )
}

// Example: traced order service
export async function createOrderTraced(input: { customerId: string }) {
  return Sentry.startSpan({ name: "order.create", op: "function" }, async span => {
    span?.setAttribute("customerId", input.customerId)

    const [customer, inventory] = await Promise.all([
      traceDbQuery("customer.fetch", () => fetchCustomer(input.customerId)),
      traceDbQuery("inventory.check", () => checkInventory()),
    ])

    const order = await traceDbQuery("order.insert", () => insertOrder(customer, inventory))

    await traceExternalCall("stripe", "charge.create", () =>
      chargeStripe(order.totalCents)
    )

    return order
  })
}

async function fetchCustomer(id: string) { return { id, email: "" } }
async function checkInventory() { return true }
async function insertOrder(_c: unknown, _i: unknown) { return { id: "ord_1", totalCents: 1000 } }
async function chargeStripe(_cents: number) { return { id: "ch_1" } }

Next.js Configuration

// next.config.js — source maps + Sentry webpack integration
import { withSentryConfig } from "@sentry/nextjs"

const nextConfig = {
  // your next.js config
}

export default withSentryConfig(nextConfig, {
  org: process.env.SENTRY_ORG,
  project: process.env.SENTRY_PROJECT,
  authToken: process.env.SENTRY_AUTH_TOKEN,

  // Upload source maps to Sentry (removes them from public bundle)
  silent: true,
  hideSourceMaps: true,
  disableLogger: true,

  // Automatically tree-shake Sentry logger statements
  automaticVercelMonitors: true,
})

For the Datadog alternative when APM, infrastructure metrics, log management, and error tracking are all needed in a single unified platform — Datadog integrates errors with host-level metrics and distributed tracing across microservices in a way that Sentry’s standalone error tracking does not, see the observability platform comparison. For the OpenTelemetry alternative when vendor-agnostic tracing exportable to multiple backends (Jaeger, Zipkin, Datadog, Honeycomb) is needed — OpenTelemetry provides the instrumentation standard while Sentry acts as one of many possible exporters, see the OpenTelemetry guide for distributed tracing pipelines. The Claude Skills 360 bundle includes Sentry skill sets covering error capture, performance tracing, and source map configuration. Start with the free tier to try error monitoring integration generation.

Put these ideas into practice

Claude Skills 360 gives you production-ready skills for everything in this article — and 2,350+ more. Start free or go all-in.

Back to Blog

Get 360 skills free