@danieljvdm/dev-kit 1.0.2 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -6
- package/package.json +1 -1
- package/skill-sources.jsonc +2 -33
- package/skill-sources.lock.json +15 -117
- package/skills/animate/LICENSE +21 -0
- package/skills/animate/NOTICE +10 -0
- package/skills/animate/SKILL.md +34 -0
- package/skills/animate/references/gestures.md +27 -0
- package/skills/animate/references/glossary.md +136 -0
- package/skills/animate/references/implementation.md +22 -0
- package/skills/animate/references/opportunities.md +18 -0
- package/skills/animate/references/principles.md +48 -0
- package/skills/animate/references/review.md +19 -0
- package/skills/cloudflare-workers/LICENSE +202 -0
- package/skills/cloudflare-workers/NOTICE +9 -0
- package/skills/cloudflare-workers/SKILL.md +26 -0
- package/skills/cloudflare-workers/references/durable-objects.md +68 -0
- package/skills/cloudflare-workers/references/sandbox.md +48 -0
- package/skills/cloudflare-workers/references/workers.md +63 -0
- package/skills/cloudflare-workers/references/wrangler.md +56 -0
- package/skills/design-ui/LICENSE +21 -0
- package/skills/design-ui/NOTICE +8 -0
- package/skills/design-ui/SKILL.md +29 -0
- package/skills/design-ui/references/appearance.md +22 -0
- package/skills/design-ui/references/components.md +33 -0
- package/skills/design-ui/references/exploration.md +50 -0
- package/skills/design-ui/references/libraries.md +39 -0
- package/skills/design-ui/references/themes.md +23 -0
- package/skills/dev-kit/SKILL.md +19 -38
- package/skills/dev-kit/references/cloudflare-worker-api.md +1 -1
- package/skills/dev-kit/references/skills.md +2 -2
- package/skills/effect-development/SKILL.md +27 -0
- package/skills/effect-development/agents/openai.yaml +4 -0
- package/skills/effect-development/references/api/index.md +32 -0
- package/skills/effect-development/references/api/schema-codecs.md +15 -0
- package/skills/{build-effect-apis/references → effect-development/references/api}/verification.md +10 -5
- package/skills/{effect-architecture-audit/SKILL.md → effect-development/references/architecture/index.md} +1 -6
- package/skills/{effect-atom-state/references → effect-development/references/atom}/effect-atom-client.md +8 -6
- package/skills/{effect-atom-state/references → effect-development/references/atom}/effect-atom-testing.md +7 -2
- package/skills/effect-development/references/atom/index.md +40 -0
- package/skills/{build-effect-clis/references → effect-development/references/cli}/entrypoints-and-testing.md +6 -2
- package/skills/effect-development/references/cli/index.md +39 -0
- package/skills/effect-development/references/setup.md +15 -0
- package/skills/open-pull-request/SKILL.md +10 -70
- package/skills/open-pull-request/references/evidence.md +22 -0
- package/skills/open-pull-request/references/explanation.md +21 -0
- package/skills/open-pull-request/references/publication.md +21 -0
- package/skills/sentry/LICENSE +202 -0
- package/skills/sentry/LICENSE-UPSTREAM +21 -0
- package/skills/sentry/NOTICE +14 -0
- package/skills/sentry/SKILL.md +33 -0
- package/skills/sentry/references/alert-payloads.md +105 -0
- package/skills/sentry/references/alerts.md +17 -0
- package/skills/sentry/references/artifacts.md +25 -0
- package/skills/sentry/references/auth-token.md +65 -0
- package/skills/sentry/references/concepts/ai-monitoring.md +131 -0
- package/skills/sentry/references/concepts/choosing-a-signal.md +78 -0
- package/skills/sentry/references/concepts/crons.md +50 -0
- package/skills/sentry/references/concepts/data-scrubbing.md +43 -0
- package/skills/sentry/references/concepts/errors.md +40 -0
- package/skills/sentry/references/concepts/logging.md +85 -0
- package/skills/sentry/references/concepts/metrics.md +49 -0
- package/skills/sentry/references/concepts/monitors.md +78 -0
- package/skills/sentry/references/concepts/profiling.md +38 -0
- package/skills/sentry/references/concepts/reduce-volume.md +49 -0
- package/skills/sentry/references/concepts/releases.md +43 -0
- package/skills/sentry/references/concepts/session-replay.md +35 -0
- package/skills/sentry/references/concepts/tracing.md +54 -0
- package/skills/sentry/references/concepts/user-feedback.md +36 -0
- package/skills/sentry/references/debug-artifacts/android.md +68 -0
- package/skills/sentry/references/debug-artifacts/apple.md +96 -0
- package/skills/sentry/references/debug-artifacts/dotnet.md +70 -0
- package/skills/sentry/references/debug-artifacts/flutter.md +65 -0
- package/skills/sentry/references/debug-artifacts/index.md +75 -0
- package/skills/sentry/references/debug-artifacts/javascript.md +94 -0
- package/skills/sentry/references/debug-artifacts/matching.md +73 -0
- package/skills/sentry/references/debug-artifacts/react-native.md +75 -0
- package/skills/sentry/references/first-error-setup.md +25 -0
- package/skills/sentry/references/instrumentation.md +30 -0
- package/skills/sentry/references/issues.md +32 -0
- package/skills/sentry/references/new-project.md +17 -0
- package/skills/sentry/references/otel-exporter.md +30 -0
- package/skills/sentry/references/release-workflow.md +31 -0
- package/skills/sentry/references/releases/ci-pipeline.md +214 -0
- package/skills/sentry/references/releases/index.md +93 -0
- package/skills/sentry/references/releases/suspect-commits.md +155 -0
- package/skills/sentry/references/releases/tagging.md +131 -0
- package/skills/sentry/references/releases/troubleshooting.md +67 -0
- package/skills/sentry/references/sdks/android/crons.md +305 -0
- package/skills/sentry/references/sdks/android/error-monitoring.md +800 -0
- package/skills/sentry/references/sdks/android/index.md +748 -0
- package/skills/sentry/references/sdks/android/integrations.md +48 -0
- package/skills/sentry/references/sdks/android/logging.md +374 -0
- package/skills/sentry/references/sdks/android/metrics.md +288 -0
- package/skills/sentry/references/sdks/android/profiling.md +397 -0
- package/skills/sentry/references/sdks/android/session-replay.md +406 -0
- package/skills/sentry/references/sdks/android/tracing.md +861 -0
- package/skills/sentry/references/sdks/browser/error-monitoring.md +861 -0
- package/skills/sentry/references/sdks/browser/index.md +714 -0
- package/skills/sentry/references/sdks/browser/logging.md +315 -0
- package/skills/sentry/references/sdks/browser/profiling.md +236 -0
- package/skills/sentry/references/sdks/browser/session-replay.md +586 -0
- package/skills/sentry/references/sdks/browser/tracing.md +561 -0
- package/skills/sentry/references/sdks/browser/user-feedback.md +354 -0
- package/skills/sentry/references/sdks/cloudflare/ai-monitoring.md +661 -0
- package/skills/sentry/references/sdks/cloudflare/crons.md +231 -0
- package/skills/sentry/references/sdks/cloudflare/durable-objects.md +381 -0
- package/skills/sentry/references/sdks/cloudflare/error-monitoring.md +329 -0
- package/skills/sentry/references/sdks/cloudflare/index.md +698 -0
- package/skills/sentry/references/sdks/cloudflare/logging.md +169 -0
- package/skills/sentry/references/sdks/cloudflare/nodejs-compat.md +134 -0
- package/skills/sentry/references/sdks/cloudflare/tracing.md +475 -0
- package/skills/sentry/references/sdks/cocoa/error-monitoring.md +394 -0
- package/skills/sentry/references/sdks/cocoa/index.md +497 -0
- package/skills/sentry/references/sdks/cocoa/logging.md +209 -0
- package/skills/sentry/references/sdks/cocoa/metrics.md +136 -0
- package/skills/sentry/references/sdks/cocoa/profiling.md +223 -0
- package/skills/sentry/references/sdks/cocoa/session-replay.md +257 -0
- package/skills/sentry/references/sdks/cocoa/tracing.md +524 -0
- package/skills/sentry/references/sdks/cocoa/user-feedback.md +310 -0
- package/skills/sentry/references/sdks/dotnet/crons.md +465 -0
- package/skills/sentry/references/sdks/dotnet/error-monitoring.md +1100 -0
- package/skills/sentry/references/sdks/dotnet/index.md +614 -0
- package/skills/sentry/references/sdks/dotnet/logging.md +556 -0
- package/skills/sentry/references/sdks/dotnet/metrics.md +229 -0
- package/skills/sentry/references/sdks/dotnet/profiling.md +296 -0
- package/skills/sentry/references/sdks/dotnet/tracing.md +897 -0
- package/skills/sentry/references/sdks/elixir/crons.md +371 -0
- package/skills/sentry/references/sdks/elixir/error-monitoring.md +335 -0
- package/skills/sentry/references/sdks/elixir/index.md +383 -0
- package/skills/sentry/references/sdks/elixir/logging.md +239 -0
- package/skills/sentry/references/sdks/elixir/tracing.md +233 -0
- package/skills/sentry/references/sdks/flutter/ecosystem-integrations.md +70 -0
- package/skills/sentry/references/sdks/flutter/error-monitoring.md +312 -0
- package/skills/sentry/references/sdks/flutter/index.md +728 -0
- package/skills/sentry/references/sdks/flutter/logging.md +387 -0
- package/skills/sentry/references/sdks/flutter/metrics.md +310 -0
- package/skills/sentry/references/sdks/flutter/profiling.md +214 -0
- package/skills/sentry/references/sdks/flutter/session-replay.md +308 -0
- package/skills/sentry/references/sdks/flutter/tracing.md +502 -0
- package/skills/sentry/references/sdks/go/crons.md +270 -0
- package/skills/sentry/references/sdks/go/error-monitoring.md +361 -0
- package/skills/sentry/references/sdks/go/index.md +324 -0
- package/skills/sentry/references/sdks/go/logging.md +354 -0
- package/skills/sentry/references/sdks/go/metrics.md +273 -0
- package/skills/sentry/references/sdks/go/profiling.md +46 -0
- package/skills/sentry/references/sdks/go/tracing.md +366 -0
- package/skills/sentry/references/sdks/index.md +41 -0
- package/skills/sentry/references/sdks/nestjs/ai-monitoring.md +410 -0
- package/skills/sentry/references/sdks/nestjs/crons.md +268 -0
- package/skills/sentry/references/sdks/nestjs/error-monitoring.md +729 -0
- package/skills/sentry/references/sdks/nestjs/index.md +699 -0
- package/skills/sentry/references/sdks/nestjs/logging.md +174 -0
- package/skills/sentry/references/sdks/nestjs/metrics.md +243 -0
- package/skills/sentry/references/sdks/nestjs/profiling.md +127 -0
- package/skills/sentry/references/sdks/nestjs/tracing.md +762 -0
- package/skills/sentry/references/sdks/nextjs/ai-monitoring.md +494 -0
- package/skills/sentry/references/sdks/nextjs/crons.md +383 -0
- package/skills/sentry/references/sdks/nextjs/error-monitoring.md +974 -0
- package/skills/sentry/references/sdks/nextjs/index.md +491 -0
- package/skills/sentry/references/sdks/nextjs/logging.md +381 -0
- package/skills/sentry/references/sdks/nextjs/metrics.md +411 -0
- package/skills/sentry/references/sdks/nextjs/profiling.md +403 -0
- package/skills/sentry/references/sdks/nextjs/session-replay.md +462 -0
- package/skills/sentry/references/sdks/nextjs/tracing.md +628 -0
- package/skills/sentry/references/sdks/node/ai-monitoring.md +303 -0
- package/skills/sentry/references/sdks/node/crons.md +432 -0
- package/skills/sentry/references/sdks/node/error-monitoring.md +1125 -0
- package/skills/sentry/references/sdks/node/index.md +942 -0
- package/skills/sentry/references/sdks/node/logging.md +380 -0
- package/skills/sentry/references/sdks/node/metrics.md +278 -0
- package/skills/sentry/references/sdks/node/profiling.md +373 -0
- package/skills/sentry/references/sdks/node/tracing.md +878 -0
- package/skills/sentry/references/sdks/php/ai-monitoring.md +310 -0
- package/skills/sentry/references/sdks/php/crons.md +265 -0
- package/skills/sentry/references/sdks/php/error-monitoring.md +626 -0
- package/skills/sentry/references/sdks/php/index.md +362 -0
- package/skills/sentry/references/sdks/php/laravel.md +542 -0
- package/skills/sentry/references/sdks/php/logging.md +242 -0
- package/skills/sentry/references/sdks/php/metrics.md +193 -0
- package/skills/sentry/references/sdks/php/profiling.md +115 -0
- package/skills/sentry/references/sdks/php/symfony.md +552 -0
- package/skills/sentry/references/sdks/php/tracing.md +516 -0
- package/skills/sentry/references/sdks/python/ai-monitoring.md +351 -0
- package/skills/sentry/references/sdks/python/crons.md +218 -0
- package/skills/sentry/references/sdks/python/error-monitoring.md +292 -0
- package/skills/sentry/references/sdks/python/index.md +361 -0
- package/skills/sentry/references/sdks/python/logging.md +234 -0
- package/skills/sentry/references/sdks/python/metrics.md +154 -0
- package/skills/sentry/references/sdks/python/profiling.md +120 -0
- package/skills/sentry/references/sdks/python/tracing.md +364 -0
- package/skills/sentry/references/sdks/react/error-monitoring.md +1607 -0
- package/skills/sentry/references/sdks/react/index.md +492 -0
- package/skills/sentry/references/sdks/react/logging.md +364 -0
- package/skills/sentry/references/sdks/react/profiling.md +322 -0
- package/skills/sentry/references/sdks/react/react-features.md +1272 -0
- package/skills/sentry/references/sdks/react/session-replay.md +1193 -0
- package/skills/sentry/references/sdks/react/tracing.md +1415 -0
- package/skills/sentry/references/sdks/react-native/error-monitoring.md +1481 -0
- package/skills/sentry/references/sdks/react-native/expo-config-plugin.md +45 -0
- package/skills/sentry/references/sdks/react-native/index.md +1030 -0
- package/skills/sentry/references/sdks/react-native/logging.md +444 -0
- package/skills/sentry/references/sdks/react-native/profiling.md +386 -0
- package/skills/sentry/references/sdks/react-native/session-replay.md +704 -0
- package/skills/sentry/references/sdks/react-native/tracing.md +1086 -0
- package/skills/sentry/references/sdks/react-native/user-feedback.md +815 -0
- package/skills/sentry/references/sdks/react-router-framework/error-monitoring.md +127 -0
- package/skills/sentry/references/sdks/react-router-framework/index.md +411 -0
- package/skills/sentry/references/sdks/react-router-framework/logging.md +66 -0
- package/skills/sentry/references/sdks/react-router-framework/profiling.md +57 -0
- package/skills/sentry/references/sdks/react-router-framework/react-router-framework-features.md +110 -0
- package/skills/sentry/references/sdks/react-router-framework/session-replay.md +67 -0
- package/skills/sentry/references/sdks/react-router-framework/tracing.md +96 -0
- package/skills/sentry/references/sdks/react-router-framework/user-feedback.md +71 -0
- package/skills/sentry/references/sdks/ruby/crons.md +184 -0
- package/skills/sentry/references/sdks/ruby/error-monitoring.md +248 -0
- package/skills/sentry/references/sdks/ruby/index.md +297 -0
- package/skills/sentry/references/sdks/ruby/logging.md +168 -0
- package/skills/sentry/references/sdks/ruby/metrics.md +196 -0
- package/skills/sentry/references/sdks/ruby/migration.md +321 -0
- package/skills/sentry/references/sdks/ruby/profiling.md +107 -0
- package/skills/sentry/references/sdks/ruby/tracing.md +388 -0
- package/skills/sentry/references/sdks/svelte/error-monitoring.md +456 -0
- package/skills/sentry/references/sdks/svelte/index.md +467 -0
- package/skills/sentry/references/sdks/svelte/logging.md +344 -0
- package/skills/sentry/references/sdks/svelte/session-replay.md +369 -0
- package/skills/sentry/references/sdks/svelte/tracing.md +406 -0
- package/skills/sentry/references/sdks/tanstack-start/error-monitoring.md +149 -0
- package/skills/sentry/references/sdks/tanstack-start/index.md +381 -0
- package/skills/sentry/references/sdks/tanstack-start/logging.md +74 -0
- package/skills/sentry/references/sdks/tanstack-start/session-replay.md +76 -0
- package/skills/sentry/references/sdks/tanstack-start/tanstackstart-features.md +128 -0
- package/skills/sentry/references/sdks/tanstack-start/tracing.md +123 -0
- package/skills/sentry/references/sdks/tanstack-start/user-feedback.md +81 -0
- package/skills/sentry/references/search-query-language.md +226 -0
- package/skills/sentry/references/semantics/angular.md +7 -0
- package/skills/sentry/references/semantics/app.md +28 -0
- package/skills/sentry/references/semantics/art.md +17 -0
- package/skills/sentry/references/semantics/aws.md +43 -0
- package/skills/sentry/references/semantics/browser.md +34 -0
- package/skills/sentry/references/semantics/cache.md +12 -0
- package/skills/sentry/references/semantics/client.md +8 -0
- package/skills/sentry/references/semantics/cloud.md +12 -0
- package/skills/sentry/references/semantics/cloudflare.md +23 -0
- package/skills/sentry/references/semantics/code.md +11 -0
- package/skills/sentry/references/semantics/culture.md +11 -0
- package/skills/sentry/references/semantics/db.md +21 -0
- package/skills/sentry/references/semantics/device.md +43 -0
- package/skills/sentry/references/semantics/error.md +7 -0
- package/skills/sentry/references/semantics/event.md +8 -0
- package/skills/sentry/references/semantics/exception.md +10 -0
- package/skills/sentry/references/semantics/faas.md +19 -0
- package/skills/sentry/references/semantics/file.md +8 -0
- package/skills/sentry/references/semantics/flag.md +7 -0
- package/skills/sentry/references/semantics/gcp.md +16 -0
- package/skills/sentry/references/semantics/gen_ai.md +53 -0
- package/skills/sentry/references/semantics/general.md +11 -0
- package/skills/sentry/references/semantics/graphql.md +9 -0
- package/skills/sentry/references/semantics/grpc.md +19 -0
- package/skills/sentry/references/semantics/http.md +34 -0
- package/skills/sentry/references/semantics/index.md +63 -0
- package/skills/sentry/references/semantics/jsonrpc.md +8 -0
- package/skills/sentry/references/semantics/jvm.md +12 -0
- package/skills/sentry/references/semantics/koa.md +7 -0
- package/skills/sentry/references/semantics/logger.md +7 -0
- package/skills/sentry/references/semantics/mcp.md +37 -0
- package/skills/sentry/references/semantics/mdc.md +7 -0
- package/skills/sentry/references/semantics/messaging.md +23 -0
- package/skills/sentry/references/semantics/middleware.md +7 -0
- package/skills/sentry/references/semantics/navigation.md +9 -0
- package/skills/sentry/references/semantics/nel.md +11 -0
- package/skills/sentry/references/semantics/network.md +17 -0
- package/skills/sentry/references/semantics/os.md +15 -0
- package/skills/sentry/references/semantics/otel.md +10 -0
- package/skills/sentry/references/semantics/params.md +7 -0
- package/skills/sentry/references/semantics/process.md +14 -0
- package/skills/sentry/references/semantics/react.md +7 -0
- package/skills/sentry/references/semantics/remix.md +7 -0
- package/skills/sentry/references/semantics/resource.md +7 -0
- package/skills/sentry/references/semantics/rpc.md +10 -0
- package/skills/sentry/references/semantics/score.md +10 -0
- package/skills/sentry/references/semantics/sentry.md +69 -0
- package/skills/sentry/references/semantics/server.md +8 -0
- package/skills/sentry/references/semantics/service.md +8 -0
- package/skills/sentry/references/semantics/session.md +7 -0
- package/skills/sentry/references/semantics/state.md +7 -0
- package/skills/sentry/references/semantics/thread.md +8 -0
- package/skills/sentry/references/semantics/timber.md +7 -0
- package/skills/sentry/references/semantics/trpc.md +8 -0
- package/skills/sentry/references/semantics/ui.md +18 -0
- package/skills/sentry/references/semantics/url.md +15 -0
- package/skills/sentry/references/semantics/user.md +17 -0
- package/skills/sentry/references/semantics/user_agent.md +7 -0
- package/skills/sentry/references/semantics/vercel.md +42 -0
- package/skills/sentry/references/setup-verification.md +39 -0
- package/skills/sentry/references/snapshots/github-actions-fanout.md +206 -0
- package/skills/sentry/references/snapshots/github-actions-simple.md +102 -0
- package/skills/sentry/references/snapshots/github-actions-swift-snapshot-testing.md +118 -0
- package/skills/sentry/references/snapshots/index.md +19 -0
- package/skills/sentry/references/snapshots/snapshot-previews.md +100 -0
- package/skills/sentry/references/snapshots/snapshots.md +123 -0
- package/skills/sentry/references/snapshots/wizard-setup.md +134 -0
- package/skills/testing/LICENSE +21 -0
- package/skills/testing/NOTICE +7 -0
- package/skills/testing/SKILL.md +13 -19
- package/skills/testing/agents/openai.yaml +1 -2
- package/skills/testing/references/selection.md +23 -0
- package/skills/testing/references/tdd.md +19 -0
- package/skills/testing/references/test-design.md +17 -0
- package/src/catalog.ts +1 -7
- package/skills/build-effect-apis/SKILL.md +0 -81
- package/skills/build-effect-apis/agents/openai.yaml +0 -4
- package/skills/build-effect-clis/SKILL.md +0 -92
- package/skills/build-effect-clis/agents/openai.yaml +0 -4
- package/skills/effect-architecture-audit/agents/openai.yaml +0 -4
- package/skills/effect-atom-state/SKILL.md +0 -97
- package/skills/effect-atom-state/agents/openai.yaml +0 -4
- package/skills/effect-ts/SKILL.md +0 -35
- package/skills/effect-ts/agents/openai.yaml +0 -4
- /package/skills/{build-effect-apis/references → effect-development/references/api}/cloudflare-workers.md +0 -0
- /package/skills/{build-effect-apis/references → effect-development/references/api}/runtime-assembly.md +0 -0
- /package/skills/{build-effect-apis/references → effect-development/references/api}/server-and-middleware.md +0 -0
- /package/skills/{build-effect-apis/references → effect-development/references/api}/shared-contracts.md +0 -0
- /package/skills/{effect-architecture-audit/references → effect-development/references/architecture}/service-and-boundary-audit.md +0 -0
- /package/skills/{effect-atom-state/references → effect-development/references/atom}/effect-atom-lifecycle.md +0 -0
- /package/skills/{effect-atom-state/references → effect-development/references/atom}/effect-atom-workflows.md +0 -0
- /package/skills/{effect-atom-state/references → effect-development/references/atom}/tanstack-start.md +0 -0
- /package/skills/{build-effect-clis/references → effect-development/references/cli}/command-design.md +0 -0
- /package/skills/{build-effect-clis/references → effect-development/references/cli}/processes-and-platform.md +0 -0
|
@@ -0,0 +1,1272 @@
|
|
|
1
|
+
# React-Specific Features — Sentry React SDK
|
|
2
|
+
|
|
3
|
+
> Minimum SDK: `@sentry/react` v8.0.0+
|
|
4
|
+
|
|
5
|
+
This is the catch-all deep dive for React-specific Sentry features: Redux integration,
|
|
6
|
+
component tracking, source maps, and the full integrations catalog.
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## Table of Contents
|
|
11
|
+
|
|
12
|
+
1. [Redux Integration](#1-redux-integration)
|
|
13
|
+
2. [Component Tracking & Performance](#2-component-tracking--performance)
|
|
14
|
+
3. [Source Maps](#3-source-maps)
|
|
15
|
+
4. [Default Integrations](#4-default-integrations)
|
|
16
|
+
5. [Optional Integrations](#5-optional-integrations)
|
|
17
|
+
6. [Build Tool Detection & Environment Variables](#6-build-tool-detection--environment-variables)
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## 1. Redux Integration
|
|
22
|
+
|
|
23
|
+
`Sentry.createReduxEnhancer()` hooks into your Redux store to automatically:
|
|
24
|
+
|
|
25
|
+
- Capture **Redux actions as breadcrumbs** on every Sentry error event
|
|
26
|
+
- Attach the **Redux state as a `redux_state.json` file** to error events
|
|
27
|
+
- Keep **Sentry scope tags in sync** with your Redux state
|
|
28
|
+
|
|
29
|
+
### Setup — Redux Toolkit (`configureStore`)
|
|
30
|
+
|
|
31
|
+
```typescript
|
|
32
|
+
import * as Sentry from "@sentry/react";
|
|
33
|
+
import { configureStore } from "@reduxjs/toolkit";
|
|
34
|
+
import rootReducer from "./reducers";
|
|
35
|
+
|
|
36
|
+
const sentryReduxEnhancer = Sentry.createReduxEnhancer({
|
|
37
|
+
// options — see below
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
const store = configureStore({
|
|
41
|
+
reducer: rootReducer,
|
|
42
|
+
enhancers: (getDefaultEnhancers) => {
|
|
43
|
+
return getDefaultEnhancers().concat(sentryReduxEnhancer);
|
|
44
|
+
},
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
export type RootState = ReturnType<typeof store.getState>;
|
|
48
|
+
export type AppDispatch = typeof store.dispatch;
|
|
49
|
+
export default store;
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
> ⚠️ **Critical:** `sentryReduxEnhancer` is a **store enhancer**, not Redux middleware.
|
|
53
|
+
> Do **NOT** pass it inside `applyMiddleware()`.
|
|
54
|
+
|
|
55
|
+
### Setup — Legacy `createStore` with Middleware
|
|
56
|
+
|
|
57
|
+
```javascript
|
|
58
|
+
import { createStore, applyMiddleware, compose } from "redux";
|
|
59
|
+
import thunk from "redux-thunk";
|
|
60
|
+
import * as Sentry from "@sentry/react";
|
|
61
|
+
|
|
62
|
+
const sentryReduxEnhancer = Sentry.createReduxEnhancer();
|
|
63
|
+
|
|
64
|
+
const store = createStore(rootReducer, compose(applyMiddleware(thunk), sentryReduxEnhancer));
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
### Options: `actionTransformer` — Filter/Scrub Actions Before Breadcrumbs
|
|
70
|
+
|
|
71
|
+
Called for every dispatched action.
|
|
72
|
+
Return the action to include it as a breadcrumb, a modified copy to scrub sensitive
|
|
73
|
+
fields, or `null` to drop it entirely.
|
|
74
|
+
|
|
75
|
+
```typescript
|
|
76
|
+
const sentryReduxEnhancer = Sentry.createReduxEnhancer({
|
|
77
|
+
actionTransformer: (action) => {
|
|
78
|
+
// Drop high-volume or sensitive actions entirely
|
|
79
|
+
if (action.type === "WEBSOCKET_PING") return null;
|
|
80
|
+
if (action.type === "FETCH_SECRETS") return null;
|
|
81
|
+
|
|
82
|
+
// Scrub sensitive fields from certain actions
|
|
83
|
+
if (action.type === "USER_LOGIN") {
|
|
84
|
+
return {
|
|
85
|
+
...action,
|
|
86
|
+
password: "[REDACTED]",
|
|
87
|
+
token: "[REDACTED]",
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if (action.type === "UPDATE_PAYMENT") {
|
|
92
|
+
return {
|
|
93
|
+
...action,
|
|
94
|
+
payload: {
|
|
95
|
+
...action.payload,
|
|
96
|
+
cardNumber: null,
|
|
97
|
+
cvv: null,
|
|
98
|
+
},
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Include all other actions as-is
|
|
103
|
+
return action;
|
|
104
|
+
},
|
|
105
|
+
});
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
---
|
|
109
|
+
|
|
110
|
+
### Options: `stateTransformer` — Filter/Scrub State Snapshots
|
|
111
|
+
|
|
112
|
+
Called on every state update.
|
|
113
|
+
Return the state to attach it to error events, a modified copy with sensitive fields
|
|
114
|
+
redacted, or `null` to exclude state entirely.
|
|
115
|
+
|
|
116
|
+
```typescript
|
|
117
|
+
const sentryReduxEnhancer = Sentry.createReduxEnhancer({
|
|
118
|
+
stateTransformer: (state: RootState) => {
|
|
119
|
+
// Return null to send NO state with errors (reduces context but protects PII)
|
|
120
|
+
// if (state.topSecret.active) return null;
|
|
121
|
+
|
|
122
|
+
// Return a scrubbed copy
|
|
123
|
+
return {
|
|
124
|
+
...state,
|
|
125
|
+
auth: {
|
|
126
|
+
...state.auth,
|
|
127
|
+
token: null, // remove auth token
|
|
128
|
+
refreshToken: null,
|
|
129
|
+
password: null,
|
|
130
|
+
},
|
|
131
|
+
user: {
|
|
132
|
+
...state.user,
|
|
133
|
+
ssn: "[REDACTED]",
|
|
134
|
+
creditCard: null,
|
|
135
|
+
dateOfBirth: null,
|
|
136
|
+
},
|
|
137
|
+
// Remove entire subtrees you don't need
|
|
138
|
+
cache: null,
|
|
139
|
+
rawApiResponses: null,
|
|
140
|
+
};
|
|
141
|
+
},
|
|
142
|
+
});
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
> ⚠️ **Warning:** If `stateTransformer` returns `null`, error events will lack Redux
|
|
146
|
+
> state context. Debugging large state-dependent bugs becomes much harder.
|
|
147
|
+
> Prefer returning a filtered copy over returning `null`.
|
|
148
|
+
|
|
149
|
+
---
|
|
150
|
+
|
|
151
|
+
### Options: `configureScopeWithState` — Derive Sentry Tags from Redux State
|
|
152
|
+
|
|
153
|
+
Called after every state update.
|
|
154
|
+
Use it to keep Sentry scope tags/context in sync with your application’s Redux state —
|
|
155
|
+
these tags then appear on every error captured after the update.
|
|
156
|
+
|
|
157
|
+
```typescript
|
|
158
|
+
const sentryReduxEnhancer = Sentry.createReduxEnhancer({
|
|
159
|
+
configureScopeWithState: (scope: Sentry.Scope, state: RootState) => {
|
|
160
|
+
// Tag events with current user plan (great for filtering errors by customer tier)
|
|
161
|
+
scope.setTag("user.plan", state.user.plan);
|
|
162
|
+
scope.setTag("user.id", state.user.id);
|
|
163
|
+
|
|
164
|
+
// Tag with feature flag state
|
|
165
|
+
scope.setTag("feature.newCheckout", String(state.features.newCheckout));
|
|
166
|
+
scope.setTag("feature.darkMode", String(state.settings.darkMode));
|
|
167
|
+
|
|
168
|
+
// Tag with routing/navigation state
|
|
169
|
+
scope.setTag("app.currentFlow", state.navigation.currentFlow);
|
|
170
|
+
|
|
171
|
+
// Conditional tags based on state shape
|
|
172
|
+
if (state.settings.useImperialUnits) {
|
|
173
|
+
scope.setTag("user.usesImperialUnits", "true");
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// Set structured context (not searchable but visible in issue detail)
|
|
177
|
+
scope.setContext("cart", {
|
|
178
|
+
itemCount: state.cart.items.length,
|
|
179
|
+
total: state.cart.total,
|
|
180
|
+
coupon: state.cart.couponCode ?? null,
|
|
181
|
+
});
|
|
182
|
+
},
|
|
183
|
+
});
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
---
|
|
187
|
+
|
|
188
|
+
### Options: `attachReduxState` — Control State File Attachment
|
|
189
|
+
|
|
190
|
+
Controls whether the Redux state (post-`stateTransformer`) is attached as a
|
|
191
|
+
`redux_state.json` file on error events.
|
|
192
|
+
|
|
193
|
+
- **Type:** `boolean`
|
|
194
|
+
- **Default:** `true`
|
|
195
|
+
- **Min SDK:** `7.69.0`
|
|
196
|
+
|
|
197
|
+
```typescript
|
|
198
|
+
const sentryReduxEnhancer = Sentry.createReduxEnhancer({
|
|
199
|
+
attachReduxState: false, // Don't attach state file — reduces payload size
|
|
200
|
+
});
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
---
|
|
204
|
+
|
|
205
|
+
### Options: `normalizeDepth` — Control State Serialization Depth
|
|
206
|
+
|
|
207
|
+
Set in `Sentry.init()`, not in `createReduxEnhancer()`. Increases the depth at which
|
|
208
|
+
Redux state trees are serialized.
|
|
209
|
+
The default of `3` is too shallow for most Redux state shapes.
|
|
210
|
+
|
|
211
|
+
```typescript
|
|
212
|
+
Sentry.init({
|
|
213
|
+
dsn: "___PUBLIC_DSN___",
|
|
214
|
+
normalizeDepth: 10, // Default is 3 — increase for deeply nested Redux state
|
|
215
|
+
});
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
---
|
|
219
|
+
|
|
220
|
+
### All Options Summary
|
|
221
|
+
|
|
222
|
+
| Option | Type | Default | Location | Description |
|
|
223
|
+
| ------------------------- | -------------------------------------- | ------- | ----------------------- | ------------------------------------------------- |
|
|
224
|
+
| `actionTransformer` | `(action: Action) => Action \| null` | — | `createReduxEnhancer()` | Modify or drop action breadcrumbs |
|
|
225
|
+
| `stateTransformer` | `(state: State) => State \| null` | — | `createReduxEnhancer()` | Modify or drop state attached to events |
|
|
226
|
+
| `configureScopeWithState` | `(scope: Scope, state: State) => void` | — | `createReduxEnhancer()` | Sync Sentry scope tags/context with Redux state |
|
|
227
|
+
| `attachReduxState` | `boolean` | `true` | `createReduxEnhancer()` | Attach state as `redux_state.json` file on errors |
|
|
228
|
+
| `normalizeDepth` | `number` | `3` | `Sentry.init()` | Max depth when serializing nested state |
|
|
229
|
+
|
|
230
|
+
---
|
|
231
|
+
|
|
232
|
+
### Complete Working Example with `@reduxjs/toolkit`
|
|
233
|
+
|
|
234
|
+
```typescript
|
|
235
|
+
// store/sentry.ts
|
|
236
|
+
import * as Sentry from "@sentry/react";
|
|
237
|
+
import type { RootState } from "./types";
|
|
238
|
+
|
|
239
|
+
export const sentryReduxEnhancer = Sentry.createReduxEnhancer({
|
|
240
|
+
actionTransformer: (action) => {
|
|
241
|
+
// Drop noisy/sensitive action types
|
|
242
|
+
const DROP_TYPES = new Set([
|
|
243
|
+
"SET_AUTH_TOKEN",
|
|
244
|
+
"REFRESH_TOKEN",
|
|
245
|
+
"WEBSOCKET_HEARTBEAT",
|
|
246
|
+
"UPDATE_CURSOR_POSITION",
|
|
247
|
+
]);
|
|
248
|
+
if (DROP_TYPES.has(action.type)) return null;
|
|
249
|
+
|
|
250
|
+
// Scrub passwords from login actions
|
|
251
|
+
if (action.type === "auth/login/pending") {
|
|
252
|
+
return {
|
|
253
|
+
...action,
|
|
254
|
+
meta: { ...action.meta, arg: { email: action.meta?.arg?.email, password: "[REDACTED]" } },
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
return action;
|
|
259
|
+
},
|
|
260
|
+
|
|
261
|
+
stateTransformer: (state: RootState) => ({
|
|
262
|
+
...state,
|
|
263
|
+
auth: { isAuthenticated: state.auth.isAuthenticated, userId: state.auth.userId },
|
|
264
|
+
// Strip large or sensitive subtrees
|
|
265
|
+
rawData: null,
|
|
266
|
+
}),
|
|
267
|
+
|
|
268
|
+
configureScopeWithState: (scope, state: RootState) => {
|
|
269
|
+
scope.setTag("user.plan", state.user.plan ?? "unknown");
|
|
270
|
+
scope.setTag("user.id", state.auth.userId ?? "anonymous");
|
|
271
|
+
scope.setTag("org.id", state.org.id ?? "none");
|
|
272
|
+
},
|
|
273
|
+
});
|
|
274
|
+
|
|
275
|
+
// store/index.ts
|
|
276
|
+
import { configureStore } from "@reduxjs/toolkit";
|
|
277
|
+
import { sentryReduxEnhancer } from "./sentry";
|
|
278
|
+
import rootReducer from "./reducers";
|
|
279
|
+
|
|
280
|
+
export const store = configureStore({
|
|
281
|
+
reducer: rootReducer,
|
|
282
|
+
enhancers: (getDefaultEnhancers) => getDefaultEnhancers().concat(sentryReduxEnhancer),
|
|
283
|
+
});
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
```typescript
|
|
287
|
+
// instrument.ts — init with normalizeDepth
|
|
288
|
+
import * as Sentry from "@sentry/react";
|
|
289
|
+
|
|
290
|
+
Sentry.init({
|
|
291
|
+
dsn: import.meta.env.VITE_SENTRY_DSN,
|
|
292
|
+
normalizeDepth: 10, // Required for deeply nested Redux state
|
|
293
|
+
integrations: [Sentry.browserTracingIntegration()],
|
|
294
|
+
tracesSampleRate: 1.0,
|
|
295
|
+
});
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
### Performance Considerations
|
|
299
|
+
|
|
300
|
+
Redux state can be very large.
|
|
301
|
+
Keep in mind:
|
|
302
|
+
|
|
303
|
+
1. **State size:** Large state trees (thousands of items) will slow serialization and
|
|
304
|
+
increase payload size.
|
|
305
|
+
Use `stateTransformer` to return only the relevant slices.
|
|
306
|
+
2. **`normalizeDepth`:** Keep it as low as practical.
|
|
307
|
+
`10` is usually sufficient for deeply nested state; avoid setting it to `Infinity`.
|
|
308
|
+
3. **`attachReduxState: false`:** For high-traffic production apps where payload size is
|
|
309
|
+
a concern, disabling state attachment reduces each error event’s size.
|
|
310
|
+
4. **`configureScopeWithState` cost:** This runs on every Redux dispatch.
|
|
311
|
+
Keep the function fast — avoid heavy computations or deep object traversals.
|
|
312
|
+
|
|
313
|
+
---
|
|
314
|
+
|
|
315
|
+
## 2. Component Tracking & Performance
|
|
316
|
+
|
|
317
|
+
### A. React Component Name Annotation (Build-Time)
|
|
318
|
+
|
|
319
|
+
Replaces opaque CSS selectors in breadcrumbs, Session Replay, and performance spans with
|
|
320
|
+
readable React component names.
|
|
321
|
+
|
|
322
|
+
**Before:** `button.en302zp1.app-191aavw.e16hd6vm2[role="button"]`\
|
|
323
|
+
**After:** `CheckoutButton`
|
|
324
|
+
|
|
325
|
+
**Requirements:**
|
|
326
|
+
|
|
327
|
+
- SDK v7.91.0+
|
|
328
|
+
- Components must be in `.jsx` or `.tsx` files (`.js` and `.ts` are **not** annotated)
|
|
329
|
+
- esbuild is **not** supported
|
|
330
|
+
|
|
331
|
+
The bundler plugins inject `data-sentry-component` and `data-sentry-source-file`
|
|
332
|
+
attributes at build time:
|
|
333
|
+
|
|
334
|
+
```html
|
|
335
|
+
<!-- Resulting DOM -->
|
|
336
|
+
<button data-sentry-component="CheckoutButton" data-sentry-source-file="CheckoutButton.tsx">
|
|
337
|
+
Checkout
|
|
338
|
+
</button>
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
**Enable via Vite (recommended):**
|
|
342
|
+
|
|
343
|
+
```typescript
|
|
344
|
+
// vite.config.ts
|
|
345
|
+
import { defineConfig } from "vite";
|
|
346
|
+
import react from "@vitejs/plugin-react";
|
|
347
|
+
import { sentryVitePlugin } from "@sentry/vite-plugin";
|
|
348
|
+
|
|
349
|
+
export default defineConfig({
|
|
350
|
+
plugins: [
|
|
351
|
+
react(),
|
|
352
|
+
sentryVitePlugin({
|
|
353
|
+
org: process.env.SENTRY_ORG,
|
|
354
|
+
project: process.env.SENTRY_PROJECT,
|
|
355
|
+
authToken: process.env.SENTRY_AUTH_TOKEN,
|
|
356
|
+
reactComponentAnnotation: {
|
|
357
|
+
enabled: true,
|
|
358
|
+
// Exclude components that cause "Passing unknown props on Fragment" errors
|
|
359
|
+
ignoredComponents: ["AnimationWrapper", "LayoutFragment"],
|
|
360
|
+
},
|
|
361
|
+
}),
|
|
362
|
+
],
|
|
363
|
+
build: {
|
|
364
|
+
sourcemap: "hidden",
|
|
365
|
+
},
|
|
366
|
+
});
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
**Enable via Babel plugin directly (without bundler plugin):**
|
|
370
|
+
|
|
371
|
+
```bash
|
|
372
|
+
npm install @sentry/babel-plugin-component-annotate --save-dev
|
|
373
|
+
```
|
|
374
|
+
|
|
375
|
+
```javascript
|
|
376
|
+
// babel.config.js
|
|
377
|
+
module.exports = {
|
|
378
|
+
plugins: ["@sentry/babel-plugin-component-annotate"],
|
|
379
|
+
};
|
|
380
|
+
```
|
|
381
|
+
|
|
382
|
+
**Bundler support:**
|
|
383
|
+
|
|
384
|
+
| Bundler | Component Annotation |
|
|
385
|
+
| ------- | -------------------- |
|
|
386
|
+
| Vite | ✅ Supported |
|
|
387
|
+
| Webpack | ✅ Supported |
|
|
388
|
+
| Rollup | ✅ Supported |
|
|
389
|
+
| esbuild | ❌ Not supported |
|
|
390
|
+
|
|
391
|
+
**What you gain:**
|
|
392
|
+
|
|
393
|
+
| Where | Before | After |
|
|
394
|
+
| ----------------- | ------------------- | ----------------------- |
|
|
395
|
+
| Breadcrumbs | `div.sc-abc123` | `ProductCard` |
|
|
396
|
+
| Session Replay | Unreadable selector | Search by `ProductCard` |
|
|
397
|
+
| Performance spans | Generic element | `CheckoutButton` render |
|
|
398
|
+
|
|
399
|
+
---
|
|
400
|
+
|
|
401
|
+
### B. `Sentry.withProfiler()` — React Profiler HOC
|
|
402
|
+
|
|
403
|
+
`withProfiler` wraps a component with the
|
|
404
|
+
[React Profiler API](https://react.dev/reference/react/Profiler) to capture render
|
|
405
|
+
timing as Sentry performance spans.
|
|
406
|
+
|
|
407
|
+
```typescript
|
|
408
|
+
import * as Sentry from "@sentry/react";
|
|
409
|
+
|
|
410
|
+
// Basic — display name inferred from component.displayName or .name
|
|
411
|
+
const ProfiledDashboard = Sentry.withProfiler(Dashboard);
|
|
412
|
+
|
|
413
|
+
// With explicit name (required for anonymous or arrow-function components)
|
|
414
|
+
const ProfiledWidget = Sentry.withProfiler(
|
|
415
|
+
({ data }) => <div>{data.title}</div>,
|
|
416
|
+
{ name: "DataWidget" }
|
|
417
|
+
);
|
|
418
|
+
|
|
419
|
+
// Class component decorator syntax
|
|
420
|
+
@Sentry.withProfiler
|
|
421
|
+
class ExpensiveList extends React.Component {
|
|
422
|
+
render() {
|
|
423
|
+
return <ul>{this.props.items.map(renderItem)}</ul>;
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
```
|
|
427
|
+
|
|
428
|
+
**Options:**
|
|
429
|
+
|
|
430
|
+
| Option | Type | Default | Description |
|
|
431
|
+
| ---------------- | --------- | --------------------------------- | ----------------------------------- |
|
|
432
|
+
| `name` | `string` | Component `displayName` or `name` | Display name shown in Sentry traces |
|
|
433
|
+
| `includeRender` | `boolean` | `true` | Track initial render phase |
|
|
434
|
+
| `includeUpdates` | `boolean` | `true` | Track re-render / update phases |
|
|
435
|
+
|
|
436
|
+
**What it captures:**
|
|
437
|
+
|
|
438
|
+
- Mount time (initial render duration)
|
|
439
|
+
- Update/re-render time per update
|
|
440
|
+
- Number of re-renders
|
|
441
|
+
- Component name in the Sentry performance trace waterfall
|
|
442
|
+
|
|
443
|
+
**Data appears in:** Sentry → Performance → Trace View, as child spans of the current
|
|
444
|
+
transaction.
|
|
445
|
+
|
|
446
|
+
> **Requires tracing:** `browserTracingIntegration` must be in your `Sentry.init`
|
|
447
|
+
> integrations.
|
|
448
|
+
|
|
449
|
+
**When to use (and when not to):**
|
|
450
|
+
|
|
451
|
+
✅ Use on:
|
|
452
|
+
|
|
453
|
+
- Root-level route components (Dashboard, CheckoutFlow, UserProfile)
|
|
454
|
+
- Components with expensive render logic (large lists, complex calculations)
|
|
455
|
+
- Components that re-render frequently and may cause jank
|
|
456
|
+
|
|
457
|
+
❌ Do **not** use on:
|
|
458
|
+
|
|
459
|
+
- Every component in the tree — the overhead compounds
|
|
460
|
+
- Simple presentational/leaf components
|
|
461
|
+
- Components that render hundreds of times per second (e.g., animation frames)
|
|
462
|
+
|
|
463
|
+
**Performance overhead:** Each profiled component adds a small constant overhead per
|
|
464
|
+
render cycle.
|
|
465
|
+
Profile the 5–10 most performance-critical components, not the entire tree.
|
|
466
|
+
|
|
467
|
+
---
|
|
468
|
+
|
|
469
|
+
## 3. Source Maps
|
|
470
|
+
|
|
471
|
+
Source maps translate minified production stack traces back to your original source
|
|
472
|
+
code. Without them, stack traces show obfuscated variable names and collapsed line
|
|
473
|
+
numbers.
|
|
474
|
+
|
|
475
|
+
### Recommended: Sentry Wizard
|
|
476
|
+
|
|
477
|
+
The fastest path — automatically detects your bundler, installs the plugin, and
|
|
478
|
+
configures auth:
|
|
479
|
+
|
|
480
|
+
> **You need to run this yourself** — the wizard opens a browser for login and requires
|
|
481
|
+
> interactive input that the agent can’t handle.
|
|
482
|
+
> Copy-paste into your terminal:
|
|
483
|
+
>
|
|
484
|
+
> ```
|
|
485
|
+
> npx @sentry/wizard@latest -i sourcemaps
|
|
486
|
+
> ```
|
|
487
|
+
>
|
|
488
|
+
> It detects Vite/webpack/CRA, installs the appropriate Sentry bundler plugin, adds
|
|
489
|
+
> `SENTRY_AUTH_TOKEN` to `.env.sentry-build-plugin`, and configures
|
|
490
|
+
> `sourcemap: "hidden"` with `filesToDeleteAfterUpload`.
|
|
491
|
+
>
|
|
492
|
+
> **Once it finishes, come back and the agent will continue.**
|
|
493
|
+
|
|
494
|
+
If the user skips the wizard, proceed with manual bundler plugin setup below.
|
|
495
|
+
|
|
496
|
+
---
|
|
497
|
+
|
|
498
|
+
### How Debug IDs Work
|
|
499
|
+
|
|
500
|
+
Modern Sentry source map matching uses **Debug IDs** — unique identifiers injected by
|
|
501
|
+
the bundler plugin into both the compiled `.js` bundle and the corresponding `.js.map`
|
|
502
|
+
file. This makes source map matching reliable without needing to manage file names or
|
|
503
|
+
release artifacts manually.
|
|
504
|
+
|
|
505
|
+
**Flow:**
|
|
506
|
+
|
|
507
|
+
1. Production build runs → bundler plugin injects a Debug ID into each `.js` and
|
|
508
|
+
`.js.map` file
|
|
509
|
+
2. Plugin uploads `.js.map` files to Sentry with their Debug IDs
|
|
510
|
+
3. Error occurs in production → stack frame contains the Debug ID
|
|
511
|
+
4. Sentry uses the Debug ID to locate the exact source map → deobfuscates the trace
|
|
512
|
+
|
|
513
|
+
Debug IDs are more reliable than release-based matching (older approach) because they
|
|
514
|
+
don’t depend on consistent release naming or artifact upload timing.
|
|
515
|
+
|
|
516
|
+
---
|
|
517
|
+
|
|
518
|
+
### Vite Plugin
|
|
519
|
+
|
|
520
|
+
**Minimum SDK:** `@sentry/vite-plugin` `2.0.0` / `@sentry/react` `7.47.0`
|
|
521
|
+
|
|
522
|
+
```bash
|
|
523
|
+
npm install @sentry/vite-plugin --save-dev
|
|
524
|
+
```
|
|
525
|
+
|
|
526
|
+
```typescript
|
|
527
|
+
// vite.config.ts
|
|
528
|
+
import { defineConfig } from "vite";
|
|
529
|
+
import react from "@vitejs/plugin-react";
|
|
530
|
+
import { sentryVitePlugin } from "@sentry/vite-plugin";
|
|
531
|
+
|
|
532
|
+
export default defineConfig({
|
|
533
|
+
build: {
|
|
534
|
+
// "hidden" generates source maps but strips the `//# sourceMappingURL=` comment
|
|
535
|
+
// from bundles, so browsers won't load them — they're only for Sentry.
|
|
536
|
+
sourcemap: "hidden",
|
|
537
|
+
},
|
|
538
|
+
plugins: [
|
|
539
|
+
react(),
|
|
540
|
+
// sentryVitePlugin MUST come after all other plugins
|
|
541
|
+
sentryVitePlugin({
|
|
542
|
+
org: process.env.SENTRY_ORG,
|
|
543
|
+
project: process.env.SENTRY_PROJECT,
|
|
544
|
+
authToken: process.env.SENTRY_AUTH_TOKEN,
|
|
545
|
+
|
|
546
|
+
// Enable React component name annotation at the same time
|
|
547
|
+
reactComponentAnnotation: {
|
|
548
|
+
enabled: true,
|
|
549
|
+
},
|
|
550
|
+
|
|
551
|
+
sourcemaps: {
|
|
552
|
+
// Delete .map files from dist/ after uploading to Sentry
|
|
553
|
+
// so they're not deployed to your CDN/server
|
|
554
|
+
filesToDeleteAfterUpload: [
|
|
555
|
+
"./**/*.map",
|
|
556
|
+
".*/**/public/**/*.map",
|
|
557
|
+
"./dist/**/client/**/*.map",
|
|
558
|
+
],
|
|
559
|
+
},
|
|
560
|
+
}),
|
|
561
|
+
],
|
|
562
|
+
});
|
|
563
|
+
```
|
|
564
|
+
|
|
565
|
+
> ⚠️ Place `sentryVitePlugin` **after** all other plugins (especially
|
|
566
|
+
> `@vitejs/plugin-react`) to ensure correct source map generation.
|
|
567
|
+
|
|
568
|
+
---
|
|
569
|
+
|
|
570
|
+
### Webpack Plugin
|
|
571
|
+
|
|
572
|
+
**Minimum SDK:** `@sentry/webpack-plugin` `2.0.0` / `@sentry/react` `7.47.0`
|
|
573
|
+
|
|
574
|
+
```bash
|
|
575
|
+
npm install @sentry/webpack-plugin --save-dev
|
|
576
|
+
```
|
|
577
|
+
|
|
578
|
+
```javascript
|
|
579
|
+
// webpack.config.js
|
|
580
|
+
const { sentryWebpackPlugin } = require("@sentry/webpack-plugin");
|
|
581
|
+
|
|
582
|
+
module.exports = {
|
|
583
|
+
// "hidden-source-map" generates source maps without the `//# sourceMappingURL=`
|
|
584
|
+
// reference comment, so they won't be served publicly.
|
|
585
|
+
devtool: "hidden-source-map",
|
|
586
|
+
|
|
587
|
+
plugins: [
|
|
588
|
+
sentryWebpackPlugin({
|
|
589
|
+
org: process.env.SENTRY_ORG,
|
|
590
|
+
project: process.env.SENTRY_PROJECT,
|
|
591
|
+
authToken: process.env.SENTRY_AUTH_TOKEN,
|
|
592
|
+
sourcemaps: {
|
|
593
|
+
filesToDeleteAfterUpload: ["./**/*.map", "./build/static/**/*.map"],
|
|
594
|
+
},
|
|
595
|
+
}),
|
|
596
|
+
],
|
|
597
|
+
};
|
|
598
|
+
```
|
|
599
|
+
|
|
600
|
+
---
|
|
601
|
+
|
|
602
|
+
### Create React App
|
|
603
|
+
|
|
604
|
+
CRA has limited configuration access.
|
|
605
|
+
Two approaches:
|
|
606
|
+
|
|
607
|
+
**Option A: CRACO (recommended — no ejection)**
|
|
608
|
+
|
|
609
|
+
```bash
|
|
610
|
+
npm install @craco/craco @sentry/webpack-plugin --save-dev
|
|
611
|
+
```
|
|
612
|
+
|
|
613
|
+
```javascript
|
|
614
|
+
// craco.config.js
|
|
615
|
+
const { sentryWebpackPlugin } = require("@sentry/webpack-plugin");
|
|
616
|
+
|
|
617
|
+
module.exports = {
|
|
618
|
+
webpack: {
|
|
619
|
+
configure: (webpackConfig) => {
|
|
620
|
+
webpackConfig.devtool = "hidden-source-map";
|
|
621
|
+
webpackConfig.plugins.push(
|
|
622
|
+
sentryWebpackPlugin({
|
|
623
|
+
org: process.env.SENTRY_ORG,
|
|
624
|
+
project: process.env.SENTRY_PROJECT,
|
|
625
|
+
authToken: process.env.SENTRY_AUTH_TOKEN,
|
|
626
|
+
sourcemaps: {
|
|
627
|
+
filesToDeleteAfterUpload: ["./build/static/**/*.map"],
|
|
628
|
+
},
|
|
629
|
+
}),
|
|
630
|
+
);
|
|
631
|
+
return webpackConfig;
|
|
632
|
+
},
|
|
633
|
+
},
|
|
634
|
+
};
|
|
635
|
+
```
|
|
636
|
+
|
|
637
|
+
Update `package.json` scripts:
|
|
638
|
+
|
|
639
|
+
```json
|
|
640
|
+
{
|
|
641
|
+
"scripts": {
|
|
642
|
+
"start": "craco start",
|
|
643
|
+
"build": "craco build"
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
```
|
|
647
|
+
|
|
648
|
+
**Option B: Eject (`npm run eject`)**
|
|
649
|
+
|
|
650
|
+
After ejecting, edit `config/webpack.config.js` directly — same as the regular webpack
|
|
651
|
+
setup above. Ejection is irreversible; prefer CRACO.
|
|
652
|
+
|
|
653
|
+
---
|
|
654
|
+
|
|
655
|
+
### Manual Upload with `sentry-cli`
|
|
656
|
+
|
|
657
|
+
Use when you can’t use a bundler plugin (e.g., legacy toolchain, pre-built artifacts):
|
|
658
|
+
|
|
659
|
+
```bash
|
|
660
|
+
npm install @sentry/cli --save-dev
|
|
661
|
+
```
|
|
662
|
+
|
|
663
|
+
```bash
|
|
664
|
+
# Upload source maps after a production build
|
|
665
|
+
npx sentry-cli sourcemaps upload \
|
|
666
|
+
--org $SENTRY_ORG \
|
|
667
|
+
--project $SENTRY_PROJECT \
|
|
668
|
+
--auth-token $SENTRY_AUTH_TOKEN \
|
|
669
|
+
./build
|
|
670
|
+
```
|
|
671
|
+
|
|
672
|
+
**`.sentryclirc` configuration file (alternative to env vars):**
|
|
673
|
+
|
|
674
|
+
```ini
|
|
675
|
+
[defaults]
|
|
676
|
+
org = my-org-slug
|
|
677
|
+
project = my-project-slug
|
|
678
|
+
url = https://sentry.io/
|
|
679
|
+
```
|
|
680
|
+
|
|
681
|
+
```bash
|
|
682
|
+
# With .sentryclirc, no --org/--project flags needed:
|
|
683
|
+
npx sentry-cli sourcemaps upload --auth-token $SENTRY_AUTH_TOKEN ./build
|
|
684
|
+
```
|
|
685
|
+
|
|
686
|
+
> ⚠️ Never commit `SENTRY_AUTH_TOKEN` to source control.
|
|
687
|
+
> Always read it from environment variables.
|
|
688
|
+
|
|
689
|
+
**CI/CD pattern (GitHub Actions):**
|
|
690
|
+
|
|
691
|
+
```yaml
|
|
692
|
+
- name: Build
|
|
693
|
+
run: npm run build
|
|
694
|
+
|
|
695
|
+
- name: Upload source maps to Sentry
|
|
696
|
+
env:
|
|
697
|
+
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
|
|
698
|
+
SENTRY_ORG: my-org-slug
|
|
699
|
+
SENTRY_PROJECT: my-react-app
|
|
700
|
+
run: |
|
|
701
|
+
npx sentry-cli sourcemaps upload \
|
|
702
|
+
--org $SENTRY_ORG \
|
|
703
|
+
--project $SENTRY_PROJECT \
|
|
704
|
+
--auth-token $SENTRY_AUTH_TOKEN \
|
|
705
|
+
./build
|
|
706
|
+
|
|
707
|
+
- name: Delete source maps from build artifacts
|
|
708
|
+
run: find ./build -name "*.map" -delete
|
|
709
|
+
|
|
710
|
+
- name: Deploy
|
|
711
|
+
run: # your deploy step
|
|
712
|
+
```
|
|
713
|
+
|
|
714
|
+
---
|
|
715
|
+
|
|
716
|
+
### Environment Variables for Source Maps
|
|
717
|
+
|
|
718
|
+
Store credentials in `.env.sentry-build-plugin` (auto-loaded by Sentry bundler plugins)
|
|
719
|
+
or pass as CI/CD secrets:
|
|
720
|
+
|
|
721
|
+
```bash
|
|
722
|
+
# .env.sentry-build-plugin ← auto-loaded by @sentry/vite-plugin and @sentry/webpack-plugin
|
|
723
|
+
# ADD THIS FILE TO .gitignore — never commit it
|
|
724
|
+
SENTRY_AUTH_TOKEN=sntrys_eyJ...
|
|
725
|
+
SENTRY_ORG=my-org-slug
|
|
726
|
+
SENTRY_PROJECT=my-project-slug
|
|
727
|
+
```
|
|
728
|
+
|
|
729
|
+
**Required token permissions:**
|
|
730
|
+
|
|
731
|
+
The `SENTRY_AUTH_TOKEN` must have:
|
|
732
|
+
|
|
733
|
+
- **Project:** Read & Write
|
|
734
|
+
- **Release:** Admin
|
|
735
|
+
|
|
736
|
+
---
|
|
737
|
+
|
|
738
|
+
### Source Map Security
|
|
739
|
+
|
|
740
|
+
| Strategy | How |
|
|
741
|
+
| ------------------------------ | ---------------------------------------------------------------------------- |
|
|
742
|
+
| Don’t expose maps to browsers | Use `sourcemap: "hidden"` (Vite) or `devtool: "hidden-source-map"` (webpack) |
|
|
743
|
+
| Delete maps after upload | Use `filesToDeleteAfterUpload` in the plugin config |
|
|
744
|
+
| Block map access at CDN/server | Configure your server to return 403 for `.js.map` requests |
|
|
745
|
+
|
|
746
|
+
All three should be used together for maximum security.
|
|
747
|
+
|
|
748
|
+
---
|
|
749
|
+
|
|
750
|
+
### Troubleshooting Source Maps
|
|
751
|
+
|
|
752
|
+
| Problem | Likely Cause | Fix |
|
|
753
|
+
| ------------------------------------------ | -------------------------------------------------------- | -------------------------------------------------------------------------- |
|
|
754
|
+
| Stack traces still minified | Source maps not uploaded, or Debug IDs missing | Rebuild with production config, re-run wizard or plugin |
|
|
755
|
+
| Maps not applied to old errors | Maps uploaded after errors occurred | Always upload maps **before** deploying — ideally in the same CI step |
|
|
756
|
+
| “SourceMapDevToolPlugin” stripping sources | `noSources: true` in your webpack SourceMapDevToolPlugin | Remove `noSources: true` option |
|
|
757
|
+
| Plugin only uploads once | Running in `--watch` or dev mode | Plugin only uploads during production builds (`NODE_ENV=production`) |
|
|
758
|
+
| SENTRY_AUTH_TOKEN not found | Missing env variable | Check `.env.sentry-build-plugin` exists and is not gitignored incorrectly |
|
|
759
|
+
| Component names still not showing | `.js`/`.ts` files instead of `.jsx`/`.tsx` | Rename files or use the Babel plugin directly on all JSX transform targets |
|
|
760
|
+
|
|
761
|
+
---
|
|
762
|
+
|
|
763
|
+
## 4. Default Integrations
|
|
764
|
+
|
|
765
|
+
These integrations are **automatically enabled** for every `@sentry/react` installation.
|
|
766
|
+
No configuration required.
|
|
767
|
+
|
|
768
|
+
| Integration | Name Constant | What It Does |
|
|
769
|
+
| ------------------ | ----------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
770
|
+
| Breadcrumbs | `breadcrumbsIntegration` | Captures breadcrumbs from DOM events (clicks, inputs), XHR, fetch, console calls, history navigation |
|
|
771
|
+
| Browser API Errors | `browserApiErrorsIntegration` | Wraps `setTimeout`, `setInterval`, `requestAnimationFrame`, `addEventListener`, `removeEventListener` in try/catch so errors inside them are captured |
|
|
772
|
+
| Browser Session | `browserSessionIntegration` | Tracks session health (healthy vs. crashed) for Release Health metrics |
|
|
773
|
+
| Dedupe | `dedupeIntegration` | Prevents duplicate error events from being sent — deduplicates based on error type, message, and stack trace |
|
|
774
|
+
| Function to String | `functionToStringIntegration` | Preserves original function `.toString()` output after SDK instrumentation, so stack traces show readable names |
|
|
775
|
+
| Global Handlers | `globalHandlersIntegration` | Listens to `window.onerror` (uncaught exceptions) and `window.onunhandledrejection` (unhandled promise rejections) |
|
|
776
|
+
| HTTP Context | `httpContextIntegration` | Attaches current URL, referrer, and user-agent to every event |
|
|
777
|
+
| Inbound Filters | `inboundFiltersIntegration` | Filters known-noisy events by error type, message, or URL (e.g., browser extension errors, localhost-only errors) |
|
|
778
|
+
| Linked Errors | `linkedErrorsIntegration` | Follows JavaScript `error.cause` chains and attaches nested errors as linked issues — also used for React component stack linkage |
|
|
779
|
+
|
|
780
|
+
### Customizing a Default Integration’s Options
|
|
781
|
+
|
|
782
|
+
Pass the integration explicitly in `integrations` — it overrides the default instance:
|
|
783
|
+
|
|
784
|
+
```typescript
|
|
785
|
+
Sentry.init({
|
|
786
|
+
dsn: "___PUBLIC_DSN___",
|
|
787
|
+
integrations: [
|
|
788
|
+
// Override breadcrumbs to disable console capturing but keep DOM/fetch/XHR
|
|
789
|
+
Sentry.breadcrumbsIntegration({
|
|
790
|
+
console: false, // don't capture console.log as breadcrumbs
|
|
791
|
+
dom: true,
|
|
792
|
+
fetch: true,
|
|
793
|
+
history: true,
|
|
794
|
+
xhr: true,
|
|
795
|
+
}),
|
|
796
|
+
|
|
797
|
+
// Only capture unhandled exceptions; handle rejections manually
|
|
798
|
+
Sentry.globalHandlersIntegration({
|
|
799
|
+
onerror: true,
|
|
800
|
+
onunhandledrejection: false,
|
|
801
|
+
}),
|
|
802
|
+
],
|
|
803
|
+
});
|
|
804
|
+
```
|
|
805
|
+
|
|
806
|
+
### Removing a Default Integration
|
|
807
|
+
|
|
808
|
+
Use the function form of `integrations` to filter out what you don’t want:
|
|
809
|
+
|
|
810
|
+
```typescript
|
|
811
|
+
Sentry.init({
|
|
812
|
+
dsn: "___PUBLIC_DSN___",
|
|
813
|
+
integrations: (integrations) => {
|
|
814
|
+
// Remove deduplication (e.g., if you want every occurrence recorded separately)
|
|
815
|
+
return integrations.filter((integration) => integration.name !== "Dedupe");
|
|
816
|
+
},
|
|
817
|
+
});
|
|
818
|
+
```
|
|
819
|
+
|
|
820
|
+
Common integration names to filter:
|
|
821
|
+
|
|
822
|
+
- `"Dedupe"` — deduplication
|
|
823
|
+
- `"Breadcrumbs"` — all automatic breadcrumbs
|
|
824
|
+
- `"GlobalHandlers"` — window.onerror / unhandledrejection
|
|
825
|
+
- `"LinkedErrors"` — error cause chain following
|
|
826
|
+
- `"HttpContext"` — URL/referrer attachment
|
|
827
|
+
- `"InboundFilters"` — built-in noise filtering
|
|
828
|
+
|
|
829
|
+
### Disabling ALL Default Integrations
|
|
830
|
+
|
|
831
|
+
```typescript
|
|
832
|
+
Sentry.init({
|
|
833
|
+
dsn: "___PUBLIC_DSN___",
|
|
834
|
+
defaultIntegrations: false,
|
|
835
|
+
// Build your own set from scratch:
|
|
836
|
+
integrations: [
|
|
837
|
+
Sentry.globalHandlersIntegration(),
|
|
838
|
+
Sentry.browserTracingIntegration(),
|
|
839
|
+
Sentry.dedupeIntegration(),
|
|
840
|
+
],
|
|
841
|
+
});
|
|
842
|
+
```
|
|
843
|
+
|
|
844
|
+
---
|
|
845
|
+
|
|
846
|
+
## 5. Optional Integrations
|
|
847
|
+
|
|
848
|
+
These are available but **must be explicitly added** to your `integrations` array.
|
|
849
|
+
|
|
850
|
+
### Performance & Tracing
|
|
851
|
+
|
|
852
|
+
| Integration | Min SDK | Description |
|
|
853
|
+
| ------------------------------- | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
854
|
+
| `browserTracingIntegration()` | 8.0.0 | Page load tracing, navigation tracing, automatic span creation for fetch/XHR, Core Web Vitals (LCP, FID, CLS), distributed tracing headers |
|
|
855
|
+
| `browserProfilingIntegration()` | 10.27.0 (Beta) | JS Self-Profiling API — captures call stacks at 100Hz in Chromium browsers. **Requires** `Document-Policy: js-profiling` HTTP header |
|
|
856
|
+
|
|
857
|
+
### Session Replay
|
|
858
|
+
|
|
859
|
+
| Integration | Min SDK | Description |
|
|
860
|
+
| --------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
861
|
+
| `replayIntegration()` | 7.27.0 | Session Replay — records DOM mutations, network requests, console output. Configured with `replaysSessionSampleRate` and `replaysOnErrorSampleRate` |
|
|
862
|
+
| `replayCanvasIntegration()` | 7.98.0 | Extends `replayIntegration` to record `<canvas>` elements in replays |
|
|
863
|
+
|
|
864
|
+
### Logging
|
|
865
|
+
|
|
866
|
+
| Integration | Min SDK | Description |
|
|
867
|
+
| ----------------------------- | ------- | ----------------------------------------------------------------------------------------------------------------------- |
|
|
868
|
+
| `consoleLoggingIntegration()` | 9.41.0 | Automatically forwards `console.log/warn/error/info/debug` calls as structured Sentry logs. Requires `enableLogs: true` |
|
|
869
|
+
|
|
870
|
+
```typescript
|
|
871
|
+
Sentry.init({
|
|
872
|
+
enableLogs: true,
|
|
873
|
+
integrations: [
|
|
874
|
+
Sentry.consoleLoggingIntegration({
|
|
875
|
+
levels: ["warn", "error"], // Only capture warnings and errors
|
|
876
|
+
}),
|
|
877
|
+
],
|
|
878
|
+
});
|
|
879
|
+
```
|
|
880
|
+
|
|
881
|
+
### User Feedback
|
|
882
|
+
|
|
883
|
+
| Integration | Min SDK | Description |
|
|
884
|
+
| --------------------------------- | ------- | ---------------------------------------------------------------------------------------------------------- |
|
|
885
|
+
| `feedbackIntegration()` | 7.85.0 | Floating feedback button + form (bottom-right). Supports screenshots, custom theming, programmatic control |
|
|
886
|
+
| `feedbackModalIntegration()` | 7.85.0 | Modal dialog variant of the feedback form |
|
|
887
|
+
| `feedbackScreenshotIntegration()` | 8.0.0 | Adds screenshot capture capability to the feedback widget |
|
|
888
|
+
|
|
889
|
+
### Error Enhancement
|
|
890
|
+
|
|
891
|
+
| Integration | Min SDK | Description |
|
|
892
|
+
| -------------------------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
893
|
+
| `extraErrorDataIntegration()` | 5.16.0 | Attaches non-standard properties on `Error` objects (e.g., `error.code`, `error.statusCode`, custom fields) as extra context |
|
|
894
|
+
| `contextLinesIntegration()` | 7.47.0 | Shows source code lines above and below the erroring line in the stack trace (requires source maps) |
|
|
895
|
+
| `httpClientIntegration()` | 7.50.0 | Captures failed HTTP requests (4xx/5xx responses) as Sentry error events, with request/response bodies. Opt-in because it may capture PII |
|
|
896
|
+
| `reportingObserverIntegration()` | 5.9.0 | Captures [Reporting Observer API](https://developer.mozilla.org/en-US/docs/Web/API/ReportingObserver) events (deprecation warnings, browser interventions, CSP violations) |
|
|
897
|
+
| `captureConsoleIntegration()` | 3.3.0 | Captures `console.error`/`console.warn` calls as Sentry issues (not logs). Legacy alternative to `consoleLoggingIntegration` |
|
|
898
|
+
|
|
899
|
+
### Stack Frame Rewriting
|
|
900
|
+
|
|
901
|
+
| Integration | Min SDK | Description |
|
|
902
|
+
| ---------------------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
903
|
+
| `rewriteFramesIntegration()` | 5.7.0 | Rewrites stack frame file paths — useful for normalizing paths in monorepos, Docker containers, or when paths differ between build and deploy environments |
|
|
904
|
+
|
|
905
|
+
---
|
|
906
|
+
|
|
907
|
+
### `httpClientIntegration` — Full Setup
|
|
908
|
+
|
|
909
|
+
Captures HTTP requests that fail (4xx/5xx) as error events, with the request URL,
|
|
910
|
+
method, status code, and optionally request/response bodies.
|
|
911
|
+
|
|
912
|
+
```typescript
|
|
913
|
+
Sentry.init({
|
|
914
|
+
dsn: "___PUBLIC_DSN___",
|
|
915
|
+
integrations: [
|
|
916
|
+
Sentry.httpClientIntegration({
|
|
917
|
+
// Capture errors for these HTTP status code ranges
|
|
918
|
+
failedRequestStatusCodes: [
|
|
919
|
+
[400, 499],
|
|
920
|
+
[500, 599],
|
|
921
|
+
],
|
|
922
|
+
|
|
923
|
+
// Only capture errors for these URL patterns
|
|
924
|
+
failedRequestTargets: ["https://api.myapp.com", /^https:\/\/internal\.service\//],
|
|
925
|
+
}),
|
|
926
|
+
],
|
|
927
|
+
dataCollection: {
|
|
928
|
+
// To disable sending user data and HTTP bodies, uncomment the lines below. For more info visit:
|
|
929
|
+
// https://docs.sentry.io/platforms/javascript/guides/react/configuration/options/#dataCollection
|
|
930
|
+
// userInfo: false,
|
|
931
|
+
// httpBodies: [],
|
|
932
|
+
},
|
|
933
|
+
});
|
|
934
|
+
```
|
|
935
|
+
|
|
936
|
+
### Adding Integrations After Init
|
|
937
|
+
|
|
938
|
+
If you need to add an integration after `Sentry.init()` has been called (e.g., after
|
|
939
|
+
user consent):
|
|
940
|
+
|
|
941
|
+
```typescript
|
|
942
|
+
// After the user accepts analytics cookies:
|
|
943
|
+
Sentry.addIntegration(
|
|
944
|
+
Sentry.replayIntegration({
|
|
945
|
+
maskAllText: true,
|
|
946
|
+
blockAllMedia: true,
|
|
947
|
+
}),
|
|
948
|
+
);
|
|
949
|
+
```
|
|
950
|
+
|
|
951
|
+
### Lazy Loading Integrations (Code Splitting)
|
|
952
|
+
|
|
953
|
+
```typescript
|
|
954
|
+
// Dynamic import (works with any bundler)
|
|
955
|
+
import("@sentry/browser").then((lazySentry) => {
|
|
956
|
+
Sentry.addIntegration(lazySentry.replayIntegration());
|
|
957
|
+
});
|
|
958
|
+
|
|
959
|
+
// CDN lazyLoadIntegration() — for Sentry loader script environments
|
|
960
|
+
async function enableFeedback() {
|
|
961
|
+
try {
|
|
962
|
+
const feedbackIntegration = await Sentry.lazyLoadIntegration("feedbackIntegration");
|
|
963
|
+
Sentry.addIntegration(feedbackIntegration({ colorScheme: "system" }));
|
|
964
|
+
} catch (e) {
|
|
965
|
+
// Ad-blockers or network failures — fail gracefully
|
|
966
|
+
console.warn("Could not load Sentry feedback integration", e);
|
|
967
|
+
}
|
|
968
|
+
}
|
|
969
|
+
```
|
|
970
|
+
|
|
971
|
+
Lazy-loadable integrations: `replayIntegration`, `replayCanvasIntegration`,
|
|
972
|
+
`feedbackIntegration`, `feedbackModalIntegration`, `feedbackScreenshotIntegration`,
|
|
973
|
+
`captureConsoleIntegration`, `contextLinesIntegration`, `linkedErrorsIntegration`,
|
|
974
|
+
`dedupeIntegration`, `extraErrorDataIntegration`, `httpClientIntegration`,
|
|
975
|
+
`reportingObserverIntegration`, `rewriteFramesIntegration`,
|
|
976
|
+
`browserProfilingIntegration`
|
|
977
|
+
|
|
978
|
+
---
|
|
979
|
+
|
|
980
|
+
## 6. Build Tool Detection & Environment Variables
|
|
981
|
+
|
|
982
|
+
### Detecting the Build Tool
|
|
983
|
+
|
|
984
|
+
```bash
|
|
985
|
+
# Run from project root
|
|
986
|
+
ls vite.config.ts vite.config.js webpack.config.js webpack.config.ts \
|
|
987
|
+
craco.config.js next.config.js next.config.ts 2>/dev/null
|
|
988
|
+
|
|
989
|
+
cat package.json | grep -E '"vite"|"react-scripts"|"webpack"|"@craco"'
|
|
990
|
+
```
|
|
991
|
+
|
|
992
|
+
| File/Package Found | Build Tool |
|
|
993
|
+
| ----------------------------------------- | -------------------------------------- |
|
|
994
|
+
| `vite.config.*` or `"vite"` in deps | Vite |
|
|
995
|
+
| `"react-scripts"` in deps | Create React App |
|
|
996
|
+
| `craco.config.js` or `"@craco/craco"` | CRA + CRACO |
|
|
997
|
+
| `webpack.config.*` or `"webpack"` in deps | Custom Webpack |
|
|
998
|
+
| `next.config.*` or `"next"` in deps | Next.js (use `@sentry/nextjs` instead) |
|
|
999
|
+
|
|
1000
|
+
---
|
|
1001
|
+
|
|
1002
|
+
### DSN Environment Variable Patterns
|
|
1003
|
+
|
|
1004
|
+
| Build Tool | Variable Name | How to Access in Code |
|
|
1005
|
+
| ---------------- | ---------------------- | ---------------------------------------------------------- |
|
|
1006
|
+
| Vite | `VITE_SENTRY_DSN` | `import.meta.env.VITE_SENTRY_DSN` |
|
|
1007
|
+
| Create React App | `REACT_APP_SENTRY_DSN` | `process.env.REACT_APP_SENTRY_DSN` |
|
|
1008
|
+
| Custom Webpack | `SENTRY_DSN` | `process.env.SENTRY_DSN` (requires `DefinePlugin`) |
|
|
1009
|
+
| Any | `SENTRY_DSN` | Build-time injection (not available at runtime in browser) |
|
|
1010
|
+
|
|
1011
|
+
**Vite — `.env` file:**
|
|
1012
|
+
|
|
1013
|
+
```bash
|
|
1014
|
+
# .env.production
|
|
1015
|
+
VITE_SENTRY_DSN=https://<key>@<org>.ingest.sentry.io/<id>
|
|
1016
|
+
VITE_SENTRY_ENVIRONMENT=production
|
|
1017
|
+
```
|
|
1018
|
+
|
|
1019
|
+
```typescript
|
|
1020
|
+
// instrument.ts
|
|
1021
|
+
Sentry.init({
|
|
1022
|
+
dsn: import.meta.env.VITE_SENTRY_DSN,
|
|
1023
|
+
environment: import.meta.env.VITE_SENTRY_ENVIRONMENT ?? "development",
|
|
1024
|
+
});
|
|
1025
|
+
```
|
|
1026
|
+
|
|
1027
|
+
**Create React App — `.env.production` file:**
|
|
1028
|
+
|
|
1029
|
+
```bash
|
|
1030
|
+
# .env.production (committed — DSN is public)
|
|
1031
|
+
REACT_APP_SENTRY_DSN=https://<key>@<org>.ingest.sentry.io/<id>
|
|
1032
|
+
REACT_APP_SENTRY_ENVIRONMENT=production
|
|
1033
|
+
```
|
|
1034
|
+
|
|
1035
|
+
```typescript
|
|
1036
|
+
// instrument.ts
|
|
1037
|
+
Sentry.init({
|
|
1038
|
+
dsn: process.env.REACT_APP_SENTRY_DSN,
|
|
1039
|
+
environment: process.env.REACT_APP_SENTRY_ENVIRONMENT ?? "development",
|
|
1040
|
+
});
|
|
1041
|
+
```
|
|
1042
|
+
|
|
1043
|
+
**Custom Webpack — `webpack.config.js` with `DefinePlugin`:**
|
|
1044
|
+
|
|
1045
|
+
```javascript
|
|
1046
|
+
const webpack = require("webpack");
|
|
1047
|
+
|
|
1048
|
+
module.exports = {
|
|
1049
|
+
plugins: [
|
|
1050
|
+
new webpack.DefinePlugin({
|
|
1051
|
+
"process.env.SENTRY_DSN": JSON.stringify(process.env.SENTRY_DSN),
|
|
1052
|
+
"process.env.SENTRY_ENVIRONMENT": JSON.stringify(process.env.NODE_ENV ?? "development"),
|
|
1053
|
+
}),
|
|
1054
|
+
],
|
|
1055
|
+
};
|
|
1056
|
+
```
|
|
1057
|
+
|
|
1058
|
+
```typescript
|
|
1059
|
+
// instrument.ts
|
|
1060
|
+
Sentry.init({
|
|
1061
|
+
dsn: process.env.SENTRY_DSN,
|
|
1062
|
+
environment: process.env.SENTRY_ENVIRONMENT,
|
|
1063
|
+
});
|
|
1064
|
+
```
|
|
1065
|
+
|
|
1066
|
+
---
|
|
1067
|
+
|
|
1068
|
+
### Conditional Initialization (Development vs Production)
|
|
1069
|
+
|
|
1070
|
+
Prevent Sentry from running in local development to avoid polluting your issue inbox
|
|
1071
|
+
with dev noise:
|
|
1072
|
+
|
|
1073
|
+
```typescript
|
|
1074
|
+
// instrument.ts
|
|
1075
|
+
import * as Sentry from "@sentry/react";
|
|
1076
|
+
|
|
1077
|
+
const IS_PRODUCTION =
|
|
1078
|
+
import.meta.env.PROD || // Vite
|
|
1079
|
+
process.env.NODE_ENV === "production"; // webpack / CRA
|
|
1080
|
+
|
|
1081
|
+
if (IS_PRODUCTION) {
|
|
1082
|
+
Sentry.init({
|
|
1083
|
+
dsn: import.meta.env.VITE_SENTRY_DSN, // or your env var pattern
|
|
1084
|
+
environment: "production",
|
|
1085
|
+
integrations: [
|
|
1086
|
+
Sentry.browserTracingIntegration(),
|
|
1087
|
+
Sentry.replayIntegration({
|
|
1088
|
+
maskAllText: false,
|
|
1089
|
+
blockAllMedia: false,
|
|
1090
|
+
}),
|
|
1091
|
+
],
|
|
1092
|
+
tracesSampleRate: 0.2, // 20% in production
|
|
1093
|
+
replaysSessionSampleRate: 0.1,
|
|
1094
|
+
replaysOnErrorSampleRate: 1.0,
|
|
1095
|
+
});
|
|
1096
|
+
} else {
|
|
1097
|
+
// In development: optionally init with verbose debug and full sampling
|
|
1098
|
+
Sentry.init({
|
|
1099
|
+
dsn: import.meta.env.VITE_SENTRY_DSN,
|
|
1100
|
+
environment: "development",
|
|
1101
|
+
debug: true, // Verbose SDK logging
|
|
1102
|
+
tracesSampleRate: 1.0, // 100% in dev so nothing is missed
|
|
1103
|
+
integrations: [Sentry.browserTracingIntegration()],
|
|
1104
|
+
// No Replay in dev — too noisy
|
|
1105
|
+
});
|
|
1106
|
+
}
|
|
1107
|
+
```
|
|
1108
|
+
|
|
1109
|
+
---
|
|
1110
|
+
|
|
1111
|
+
### Complete `instrument.ts` Reference — All Features
|
|
1112
|
+
|
|
1113
|
+
A kitchen-sink example combining every feature:
|
|
1114
|
+
|
|
1115
|
+
```typescript
|
|
1116
|
+
// src/instrument.ts
|
|
1117
|
+
import * as Sentry from "@sentry/react";
|
|
1118
|
+
|
|
1119
|
+
Sentry.init({
|
|
1120
|
+
dsn: import.meta.env.VITE_SENTRY_DSN,
|
|
1121
|
+
environment: import.meta.env.VITE_APP_ENV ?? "production",
|
|
1122
|
+
release: import.meta.env.VITE_APP_VERSION,
|
|
1123
|
+
|
|
1124
|
+
// ── Integrations ─────────────────────────────────────────────
|
|
1125
|
+
integrations: [
|
|
1126
|
+
// Tracing (navigation + API + Core Web Vitals)
|
|
1127
|
+
Sentry.browserTracingIntegration(),
|
|
1128
|
+
|
|
1129
|
+
// Session Replay
|
|
1130
|
+
Sentry.replayIntegration({
|
|
1131
|
+
maskAllText: false,
|
|
1132
|
+
blockAllMedia: false,
|
|
1133
|
+
}),
|
|
1134
|
+
|
|
1135
|
+
// Profiling (Beta — Chromium only, needs Document-Policy header)
|
|
1136
|
+
// Sentry.browserProfilingIntegration(),
|
|
1137
|
+
|
|
1138
|
+
// Structured logging (requires enableLogs: true)
|
|
1139
|
+
Sentry.consoleLoggingIntegration({
|
|
1140
|
+
levels: ["warn", "error"],
|
|
1141
|
+
}),
|
|
1142
|
+
|
|
1143
|
+
// Capture HTTP 4xx/5xx as Sentry errors
|
|
1144
|
+
Sentry.httpClientIntegration({
|
|
1145
|
+
failedRequestStatusCodes: [
|
|
1146
|
+
[400, 499],
|
|
1147
|
+
[500, 599],
|
|
1148
|
+
],
|
|
1149
|
+
}),
|
|
1150
|
+
|
|
1151
|
+
// Show source lines in stack traces (requires source maps)
|
|
1152
|
+
Sentry.contextLinesIntegration(),
|
|
1153
|
+
|
|
1154
|
+
// Capture non-standard Error properties
|
|
1155
|
+
Sentry.extraErrorDataIntegration(),
|
|
1156
|
+
|
|
1157
|
+
// User feedback widget
|
|
1158
|
+
Sentry.feedbackIntegration({
|
|
1159
|
+
colorScheme: "system",
|
|
1160
|
+
showBranding: false,
|
|
1161
|
+
triggerLabel: "Report a Bug",
|
|
1162
|
+
}),
|
|
1163
|
+
],
|
|
1164
|
+
|
|
1165
|
+
// ── Tracing ───────────────────────────────────────────────────
|
|
1166
|
+
tracesSampleRate: 0.2,
|
|
1167
|
+
tracePropagationTargets: ["localhost", /^https:\/\/api\.myapp\.com/],
|
|
1168
|
+
|
|
1169
|
+
// ── Session Replay ────────────────────────────────────────────
|
|
1170
|
+
replaysSessionSampleRate: 0.1,
|
|
1171
|
+
replaysOnErrorSampleRate: 1.0,
|
|
1172
|
+
|
|
1173
|
+
// ── Profiling ─────────────────────────────────────────────────
|
|
1174
|
+
profileSessionSampleRate: 1.0,
|
|
1175
|
+
|
|
1176
|
+
// ── Logging ───────────────────────────────────────────────────
|
|
1177
|
+
enableLogs: true,
|
|
1178
|
+
beforeSendLog: (log) => {
|
|
1179
|
+
if (log.level === "debug") return null; // Drop debug logs
|
|
1180
|
+
if (log.attributes?.password) delete log.attributes.password;
|
|
1181
|
+
return log;
|
|
1182
|
+
},
|
|
1183
|
+
|
|
1184
|
+
// ── Redux ─────────────────────────────────────────────────────
|
|
1185
|
+
normalizeDepth: 10,
|
|
1186
|
+
|
|
1187
|
+
// ── Filtering ─────────────────────────────────────────────────
|
|
1188
|
+
ignoreErrors: ["ResizeObserver loop limit exceeded", /^Loading chunk \d+ failed/],
|
|
1189
|
+
denyUrls: [/extensions\//i, /^chrome:\/\//i],
|
|
1190
|
+
|
|
1191
|
+
beforeSend(event) {
|
|
1192
|
+
// Strip credit card numbers from messages just in case
|
|
1193
|
+
if (event.message) {
|
|
1194
|
+
event.message = event.message.replace(/\b\d{16}\b/g, "[CARD]");
|
|
1195
|
+
}
|
|
1196
|
+
return event;
|
|
1197
|
+
},
|
|
1198
|
+
});
|
|
1199
|
+
```
|
|
1200
|
+
|
|
1201
|
+
```typescript
|
|
1202
|
+
// store/index.ts — wire in Redux enhancer
|
|
1203
|
+
import { configureStore } from "@reduxjs/toolkit";
|
|
1204
|
+
import * as Sentry from "@sentry/react";
|
|
1205
|
+
|
|
1206
|
+
export const store = configureStore({
|
|
1207
|
+
reducer: rootReducer,
|
|
1208
|
+
enhancers: (getDefaultEnhancers) =>
|
|
1209
|
+
getDefaultEnhancers().concat(
|
|
1210
|
+
Sentry.createReduxEnhancer({
|
|
1211
|
+
stateTransformer: (state) => ({ ...state, auth: null }),
|
|
1212
|
+
configureScopeWithState: (scope, state) => {
|
|
1213
|
+
scope.setTag("user.plan", state.user.plan);
|
|
1214
|
+
},
|
|
1215
|
+
}),
|
|
1216
|
+
),
|
|
1217
|
+
});
|
|
1218
|
+
```
|
|
1219
|
+
|
|
1220
|
+
---
|
|
1221
|
+
|
|
1222
|
+
## Quick Reference
|
|
1223
|
+
|
|
1224
|
+
```typescript
|
|
1225
|
+
// ── Redux ─────────────────────────────────────────────────────
|
|
1226
|
+
Sentry.createReduxEnhancer({
|
|
1227
|
+
actionTransformer: (action) => action | null,
|
|
1228
|
+
stateTransformer: (state) => state | null,
|
|
1229
|
+
configureScopeWithState: (scope, state) => void,
|
|
1230
|
+
attachReduxState: true,
|
|
1231
|
+
})
|
|
1232
|
+
// normalizeDepth goes in Sentry.init(), not createReduxEnhancer()
|
|
1233
|
+
|
|
1234
|
+
// ── Component Tracking ────────────────────────────────────────
|
|
1235
|
+
Sentry.withProfiler(Component, { name?, includeRender?, includeUpdates? })
|
|
1236
|
+
sentryVitePlugin({ reactComponentAnnotation: { enabled: true, ignoredComponents: [] } })
|
|
1237
|
+
// Babel plugin direct: @sentry/babel-plugin-component-annotate
|
|
1238
|
+
|
|
1239
|
+
// ── Source Maps ───────────────────────────────────────────────
|
|
1240
|
+
npx @sentry/wizard@latest -i sourcemaps // automated setup
|
|
1241
|
+
// Vite: build.sourcemap = "hidden" + sentryVitePlugin()
|
|
1242
|
+
// Webpack: devtool: "hidden-source-map" + sentryWebpackPlugin()
|
|
1243
|
+
// CRA: use CRACO + sentryWebpackPlugin
|
|
1244
|
+
// Manual: npx sentry-cli sourcemaps upload --auth-token $TOKEN ./dist
|
|
1245
|
+
|
|
1246
|
+
// ── Integrations (opt-in) ─────────────────────────────────────
|
|
1247
|
+
Sentry.browserTracingIntegration() // Tracing + Core Web Vitals
|
|
1248
|
+
Sentry.replayIntegration() // Session Replay
|
|
1249
|
+
Sentry.browserProfilingIntegration() // JS Profiler (Beta, Chromium only)
|
|
1250
|
+
Sentry.consoleLoggingIntegration() // console → Sentry logs
|
|
1251
|
+
Sentry.feedbackIntegration() // Feedback widget
|
|
1252
|
+
Sentry.httpClientIntegration() // 4xx/5xx as errors
|
|
1253
|
+
Sentry.contextLinesIntegration() // Source lines in stack traces
|
|
1254
|
+
Sentry.extraErrorDataIntegration() // Non-standard Error properties
|
|
1255
|
+
Sentry.reportingObserverIntegration() // Browser deprecation/CSP reports
|
|
1256
|
+
Sentry.rewriteFramesIntegration() // Rewrite stack frame paths
|
|
1257
|
+
Sentry.captureConsoleIntegration() // console → Sentry issues (legacy)
|
|
1258
|
+
|
|
1259
|
+
// ── Remove a Default Integration ─────────────────────────────
|
|
1260
|
+
Sentry.init({
|
|
1261
|
+
integrations: (integrations) =>
|
|
1262
|
+
integrations.filter((i) => i.name !== "Dedupe"),
|
|
1263
|
+
})
|
|
1264
|
+
|
|
1265
|
+
// ── Add Integration After Init ────────────────────────────────
|
|
1266
|
+
Sentry.addIntegration(Sentry.replayIntegration())
|
|
1267
|
+
|
|
1268
|
+
// ── Environment Variables ─────────────────────────────────────
|
|
1269
|
+
// Vite: import.meta.env.VITE_SENTRY_DSN
|
|
1270
|
+
// CRA: process.env.REACT_APP_SENTRY_DSN
|
|
1271
|
+
// Webpack: process.env.SENTRY_DSN (via DefinePlugin)
|
|
1272
|
+
```
|