diff --git a/dev-packages/e2e-tests/test-applications/nuxt-5/app/pages/route-provider/[id].vue b/dev-packages/e2e-tests/test-applications/nuxt-5/app/pages/route-provider/[id].vue
new file mode 100644
index 000000000000..15ecf3348e94
--- /dev/null
+++ b/dev-packages/e2e-tests/test-applications/nuxt-5/app/pages/route-provider/[id].vue
@@ -0,0 +1,14 @@
+
+
+
+ {{ route }}
+
diff --git a/dev-packages/e2e-tests/test-applications/nuxt-5/tests/route-provider.test.ts b/dev-packages/e2e-tests/test-applications/nuxt-5/tests/route-provider.test.ts
new file mode 100644
index 000000000000..4796384fbb47
--- /dev/null
+++ b/dev-packages/e2e-tests/test-applications/nuxt-5/tests/route-provider.test.ts
@@ -0,0 +1,8 @@
+import { expect, test } from '@playwright/test';
+
+// The route provider reads the router off the Nuxt app, so this fails if the plugin never registers it.
+test('resolves the parameterized route through the route provider', async ({ page }) => {
+ await page.goto('/route-provider/123');
+
+ await expect(page.locator('#resolved-route')).toHaveText('/route-provider/:id()');
+});
diff --git a/packages/nuxt/src/runtime/plugins/sentry.client.ts b/packages/nuxt/src/runtime/plugins/sentry.client.ts
index 6d03b3cd9625..a9969c3be2f7 100644
--- a/packages/nuxt/src/runtime/plugins/sentry.client.ts
+++ b/packages/nuxt/src/runtime/plugins/sentry.client.ts
@@ -1,5 +1,11 @@
import { getClient, GLOBAL_OBJ } from '@sentry/core';
-import { browserTracingIntegration, vueIntegration } from '@sentry/vue';
+import {
+ browserTracingIntegration,
+ createVueRouteProvider,
+ getRouteProvider,
+ setRouteProvider,
+ vueIntegration,
+} from '@sentry/vue';
import { defineNuxtPlugin, isNuxtError } from 'nuxt/app';
import type { GlobalObjWithIntegrationOptions } from '../../client/vueIntegration';
import { reportNuxtError } from '../utils';
@@ -28,6 +34,8 @@ interface VueRouter {
beforeEach: (fn: (to: Route, from: Route, next?: () => void) => void) => void;
}
+type VueRouteProviderRouter = ReturnType[0]>;
+
// Tree-shakable guard to remove all code related to tracing
declare const __SENTRY_TRACING__: boolean;
@@ -35,6 +43,19 @@ export default defineNuxtPlugin({
name: 'sentry-client-integrations',
dependsOn: ['sentry-client-config'],
async setup(nuxtApp) {
+ // Registered outside the tracing guard, because route parameterization should not depend on
+ // tracing: anything that needs a route name (bfcache metrics, web vitals) can resolve one even
+ // when tracing is tree-shaken away. Nuxt installs the router before its plugins run, so unlike
+ // `@sentry/vue` this can read it straight off `nuxtApp`.
+ const client = getClient();
+ // A `routeProvider` passed to `Sentry.init` is the user's choice, so it is left in place.
+ if (client && '$router' in nuxtApp && !getRouteProvider(client)) {
+ setRouteProvider(
+ createVueRouteProvider(() => nuxtApp.$router as VueRouteProviderRouter),
+ client,
+ );
+ }
+
// This evaluates to true unless __SENTRY_TRACING__ is text-replaced with "false", in which case everything inside
// will get tree-shaken away
if (typeof __SENTRY_TRACING__ === 'undefined' || __SENTRY_TRACING__) {