@danieljvdm/dev-kit 1.0.1 → 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 +6 -29
- package/skill-sources.lock.json +23 -109
- 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 +11 -115
- package/skills/open-pull-request/agents/openai.yaml +3 -3
- 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,815 @@
|
|
|
1
|
+
# User Feedback — Sentry React Native SDK
|
|
2
|
+
|
|
3
|
+
> **Minimum SDK:** `@sentry/react-native` ≥6.5.0 for `captureFeedback()` API\
|
|
4
|
+
> **Feedback widget** (`showFeedbackWidget`, `feedbackIntegration`): ≥6.9.0\
|
|
5
|
+
> **Self-hosted Sentry:** ≥24.4.2 required for full user feedback functionality\
|
|
6
|
+
> **New Architecture (Fabric):** Feedback widget requires React Native ≥0.71+
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## Overview
|
|
11
|
+
|
|
12
|
+
Sentry provides three complementary approaches to collecting user feedback in React
|
|
13
|
+
Native:
|
|
14
|
+
|
|
15
|
+
| Approach | When to Use |
|
|
16
|
+
| ------------------------------ | ----------------------------------------------------------- |
|
|
17
|
+
| **Feedback Widget** | Built-in modal; minimal code; works out of the box |
|
|
18
|
+
| **`FeedbackWidget` component** | Embed feedback form inline within your own screen |
|
|
19
|
+
| **`captureFeedback()` API** | Full control; build your own UI and submit programmatically |
|
|
20
|
+
|
|
21
|
+
All approaches support:
|
|
22
|
+
|
|
23
|
+
- Linking feedback to specific error events via `associatedEventId`
|
|
24
|
+
- Offline caching (stored on-device, sent when connectivity restores)
|
|
25
|
+
- Session Replay integration (buffers last 60 seconds of activity with submitted
|
|
26
|
+
feedback)
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## Prerequisites
|
|
31
|
+
|
|
32
|
+
Wrap your root component with `Sentry.wrap` — this is **required** for the feedback
|
|
33
|
+
widget and error boundary integration:
|
|
34
|
+
|
|
35
|
+
```typescript
|
|
36
|
+
import * as Sentry from "@sentry/react-native";
|
|
37
|
+
|
|
38
|
+
export default Sentry.wrap(App);
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Without `Sentry.wrap`, `Sentry.showFeedbackWidget()` and `Sentry.showFeedbackButton()`
|
|
42
|
+
will not function correctly.
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
## Approach 1: Built-In Feedback Widget
|
|
47
|
+
|
|
48
|
+
The simplest integration.
|
|
49
|
+
Call `Sentry.showFeedbackWidget()` from anywhere — a button, menu item, or support
|
|
50
|
+
screen. For automatic shake-to-report, see
|
|
51
|
+
[Shake to Report](#shake-to-report-built-in-native-detection) below.
|
|
52
|
+
|
|
53
|
+
### Trigger the Widget
|
|
54
|
+
|
|
55
|
+
```typescript
|
|
56
|
+
import * as Sentry from "@sentry/react-native";
|
|
57
|
+
import { Button } from "react-native";
|
|
58
|
+
|
|
59
|
+
function SupportButton() {
|
|
60
|
+
return (
|
|
61
|
+
<Button
|
|
62
|
+
title="Report a Problem"
|
|
63
|
+
onPress={() => Sentry.showFeedbackWidget()}
|
|
64
|
+
/>
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### Persistent Feedback Button
|
|
70
|
+
|
|
71
|
+
Show or hide the built-in floating feedback button:
|
|
72
|
+
|
|
73
|
+
```typescript
|
|
74
|
+
// Show the floating feedback button (persists on screen)
|
|
75
|
+
Sentry.showFeedbackButton();
|
|
76
|
+
|
|
77
|
+
// Hide it when no longer needed
|
|
78
|
+
Sentry.hideFeedbackButton();
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### Shake to Report (Built-In Native Detection)
|
|
82
|
+
|
|
83
|
+
The SDK provides built-in device shake detection that automatically shows the feedback
|
|
84
|
+
widget when the user shakes their device.
|
|
85
|
+
This delegates to native shake detectors in the iOS and Android SDKs — no permissions
|
|
86
|
+
required.
|
|
87
|
+
|
|
88
|
+
**Option A: Enable via `feedbackIntegration` config**
|
|
89
|
+
|
|
90
|
+
```typescript
|
|
91
|
+
Sentry.init({
|
|
92
|
+
dsn: "YOUR_DSN",
|
|
93
|
+
integrations: [Sentry.feedbackIntegration({ enableShakeToReport: true })],
|
|
94
|
+
});
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
**Option B: Imperative API (enable/disable at runtime)**
|
|
98
|
+
|
|
99
|
+
```typescript
|
|
100
|
+
import * as Sentry from "@sentry/react-native";
|
|
101
|
+
|
|
102
|
+
// Start listening for device shakes — shows feedback widget on shake
|
|
103
|
+
Sentry.enableFeedbackOnShake();
|
|
104
|
+
|
|
105
|
+
// Stop listening when no longer needed
|
|
106
|
+
Sentry.disableFeedbackOnShake();
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
> **Platform details:**
|
|
110
|
+
>
|
|
111
|
+
> - **iOS:** Uses UIKit motion event detection (`SentryShakeDetector`)
|
|
112
|
+
> - **Android:** Uses accelerometer sensor (`SentryShakeDetector`)
|
|
113
|
+
> - **Web:** Not supported — shake detection is native-only
|
|
114
|
+
|
|
115
|
+
### Configure the Widget via `feedbackIntegration`
|
|
116
|
+
|
|
117
|
+
Customize appearance and fields in `Sentry.init`:
|
|
118
|
+
|
|
119
|
+
```typescript
|
|
120
|
+
import * as Sentry from "@sentry/react-native";
|
|
121
|
+
|
|
122
|
+
Sentry.init({
|
|
123
|
+
dsn: "YOUR_DSN",
|
|
124
|
+
integrations: [
|
|
125
|
+
Sentry.feedbackIntegration({
|
|
126
|
+
// Field placeholder text
|
|
127
|
+
namePlaceholder: "Full Name",
|
|
128
|
+
emailPlaceholder: "your@email.com",
|
|
129
|
+
messagePlaceholder: "What went wrong? What did you expect?",
|
|
130
|
+
|
|
131
|
+
// Field labels
|
|
132
|
+
nameLabel: "Name",
|
|
133
|
+
emailLabel: "Email",
|
|
134
|
+
messageLabel: "Description",
|
|
135
|
+
submitButtonLabel: "Send Report",
|
|
136
|
+
cancelButtonLabel: "Cancel",
|
|
137
|
+
formTitle: "Report a Bug",
|
|
138
|
+
|
|
139
|
+
// Require fields (all optional by default)
|
|
140
|
+
isNameRequired: false,
|
|
141
|
+
isEmailRequired: false,
|
|
142
|
+
|
|
143
|
+
// Styling
|
|
144
|
+
styles: {
|
|
145
|
+
submitButton: {
|
|
146
|
+
backgroundColor: "#6a1b9a",
|
|
147
|
+
},
|
|
148
|
+
},
|
|
149
|
+
|
|
150
|
+
// Pre-fill from current user context (reads Sentry user scope)
|
|
151
|
+
useSentryUser: {
|
|
152
|
+
name: "username", // maps user.username → name field
|
|
153
|
+
email: "email", // maps user.email → email field
|
|
154
|
+
},
|
|
155
|
+
}),
|
|
156
|
+
],
|
|
157
|
+
});
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
### Architecture Requirements
|
|
161
|
+
|
|
162
|
+
| Architecture | Support |
|
|
163
|
+
| ------------------------- | ------------------------------ |
|
|
164
|
+
| Legacy (Bridge) | ✅ Fully supported |
|
|
165
|
+
| New Architecture (Fabric) | ✅ Requires React Native ≥0.71 |
|
|
166
|
+
|
|
167
|
+
---
|
|
168
|
+
|
|
169
|
+
## Approach 2: `FeedbackWidget` Component
|
|
170
|
+
|
|
171
|
+
Embed the feedback form directly into your own screen layout instead of showing it as a
|
|
172
|
+
modal:
|
|
173
|
+
|
|
174
|
+
```typescript
|
|
175
|
+
import { FeedbackWidget } from "@sentry/react-native";
|
|
176
|
+
import { View, Text, StyleSheet } from "react-native";
|
|
177
|
+
|
|
178
|
+
function SupportScreen() {
|
|
179
|
+
return (
|
|
180
|
+
<View style={styles.container}>
|
|
181
|
+
<Text style={styles.heading}>Having trouble?</Text>
|
|
182
|
+
<Text style={styles.subtext}>
|
|
183
|
+
Describe what happened and we'll look into it.
|
|
184
|
+
</Text>
|
|
185
|
+
<FeedbackWidget />
|
|
186
|
+
</View>
|
|
187
|
+
);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
const styles = StyleSheet.create({
|
|
191
|
+
container: { flex: 1, padding: 16 },
|
|
192
|
+
heading: { fontSize: 20, fontWeight: "bold", marginBottom: 8 },
|
|
193
|
+
subtext: { color: "#666", marginBottom: 16 },
|
|
194
|
+
});
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
The `FeedbackWidget` component respects the same configuration set in
|
|
198
|
+
`feedbackIntegration` within `Sentry.init`.
|
|
199
|
+
|
|
200
|
+
---
|
|
201
|
+
|
|
202
|
+
## Approach 3: Programmatic API (`captureFeedback`)
|
|
203
|
+
|
|
204
|
+
Build a completely custom feedback UI and submit via the SDK. Gives full control over
|
|
205
|
+
form layout, validation, and submission flow.
|
|
206
|
+
|
|
207
|
+
### Basic Feedback (Standalone)
|
|
208
|
+
|
|
209
|
+
```typescript
|
|
210
|
+
import * as Sentry from "@sentry/react-native";
|
|
211
|
+
|
|
212
|
+
Sentry.captureFeedback({
|
|
213
|
+
name: "Jane Smith",
|
|
214
|
+
email: "jane@example.com",
|
|
215
|
+
message: "The checkout button doesn't respond after the first tap.",
|
|
216
|
+
});
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
### Link Feedback to a Specific Error Event
|
|
220
|
+
|
|
221
|
+
```typescript
|
|
222
|
+
import * as Sentry from "@sentry/react-native";
|
|
223
|
+
|
|
224
|
+
// Capture an error and get its ID
|
|
225
|
+
const eventId = Sentry.captureException(new Error("Payment failed"));
|
|
226
|
+
|
|
227
|
+
// Associate the user's report with that exact error
|
|
228
|
+
Sentry.captureFeedback({
|
|
229
|
+
name: "John Doe",
|
|
230
|
+
email: "john@example.com",
|
|
231
|
+
message: "App crashed when I tapped Pay Now.",
|
|
232
|
+
associatedEventId: eventId,
|
|
233
|
+
});
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
### Link Feedback to the Most Recent Event
|
|
237
|
+
|
|
238
|
+
`Sentry.lastEventId()` retrieves the ID of the last event captured in the current
|
|
239
|
+
session — useful for post-crash feedback flows:
|
|
240
|
+
|
|
241
|
+
```typescript
|
|
242
|
+
import * as Sentry from "@sentry/react-native";
|
|
243
|
+
|
|
244
|
+
const lastId = Sentry.lastEventId();
|
|
245
|
+
|
|
246
|
+
if (lastId) {
|
|
247
|
+
Sentry.captureFeedback({
|
|
248
|
+
name: user.name,
|
|
249
|
+
email: user.email,
|
|
250
|
+
message: feedbackText,
|
|
251
|
+
associatedEventId: lastId,
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
### Feedback with Tags and Attachments
|
|
257
|
+
|
|
258
|
+
```typescript
|
|
259
|
+
import * as Sentry from "@sentry/react-native";
|
|
260
|
+
|
|
261
|
+
Sentry.captureFeedback(
|
|
262
|
+
{
|
|
263
|
+
name: user.displayName,
|
|
264
|
+
email: user.email,
|
|
265
|
+
message: feedbackText,
|
|
266
|
+
},
|
|
267
|
+
{
|
|
268
|
+
captureContext: {
|
|
269
|
+
tags: {
|
|
270
|
+
screen: currentScreen,
|
|
271
|
+
appVersion: appVersion,
|
|
272
|
+
platform: Platform.OS,
|
|
273
|
+
},
|
|
274
|
+
},
|
|
275
|
+
attachments: [
|
|
276
|
+
{
|
|
277
|
+
filename: "device_info.txt",
|
|
278
|
+
data: JSON.stringify(deviceInfo, null, 2),
|
|
279
|
+
contentType: "text/plain",
|
|
280
|
+
},
|
|
281
|
+
],
|
|
282
|
+
},
|
|
283
|
+
);
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
---
|
|
287
|
+
|
|
288
|
+
## Crash Report Modal (Post-Crash Feedback)
|
|
289
|
+
|
|
290
|
+
Show a feedback form on the next app launch after a crash.
|
|
291
|
+
This is the recommended pattern for collecting context around hard crashes that the user
|
|
292
|
+
survived.
|
|
293
|
+
|
|
294
|
+
### Pattern: Check for Last Event on Launch
|
|
295
|
+
|
|
296
|
+
```typescript
|
|
297
|
+
import * as Sentry from "@sentry/react-native";
|
|
298
|
+
import React from "react";
|
|
299
|
+
import { Modal, View, Text, TextInput, Button } from "react-native";
|
|
300
|
+
|
|
301
|
+
function App() {
|
|
302
|
+
const [showFeedback, setShowFeedback] = React.useState(false);
|
|
303
|
+
const [feedbackText, setFeedbackText] = React.useState("");
|
|
304
|
+
const lastEventId = React.useRef<string | undefined>(undefined);
|
|
305
|
+
|
|
306
|
+
React.useEffect(() => {
|
|
307
|
+
// Check if there was a crash in the previous session
|
|
308
|
+
const eventId = Sentry.lastEventId();
|
|
309
|
+
if (eventId) {
|
|
310
|
+
lastEventId.current = eventId;
|
|
311
|
+
setShowFeedback(true);
|
|
312
|
+
}
|
|
313
|
+
}, []);
|
|
314
|
+
|
|
315
|
+
function submitCrashFeedback() {
|
|
316
|
+
if (!feedbackText.trim()) return;
|
|
317
|
+
|
|
318
|
+
Sentry.captureFeedback({
|
|
319
|
+
message: feedbackText,
|
|
320
|
+
associatedEventId: lastEventId.current,
|
|
321
|
+
});
|
|
322
|
+
|
|
323
|
+
setShowFeedback(false);
|
|
324
|
+
setFeedbackText("");
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
return (
|
|
328
|
+
<>
|
|
329
|
+
<Modal visible={showFeedback} transparent animationType="slide">
|
|
330
|
+
<View style={{ flex: 1, justifyContent: "center", padding: 24 }}>
|
|
331
|
+
<Text style={{ fontSize: 18, fontWeight: "bold", marginBottom: 8 }}>
|
|
332
|
+
It looks like the app crashed
|
|
333
|
+
</Text>
|
|
334
|
+
<Text style={{ color: "#555", marginBottom: 16 }}>
|
|
335
|
+
What were you doing when it happened?
|
|
336
|
+
</Text>
|
|
337
|
+
<TextInput
|
|
338
|
+
multiline
|
|
339
|
+
value={feedbackText}
|
|
340
|
+
onChangeText={setFeedbackText}
|
|
341
|
+
placeholder="Describe what happened..."
|
|
342
|
+
style={{
|
|
343
|
+
borderWidth: 1,
|
|
344
|
+
borderColor: "#ccc",
|
|
345
|
+
borderRadius: 8,
|
|
346
|
+
padding: 12,
|
|
347
|
+
minHeight: 100,
|
|
348
|
+
marginBottom: 16,
|
|
349
|
+
}}
|
|
350
|
+
/>
|
|
351
|
+
<Button title="Send Report" onPress={submitCrashFeedback} />
|
|
352
|
+
<Button title="Skip" onPress={() => setShowFeedback(false)} />
|
|
353
|
+
</View>
|
|
354
|
+
</Modal>
|
|
355
|
+
{/* rest of app */}
|
|
356
|
+
</>
|
|
357
|
+
);
|
|
358
|
+
}
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
> **Tip:** `Sentry.lastEventId()` returns the ID of the most recent event captured
|
|
362
|
+
> during the _current_ app session.
|
|
363
|
+
> For post-crash context, call it at app start before any other Sentry calls that might
|
|
364
|
+
> create a new event.
|
|
365
|
+
|
|
366
|
+
---
|
|
367
|
+
|
|
368
|
+
## Linking Feedback to Errors via `ErrorBoundary`
|
|
369
|
+
|
|
370
|
+
The `Sentry.ErrorBoundary` component can automatically show a feedback dialog after
|
|
371
|
+
capturing a React render error, using the `showDialog` prop:
|
|
372
|
+
|
|
373
|
+
```typescript
|
|
374
|
+
import * as Sentry from "@sentry/react-native";
|
|
375
|
+
import { Text } from "react-native";
|
|
376
|
+
|
|
377
|
+
function App() {
|
|
378
|
+
return (
|
|
379
|
+
<Sentry.ErrorBoundary
|
|
380
|
+
fallback={<Text>Something went wrong. Your report has been sent.</Text>}
|
|
381
|
+
showDialog // Opens Sentry feedback widget after capturing the error
|
|
382
|
+
>
|
|
383
|
+
<MainContent />
|
|
384
|
+
</Sentry.ErrorBoundary>
|
|
385
|
+
);
|
|
386
|
+
}
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
### Custom Post-Error Feedback Form
|
|
390
|
+
|
|
391
|
+
For full control, use `onError` to capture the `eventId` and trigger your own feedback
|
|
392
|
+
form:
|
|
393
|
+
|
|
394
|
+
```typescript
|
|
395
|
+
import * as Sentry from "@sentry/react-native";
|
|
396
|
+
import React from "react";
|
|
397
|
+
import { View, Text, TextInput, Button } from "react-native";
|
|
398
|
+
|
|
399
|
+
function ErrorFallback({ eventId, onReset }: { eventId: string; onReset: () => void }) {
|
|
400
|
+
const [message, setMessage] = React.useState("");
|
|
401
|
+
|
|
402
|
+
function submit() {
|
|
403
|
+
Sentry.captureFeedback({
|
|
404
|
+
message,
|
|
405
|
+
associatedEventId: eventId,
|
|
406
|
+
});
|
|
407
|
+
onReset();
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
return (
|
|
411
|
+
<View style={{ padding: 24 }}>
|
|
412
|
+
<Text style={{ fontSize: 18, fontWeight: "bold" }}>Oops, something broke</Text>
|
|
413
|
+
<TextInput
|
|
414
|
+
multiline
|
|
415
|
+
value={message}
|
|
416
|
+
onChangeText={setMessage}
|
|
417
|
+
placeholder="What were you trying to do?"
|
|
418
|
+
style={{ borderWidth: 1, borderColor: "#ccc", padding: 12, marginVertical: 16 }}
|
|
419
|
+
/>
|
|
420
|
+
<Button title="Send Feedback" onPress={submit} />
|
|
421
|
+
</View>
|
|
422
|
+
);
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
function App() {
|
|
426
|
+
const [errorEventId, setErrorEventId] = React.useState<string | null>(null);
|
|
427
|
+
|
|
428
|
+
return (
|
|
429
|
+
<Sentry.ErrorBoundary
|
|
430
|
+
onError={(_error, _componentStack, eventId) => {
|
|
431
|
+
setErrorEventId(eventId);
|
|
432
|
+
}}
|
|
433
|
+
fallback={
|
|
434
|
+
errorEventId
|
|
435
|
+
? <ErrorFallback eventId={errorEventId} onReset={() => setErrorEventId(null)} />
|
|
436
|
+
: <Text>Something went wrong.</Text>
|
|
437
|
+
}
|
|
438
|
+
>
|
|
439
|
+
<MainContent />
|
|
440
|
+
</Sentry.ErrorBoundary>
|
|
441
|
+
);
|
|
442
|
+
}
|
|
443
|
+
```
|
|
444
|
+
|
|
445
|
+
---
|
|
446
|
+
|
|
447
|
+
## Screenshots in Feedback
|
|
448
|
+
|
|
449
|
+
Allow users to attach screenshots to feedback reports.
|
|
450
|
+
Use `attachments` in `captureFeedback` to include screenshots captured from the device:
|
|
451
|
+
|
|
452
|
+
```typescript
|
|
453
|
+
import * as Sentry from "@sentry/react-native";
|
|
454
|
+
import { captureScreen } from "react-native-view-shot"; // npm install react-native-view-shot
|
|
455
|
+
import RNFS from "react-native-fs"; // npm install react-native-fs
|
|
456
|
+
|
|
457
|
+
async function submitFeedbackWithScreenshot(feedbackMessage: string) {
|
|
458
|
+
// Capture current screen as PNG
|
|
459
|
+
const screenshotUri = await captureScreen({ format: "png", quality: 0.8 });
|
|
460
|
+
const screenshotBase64 = await RNFS.readFile(screenshotUri, "base64");
|
|
461
|
+
|
|
462
|
+
Sentry.captureFeedback(
|
|
463
|
+
{
|
|
464
|
+
message: feedbackMessage,
|
|
465
|
+
associatedEventId: Sentry.lastEventId(),
|
|
466
|
+
},
|
|
467
|
+
{
|
|
468
|
+
attachments: [
|
|
469
|
+
{
|
|
470
|
+
filename: "screenshot.png",
|
|
471
|
+
data: screenshotBase64,
|
|
472
|
+
contentType: "image/png",
|
|
473
|
+
},
|
|
474
|
+
],
|
|
475
|
+
},
|
|
476
|
+
);
|
|
477
|
+
}
|
|
478
|
+
```
|
|
479
|
+
|
|
480
|
+
> **Alternative:** Enable `attachScreenshot: true` in `Sentry.init` to automatically
|
|
481
|
+
> attach a screenshot to every error event — the screenshot then appears alongside any
|
|
482
|
+
> feedback linked to that event via `associatedEventId`.
|
|
483
|
+
|
|
484
|
+
```typescript
|
|
485
|
+
Sentry.init({
|
|
486
|
+
dsn: "YOUR_DSN",
|
|
487
|
+
attachScreenshot: true, // Auto-attach screenshot to every error event
|
|
488
|
+
});
|
|
489
|
+
```
|
|
490
|
+
|
|
491
|
+
---
|
|
492
|
+
|
|
493
|
+
## Session Replay Integration with Feedback
|
|
494
|
+
|
|
495
|
+
When `mobileReplayIntegration()` is enabled and a user submits feedback via the widget,
|
|
496
|
+
Sentry automatically buffers and attaches **up to 60 seconds of prior session replay**
|
|
497
|
+
to the feedback submission.
|
|
498
|
+
This gives you visual context for what the user experienced before they filed the report
|
|
499
|
+
— no extra code required.
|
|
500
|
+
|
|
501
|
+
```typescript
|
|
502
|
+
Sentry.init({
|
|
503
|
+
dsn: "YOUR_DSN",
|
|
504
|
+
replaysOnErrorSampleRate: 1.0,
|
|
505
|
+
replaysSessionSampleRate: 0.1,
|
|
506
|
+
integrations: [
|
|
507
|
+
Sentry.mobileReplayIntegration(),
|
|
508
|
+
Sentry.feedbackIntegration(), // replay attaches automatically on feedback submit
|
|
509
|
+
],
|
|
510
|
+
});
|
|
511
|
+
```
|
|
512
|
+
|
|
513
|
+
---
|
|
514
|
+
|
|
515
|
+
## Offline Feedback
|
|
516
|
+
|
|
517
|
+
Feedback captured while the device is offline is **automatically cached on-device** by
|
|
518
|
+
the native SDK layer and replayed to Sentry when connectivity is restored.
|
|
519
|
+
This applies to all three approaches (`showFeedbackWidget`, `FeedbackWidget`,
|
|
520
|
+
`captureFeedback`). No additional configuration is needed.
|
|
521
|
+
|
|
522
|
+
---
|
|
523
|
+
|
|
524
|
+
## Complete Custom Feedback Form Example
|
|
525
|
+
|
|
526
|
+
A fully custom feedback flow — your own UI, validation, submission:
|
|
527
|
+
|
|
528
|
+
```typescript
|
|
529
|
+
import React from "react";
|
|
530
|
+
import {
|
|
531
|
+
View,
|
|
532
|
+
Text,
|
|
533
|
+
TextInput,
|
|
534
|
+
TouchableOpacity,
|
|
535
|
+
StyleSheet,
|
|
536
|
+
Alert,
|
|
537
|
+
} from "react-native";
|
|
538
|
+
import * as Sentry from "@sentry/react-native";
|
|
539
|
+
|
|
540
|
+
interface FeedbackFormProps {
|
|
541
|
+
onDismiss: () => void;
|
|
542
|
+
associatedEventId?: string;
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
export function CustomFeedbackForm({ onDismiss, associatedEventId }: FeedbackFormProps) {
|
|
546
|
+
const [name, setName] = React.useState("");
|
|
547
|
+
const [email, setEmail] = React.useState("");
|
|
548
|
+
const [message, setMessage] = React.useState("");
|
|
549
|
+
const [submitting, setSubmitting] = React.useState(false);
|
|
550
|
+
|
|
551
|
+
async function handleSubmit() {
|
|
552
|
+
if (!message.trim()) {
|
|
553
|
+
Alert.alert("Required", "Please describe what happened.");
|
|
554
|
+
return;
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
setSubmitting(true);
|
|
558
|
+
|
|
559
|
+
try {
|
|
560
|
+
Sentry.captureFeedback(
|
|
561
|
+
{
|
|
562
|
+
name: name.trim() || undefined,
|
|
563
|
+
email: email.trim() || undefined,
|
|
564
|
+
message: message.trim(),
|
|
565
|
+
associatedEventId,
|
|
566
|
+
},
|
|
567
|
+
{
|
|
568
|
+
captureContext: {
|
|
569
|
+
tags: { feedbackSource: "custom-form" },
|
|
570
|
+
},
|
|
571
|
+
}
|
|
572
|
+
);
|
|
573
|
+
|
|
574
|
+
Alert.alert("Thank you", "Your feedback has been submitted.");
|
|
575
|
+
onDismiss();
|
|
576
|
+
} catch (err) {
|
|
577
|
+
Alert.alert("Error", "Failed to submit feedback. Please try again.");
|
|
578
|
+
} finally {
|
|
579
|
+
setSubmitting(false);
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
return (
|
|
584
|
+
<View style={styles.container}>
|
|
585
|
+
<Text style={styles.title}>Send Feedback</Text>
|
|
586
|
+
|
|
587
|
+
<TextInput
|
|
588
|
+
style={styles.input}
|
|
589
|
+
placeholder="Name (optional)"
|
|
590
|
+
value={name}
|
|
591
|
+
onChangeText={setName}
|
|
592
|
+
autoCapitalize="words"
|
|
593
|
+
/>
|
|
594
|
+
|
|
595
|
+
<TextInput
|
|
596
|
+
style={styles.input}
|
|
597
|
+
placeholder="Email (optional)"
|
|
598
|
+
value={email}
|
|
599
|
+
onChangeText={setEmail}
|
|
600
|
+
keyboardType="email-address"
|
|
601
|
+
autoCapitalize="none"
|
|
602
|
+
/>
|
|
603
|
+
|
|
604
|
+
<TextInput
|
|
605
|
+
style={[styles.input, styles.messageInput]}
|
|
606
|
+
placeholder="Describe what happened *"
|
|
607
|
+
value={message}
|
|
608
|
+
onChangeText={setMessage}
|
|
609
|
+
multiline
|
|
610
|
+
numberOfLines={5}
|
|
611
|
+
textAlignVertical="top"
|
|
612
|
+
/>
|
|
613
|
+
|
|
614
|
+
<TouchableOpacity
|
|
615
|
+
style={[styles.button, submitting && styles.buttonDisabled]}
|
|
616
|
+
onPress={handleSubmit}
|
|
617
|
+
disabled={submitting}
|
|
618
|
+
>
|
|
619
|
+
<Text style={styles.buttonText}>
|
|
620
|
+
{submitting ? "Sending…" : "Submit"}
|
|
621
|
+
</Text>
|
|
622
|
+
</TouchableOpacity>
|
|
623
|
+
|
|
624
|
+
<TouchableOpacity style={styles.cancelButton} onPress={onDismiss}>
|
|
625
|
+
<Text style={styles.cancelText}>Cancel</Text>
|
|
626
|
+
</TouchableOpacity>
|
|
627
|
+
</View>
|
|
628
|
+
);
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
const styles = StyleSheet.create({
|
|
632
|
+
container: { padding: 24, backgroundColor: "#fff", borderRadius: 12 },
|
|
633
|
+
title: { fontSize: 20, fontWeight: "bold", marginBottom: 16 },
|
|
634
|
+
input: {
|
|
635
|
+
borderWidth: 1,
|
|
636
|
+
borderColor: "#ddd",
|
|
637
|
+
borderRadius: 8,
|
|
638
|
+
padding: 12,
|
|
639
|
+
marginBottom: 12,
|
|
640
|
+
fontSize: 16,
|
|
641
|
+
},
|
|
642
|
+
messageInput: { minHeight: 120 },
|
|
643
|
+
button: {
|
|
644
|
+
backgroundColor: "#6200ee",
|
|
645
|
+
borderRadius: 8,
|
|
646
|
+
padding: 14,
|
|
647
|
+
alignItems: "center",
|
|
648
|
+
marginBottom: 8,
|
|
649
|
+
},
|
|
650
|
+
buttonDisabled: { opacity: 0.6 },
|
|
651
|
+
buttonText: { color: "#fff", fontSize: 16, fontWeight: "600" },
|
|
652
|
+
cancelButton: { alignItems: "center", padding: 10 },
|
|
653
|
+
cancelText: { color: "#666", fontSize: 16 },
|
|
654
|
+
});
|
|
655
|
+
```
|
|
656
|
+
|
|
657
|
+
---
|
|
658
|
+
|
|
659
|
+
## `captureFeedback` API Reference
|
|
660
|
+
|
|
661
|
+
```typescript
|
|
662
|
+
Sentry.captureFeedback(
|
|
663
|
+
feedback: UserFeedback,
|
|
664
|
+
hint?: EventHint
|
|
665
|
+
): string | undefined
|
|
666
|
+
```
|
|
667
|
+
|
|
668
|
+
### `feedback` object
|
|
669
|
+
|
|
670
|
+
| Field | Type | Required | Description |
|
|
671
|
+
| ------------------- | -------- | -------- | ------------------------------------------------------------ |
|
|
672
|
+
| `message` | `string` | ✅ | User’s feedback text |
|
|
673
|
+
| `name` | `string` | ❌ | User’s display name |
|
|
674
|
+
| `email` | `string` | ❌ | User’s email address |
|
|
675
|
+
| `associatedEventId` | `string` | ❌ | Links feedback to a specific Sentry event (error or message) |
|
|
676
|
+
|
|
677
|
+
### `hint` object (optional)
|
|
678
|
+
|
|
679
|
+
| Field | Type | Description |
|
|
680
|
+
| ---------------- | ---------------- | --------------------------------------------------------- |
|
|
681
|
+
| `captureContext` | `CaptureContext` | Scope data to attach (tags, extra, user, level, contexts) |
|
|
682
|
+
| `attachments` | `Attachment[]` | Files to attach (screenshots, logs, etc.) |
|
|
683
|
+
|
|
684
|
+
Returns the feedback event ID (or `undefined` if SDK is disabled).
|
|
685
|
+
|
|
686
|
+
---
|
|
687
|
+
|
|
688
|
+
## `feedbackIntegration` Configuration Reference
|
|
689
|
+
|
|
690
|
+
| Option | Type | Default | Description |
|
|
691
|
+
| --------------------- | --------- | ---------------------------------------- | ------------------------------------------------------------------------------ |
|
|
692
|
+
| `formTitle` | `string` | `"Report a Bug"` | Widget modal title |
|
|
693
|
+
| `submitButtonLabel` | `string` | `"Send Bug Report"` | Submit button text |
|
|
694
|
+
| `cancelButtonLabel` | `string` | `"Cancel"` | Cancel button text |
|
|
695
|
+
| `nameLabel` | `string` | `"Name"` | Name field label |
|
|
696
|
+
| `namePlaceholder` | `string` | `"Your Name"` | Name field placeholder |
|
|
697
|
+
| `emailLabel` | `string` | `"Email"` | Email field label |
|
|
698
|
+
| `emailPlaceholder` | `string` | `"your.email@example.org"` | Email field placeholder |
|
|
699
|
+
| `messageLabel` | `string` | `"Description"` | Message field label |
|
|
700
|
+
| `messagePlaceholder` | `string` | `"What's the bug? What did you expect?"` | Message field placeholder |
|
|
701
|
+
| `isNameRequired` | `boolean` | `false` | Make name field required |
|
|
702
|
+
| `isEmailRequired` | `boolean` | `false` | Make email field required |
|
|
703
|
+
| `useSentryUser` | `object` | — | Maps Sentry user scope fields to pre-fill name/email |
|
|
704
|
+
| `enableShakeToReport` | `boolean` | `false` | Show feedback widget when the user shakes the device (native iOS/Android only) |
|
|
705
|
+
| `styles` | `object` | — | Style overrides for widget UI elements |
|
|
706
|
+
|
|
707
|
+
---
|
|
708
|
+
|
|
709
|
+
## API Summary
|
|
710
|
+
|
|
711
|
+
| Method | Description |
|
|
712
|
+
| ----------------------------------------- | ---------------------------------------------------------- |
|
|
713
|
+
| `Sentry.showFeedbackWidget()` | Open the built-in feedback modal |
|
|
714
|
+
| `Sentry.showFeedbackButton()` | Show the persistent floating feedback button |
|
|
715
|
+
| `Sentry.hideFeedbackButton()` | Hide the persistent floating feedback button |
|
|
716
|
+
| `Sentry.enableFeedbackOnShake()` | Start native shake detection to show feedback widget |
|
|
717
|
+
| `Sentry.disableFeedbackOnShake()` | Stop native shake detection |
|
|
718
|
+
| `Sentry.captureFeedback(feedback, hint?)` | Submit feedback programmatically |
|
|
719
|
+
| `Sentry.lastEventId()` | Get the ID of the most recent captured event (for linking) |
|
|
720
|
+
| `Sentry.feedbackIntegration(options)` | Configure the built-in widget |
|
|
721
|
+
|
|
722
|
+
---
|
|
723
|
+
|
|
724
|
+
## Version Requirements
|
|
725
|
+
|
|
726
|
+
| Feature | Min SDK | Notes |
|
|
727
|
+
| ------------------------------------------------- | ------------------ | ------------------------------------------- |
|
|
728
|
+
| `captureFeedback()` | ≥6.5.0 | Replaces deprecated `captureUserFeedback()` |
|
|
729
|
+
| `showFeedbackWidget()` | ≥6.9.0 | Requires `Sentry.wrap(App)` |
|
|
730
|
+
| `feedbackIntegration()` | ≥6.9.0 | Configure widget appearance |
|
|
731
|
+
| `FeedbackWidget` component | ≥6.9.0 | Inline embedded widget |
|
|
732
|
+
| `showFeedbackButton()` / `hideFeedbackButton()` | ≥6.15.0 | Floating feedback button |
|
|
733
|
+
| `enableShakeToReport` / `enableFeedbackOnShake()` | ≥8.5.0 | Native shake detection (iOS & Android) |
|
|
734
|
+
| Offline caching | Built-in | Automatic, no config needed |
|
|
735
|
+
| Session Replay attachment | ≥6.9.0 | When `mobileReplayIntegration` enabled |
|
|
736
|
+
| New Architecture (Fabric) support | React Native ≥0.71 | Widget works on new arch |
|
|
737
|
+
|
|
738
|
+
---
|
|
739
|
+
|
|
740
|
+
## Expo Considerations
|
|
741
|
+
|
|
742
|
+
- The feedback widget works in **Expo managed and bare** workflows
|
|
743
|
+
- `showFeedbackWidget()` requires a **native build** — it does **not** function in Expo
|
|
744
|
+
Go
|
|
745
|
+
- `captureFeedback()` (programmatic API) works in both Expo Go and native builds
|
|
746
|
+
- Use `isRunningInExpoGo()` to guard widget calls in dev:
|
|
747
|
+
|
|
748
|
+
```typescript
|
|
749
|
+
import { isRunningInExpoGo } from "expo";
|
|
750
|
+
import * as Sentry from "@sentry/react-native";
|
|
751
|
+
|
|
752
|
+
function ReportButton() {
|
|
753
|
+
if (isRunningInExpoGo()) {
|
|
754
|
+
// Fallback: use captureFeedback directly instead of the widget
|
|
755
|
+
return (
|
|
756
|
+
<Button
|
|
757
|
+
title="Report (dev mode)"
|
|
758
|
+
onPress={() =>
|
|
759
|
+
Sentry.captureFeedback({ message: "Test feedback from Expo Go" })
|
|
760
|
+
}
|
|
761
|
+
/>
|
|
762
|
+
);
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
return (
|
|
766
|
+
<Button
|
|
767
|
+
title="Report a Problem"
|
|
768
|
+
onPress={() => Sentry.showFeedbackWidget()}
|
|
769
|
+
/>
|
|
770
|
+
);
|
|
771
|
+
}
|
|
772
|
+
```
|
|
773
|
+
|
|
774
|
+
---
|
|
775
|
+
|
|
776
|
+
## Migration: `captureUserFeedback` → `captureFeedback`
|
|
777
|
+
|
|
778
|
+
`captureUserFeedback()` was removed in v7. Replace all usages:
|
|
779
|
+
|
|
780
|
+
```typescript
|
|
781
|
+
// ❌ BEFORE (v6 and earlier) — removed in v7
|
|
782
|
+
Sentry.captureUserFeedback({
|
|
783
|
+
event_id: eventId,
|
|
784
|
+
name: "John",
|
|
785
|
+
email: "john@example.com",
|
|
786
|
+
comments: "Something went wrong.",
|
|
787
|
+
});
|
|
788
|
+
|
|
789
|
+
// ✅ AFTER (v7+)
|
|
790
|
+
Sentry.captureFeedback({
|
|
791
|
+
associatedEventId: eventId,
|
|
792
|
+
name: "John",
|
|
793
|
+
email: "john@example.com",
|
|
794
|
+
message: "Something went wrong.", // renamed from "comments"
|
|
795
|
+
});
|
|
796
|
+
```
|
|
797
|
+
|
|
798
|
+
---
|
|
799
|
+
|
|
800
|
+
## Troubleshooting
|
|
801
|
+
|
|
802
|
+
| Issue | Solution |
|
|
803
|
+
| ------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------- |
|
|
804
|
+
| `showFeedbackWidget()` has no effect | Confirm `Sentry.wrap(App)` wraps your root component |
|
|
805
|
+
| Widget doesn’t open on New Architecture | Requires React Native ≥0.71; check architecture compatibility |
|
|
806
|
+
| Feedback not appearing in Sentry dashboard | Verify DSN is correct; check network connectivity; enable `debug: true` for SDK logs |
|
|
807
|
+
| `captureFeedback` not sending in Expo Go | Expected — use `captureFeedback()` (works) but not `showFeedbackWidget()` (native only) |
|
|
808
|
+
| `lastEventId()` returns `undefined` | No events have been captured in the current session yet; ensure an error or message was captured first |
|
|
809
|
+
| Offline feedback not delivered | Offline caching is automatic; check `maxCacheItems` (default: 30); old cache is evicted if full |
|
|
810
|
+
| `captureUserFeedback` is not a function | Upgrade to `@sentry/react-native` ≥7.0.0 and replace with `captureFeedback()` |
|
|
811
|
+
| Replay not attaching to feedback | Confirm `mobileReplayIntegration()` is in `integrations` and the app is running as a native build |
|
|
812
|
+
| `associatedEventId` not linking correctly | Pass the exact event ID string returned by `captureException`, `captureMessage`, or `lastEventId()` |
|
|
813
|
+
| Widget styles not applying | Pass `styles` config inside `feedbackIntegration({ styles: { ... } })` in `Sentry.init` |
|
|
814
|
+
| Shake to report not working | Confirm `Sentry.wrap(App)` wraps your root component; shake detection is native-only (not available on Web or Expo Go) |
|
|
815
|
+
| Shake detected but widget doesn’t appear | Ensure `feedbackIntegration()` is in the `integrations` array; check `debug: true` for logs |
|