diff --git a/static/app/gettingStartedDocs/javascript/tanstackstart-react/onboarding.tsx b/static/app/gettingStartedDocs/javascript/tanstackstart-react/onboarding.tsx
index f19ea466af499d..19b3b3cb0ed2a1 100644
--- a/static/app/gettingStartedDocs/javascript/tanstackstart-react/onboarding.tsx
+++ b/static/app/gettingStartedDocs/javascript/tanstackstart-react/onboarding.tsx
@@ -1,3 +1,4 @@
+import {ExternalLink} from 'sentry/components/core/link';
import type {OnboardingConfig} from 'sentry/components/onboarding/gettingStartedDoc/types';
import {StepType} from 'sentry/components/onboarding/gettingStartedDoc/types';
import {t, tct} from 'sentry/locale';
@@ -52,7 +53,7 @@ export const onboarding: OnboardingConfig = {
{
type: 'text',
text: tct(
- "First, extend your app's default TanStack Start configuration by adding [code:wrapVinxiConfigWithSentry] to your [code:app.config.ts] file:",
+ 'First, initialize Sentry on the client in your [code:src/router.tsx] file:',
{code: }
),
},
@@ -62,115 +63,69 @@ export const onboarding: OnboardingConfig = {
{
label: 'TypeScript',
language: 'typescript',
- filename: 'app.config.ts',
- code: `import { defineConfig } from "@tanstack/react-start/config";
-import { wrapVinxiConfigWithSentry } from "@sentry/tanstackstart-react";
-
-const config = defineConfig({
- // ... your other TanStack Start config
-})
-
-export default wrapVinxiConfigWithSentry(config, {
- org: "${params.organization.slug}",
- project: "${params.project.slug}",
- authToken: process.env.SENTRY_AUTH_TOKEN,
+ filename: 'src/router.tsx',
+ code: `import * as Sentry from "@sentry/tanstackstart-react";
+import { createRouter } from '@tanstack/react-router'
- // Only print logs for uploading source maps in CI
- // Set to \`true\` to suppress logs
- silent: !process.env.CI,
-});
-`,
- },
- ],
- },
- {
- type: 'text',
- text: tct(
- 'In future versions of this SDK, setting the [code:SENTRY_AUTH_TOKEN] environment variable during your build will upload sourcemaps for you to see unminified errors in Sentry.',
- {code: }
- ),
- },
- {
- type: 'code',
- tabs: [
- {
- language: 'bash',
- label: 'Bash',
- code: `SENTRY_AUTH_TOKEN=___ORG_AUTH_TOKEN___`,
- },
- ],
- },
- {
- type: 'text',
- text: tct(
- 'Add the following initialization code to your [code:app/client.tsx] file to initialize Sentry on the client:',
- {code: }
- ),
- },
- {
- type: 'code',
- tabs: [
- {
- label: 'TypeScript',
- language: 'tsx',
- filename: 'app/client.tsx',
- code: `import { hydrateRoot } from "react-dom/client";
-import { StartClient } from "@tanstack/react-start";
-import { createRouter } from "./router";
+// Create a new router instance
+export const getRouter = () => {
+ const router = createRouter();
-import * as Sentry from "@sentry/tanstackstart-react";
+ if (!router.isServer) {
+ Sentry.init({
+ dsn: "${params.dsn.public}",
-const router = createRouter();
+ // Adds request headers and IP for users, for more info visit:
+ // https://docs.sentry.io/platforms/javascript/guides/tanstackstart-react/configuration/options/#sendDefaultPii
+ sendDefaultPii: true,${
+ params.isPerformanceSelected || params.isReplaySelected
+ ? `
-Sentry.init({
- dsn: "${params.dsn.public}",${
- params.isPerformanceSelected || params.isReplaySelected
- ? `
- integrations: [${
- params.isPerformanceSelected
- ? `
- Sentry.tanstackRouterBrowserTracingIntegration(router),`
- : ''
- }${
- params.isReplaySelected
- ? `
- Sentry.replayIntegration(),`
- : ''
- }
- ],`
- : ''
- }${
- params.isPerformanceSelected
- ? `
+ integrations: [${
+ params.isPerformanceSelected
+ ? `
+ Sentry.tanstackRouterBrowserTracingIntegration(router),`
+ : ''
+ }${
+ params.isReplaySelected
+ ? `
+ Sentry.replayIntegration(),`
+ : ''
+ }
+ ],`
+ : ''
+ }${
+ params.isPerformanceSelected
+ ? `
- // Set tracesSampleRate to 1.0 to capture 100%
- // of transactions for tracing.
- tracesSampleRate: 1.0,`
- : ''
- }${
- params.isReplaySelected
- ? `
+ // Set tracesSampleRate to 1.0 to capture 100%
+ // of transactions for tracing.
+ // We recommend adjusting this value in production.
+ // Learn more at https://docs.sentry.io/platforms/javascript/configuration/options/#traces-sample-rate
+ tracesSampleRate: 1.0,`
+ : ''
+ }${
+ params.isReplaySelected
+ ? `
- // Capture Replay for 10% of all sessions,
- // plus for 100% of sessions with an error.
- replaysSessionSampleRate: 0.1,
- replaysOnErrorSampleRate: 1.0,`
- : ''
+ // Capture Replay for 10% of all sessions,
+ // plus for 100% of sessions with an error.
+ replaysSessionSampleRate: 0.1,
+ replaysOnErrorSampleRate: 1.0,`
+ : ''
+ }
+ });
}
- // Setting this option to true will send default PII data to Sentry.
- // For example, automatic IP address collection on events
- sendDefaultPii: true,
-});
-
-hydrateRoot(document, }
),
},
@@ -180,26 +135,25 @@ hydrateRoot(document, }
- ),
- },
- {
- type: 'code',
- tabs: [
+ 'For production monitoring, you need to move the Sentry server config file to your build output. Since [hostingLink:TanStack Start is designed to work with any hosting provider], the exact location will depend on where your build artifacts are deployed (for example, [code:/dist], [code:.output/server] or a platform-specific directory).',
{
- label: 'TypeScript',
- language: 'tsx',
- filename: 'app/routes/__root.tsx',
- code: `import type { ReactNode } from "react";
-import { createRootRoute } from "@tanstack/react-router";
-
-// (Wrap \`createRootRoute\`, not its return value!)
-export const Route = wrapCreateRootRouteWithSentry(createRootRoute)({
- // ...
-});`,
- },
- ],
+ code: ,
+ hostingLink: (
+ }
+ 'For example, when using [nitroLink:Nitro], copy the instrumentation file to [code:.output/server]:',
+ {
+ code: ,
+ nitroLink: }
),
},
@@ -268,33 +206,30 @@ export default createStartHandler({
type: 'code',
tabs: [
{
- label: 'TypeScript',
- language: 'typescript',
- filename: 'app/global-middleware.ts',
- code: `import {
- createMiddleware,
- registerGlobalMiddleware,
-} from "@tanstack/react-start";
-import * as Sentry from "@sentry/tanstackstart-react";
-
-registerGlobalMiddleware({
- middleware: [
- createMiddleware().server(Sentry.sentryGlobalServerMiddlewareHandler()),
- ],
-});`,
+ label: 'JSON',
+ language: 'json',
+ filename: 'package.json',
+ code: `{
+ "scripts": {
+ "build": "vite build && cp instrument.server.mjs .output/server",
+ "dev": "NODE_OPTIONS='--import ./instrument.server.mjs' vite dev --port 3000",
+ "start": "node --import ./.output/server/instrument.server.mjs .output/server/index.mjs",
+ }
+}`,
},
],
},
{
type: 'text',
- text: t(
- 'The Sentry SDK cannot capture errors that you manually caught yourself with error boundaries.'
+ text: tct(
+ 'Sentry automatically captures unhandled client-side errors. On the server side of TanStack Start, automatic error monitoring is not yet supported. Use [code:captureException] to manually capture errors in your server-side code.',
+ {code: }
),
},
{
type: 'text',
text: tct(
- 'If you have React error boundaries in your app and you want to report errors that these boundaries catch to Sentry, apply the [code:withErrorBoundary] wrapper to your [code:ErrorBoundary]:',
+ "Errors caught by your own error boundaries aren't captured unless you report them manually. Wrap your custom [code:ErrorBoundary] component with [code:withErrorBoundary]:",
{code: }
),
},
@@ -350,10 +285,37 @@ const route = createRoute({
},
],
},
+ {
+ type: 'text',
+ text: tct(
+ 'You can prevent ad blockers from blocking Sentry events using tunneling. Use the [code:tunnel] option to add an API endpoint in your application that forwards Sentry events to Sentry servers.',
+ {code: }
+ ),
+ },
+ {
+ type: 'text',
+ text: tct(
+ 'To enable tunneling, update [code:Sentry.init] with the following option:',
+ {code: }
+ ),
+ },
+ {
+ type: 'code',
+ tabs: [
+ {
+ label: 'TypeScript',
+ language: 'tsx',
+ code: `Sentry.init({
+ dsn: "${params.dsn.public}",
+ tunnel: '/tunnel',
+});`,
+ },
+ ],
+ },
],
},
],
- verify: () => [
+ verify: params => [
{
type: StepType.VERIFY,
content: [
@@ -366,7 +328,7 @@ const route = createRoute({
{
type: 'text',
text: t(
- 'To verify that Sentry captures errors and creates issues in your Sentry project, add a test button to an existing page or create a new one:'
+ 'To verify that Sentry captures errors and creates issues in your Sentry project, add a test button to one of your pages, which will trigger an error that Sentry will capture when you click it:'
),
},
{
@@ -388,46 +350,60 @@ const route = createRoute({
],
},
{
- type: 'text',
- text: tct(
- 'To test tracing, create a test API route like /api/sentry-example-api:',
- {code: }
- ),
- },
- {
- type: 'code',
- tabs: [
+ type: 'conditional',
+ condition: params.isPerformanceSelected,
+ content: [
{
- label: 'TypeScript',
- language: 'typescript',
- filename: 'app/routes/api/sentry-example-api.ts',
- code: `import { json } from "@tanstack/react-start";
-import { createAPIFileRoute } from "@tanstack/react-start/api";
+ type: 'text',
+ text: tct(
+ 'To test tracing, create a new file like [code:src/routes/api/sentry-example.ts] to create a test route [code:/api/sentry-example]:',
+ {code: }
+ ),
+ },
+ {
+ type: 'code',
+ tabs: [
+ {
+ label: 'TypeScript',
+ language: 'typescript',
+ filename: 'src/app/routes/api/sentry-example-api.ts',
+ code: `import { createFileRoute } from "@tanstack/react-router";
+import { json } from "@tanstack/react-start";
-// A faulty API route to test Sentry's error monitoring
-export const APIRoute = createAPIFileRoute("/api/sentry-example-api")({
- GET: ({ request, params }) => {
- throw new Error("Sentry Example API Route Error");
- return json({ message: "Testing Sentry Error..." });
+export const Route = createFileRoute("/api/sentry-example")({
+ server: {
+ handlers: {
+ GET: () => {
+ throw new Error("Sentry Example Route Error");
+ return new Response(
+ JSON.stringify({ message: "Testing Sentry Error..." }),
+ {
+ headers: {
+ "Content-Type": "application/json",
+ },
+ },
+ );
+ },
+ },
},
});`,
+ },
+ ],
},
- ],
- },
- {
- type: 'text',
- text: tct(
- "Next, update your test button to call this route and throw an error if the response isn't [code:ok]:",
- {code: }
- ),
- },
- {
- type: 'code',
- tabs: [
{
- label: 'TypeScript',
- language: 'tsx',
- code: `}
+ ),
+ },
+ {
+ type: 'code',
+ tabs: [
+ {
+ label: 'TypeScript',
+ language: 'tsx',
+ code: ``,
+;`,
+ },
+ ],
+ },
+ {
+ type: 'text',
+ text: t(
+ 'Open the page in a browser and click the button to trigger two errors:'
+ ),
+ },
+ {
+ type: 'custom',
+ content: (
+