Integrating under SSR Framework¶
The RUM SDK can only be initialized in the browser environment and must not be executed during server-side rendering. This page describes how to integrate the official framework plugins for Next.js and Nuxt.
| Stage | Runtime Environment | Initialize RUM |
|---|---|---|
| SSR, Server Component, or Nitro Execution Phase | Node.js | No |
| Hydration and Client-Side Routing Phase | Browser | Yes |
The framework plugins capture browser Views, Resources, Actions, and client-side errors. For pure server-side requests, Server Actions, Nitro processing, and server-side errors that are not passed to the client, a server-side monitoring solution is required.
Version Requirements
Next.js and Nuxt framework plugins are available starting from RUM SDK 3.3.6. The version of the main RUM package must not be lower than the framework plugin version.
The following examples use the public OpenWay site and clientToken. When using a direct connection to DataKit, replace these two parameters with datakitOrigin; do not configure both reporting endpoints simultaneously.
Next.js¶
The Next.js plugin supports Next.js 13 and above, React 18 and above, as well as App Router and Pages Router.
Installation¶
App Router: Next.js 15.3 and above¶
Next.js 15.3 and above support instrumentation-client.js|ts. This file runs before hydration, making it suitable for initializing browser monitoring as early as possible.
Create instrumentation-client.ts; when using the src directory, place the file in src/instrumentation-client.ts:
import { datafluxRum } from "@cloudcare/browser-rum"
import {
nextjsPlugin,
onRouterTransitionStart,
} from "@cloudcare/browser-rum-nextjs"
export { onRouterTransitionStart }
datafluxRum.init({
applicationId: "<APPLICATION_ID>",
site: "<PUBLIC_OPENWAY_URL>",
clientToken: "<CLIENT_TOKEN>",
service: "web-nextjs",
env: "production",
version: "1.0.0",
sessionSampleRate: 100,
plugins: [nextjsPlugin()],
})
Create a client-side Router tracker:
// app/rum-router-tracker.tsx
"use client"
import { RumNextjsAppRouter } from "@cloudcare/browser-rum-nextjs"
export function RumRouterTracker() {
return <RumNextjsAppRouter />
}
Render it once in the root layout:
// app/layout.tsx
import { RumRouterTracker } from "./rum-router-tracker"
export default function RootLayout({ children }) {
return (
<html lang="zh-CN">
<body>
<RumRouterTracker />
{children}
</body>
</html>
)
}
onRouterTransitionStart() records the navigation target, and RumNextjsAppRouter only creates a View after the new pathname is actually committed. Invalid Views are not created for canceled, failed, or uncommitted renderings; when a successful redirect occurs, the View uses the final committed pathname.
App Router: Next.js 13 to 15.2¶
These versions do not have instrumentation-client. You can place a client-side initialization component in the root layout:
// app/rum-provider.tsx
"use client"
import { useEffect } from "react"
import { datafluxRum } from "@cloudcare/browser-rum"
import {
nextjsPlugin,
RumNextjsAppRouter,
} from "@cloudcare/browser-rum-nextjs"
let initialized = false
export function RumProvider() {
useEffect(() => {
if (initialized) return
initialized = true
datafluxRum.init({
applicationId: "<APPLICATION_ID>",
site: "<PUBLIC_OPENWAY_URL>",
clientToken: "<CLIENT_TOKEN>",
service: "web-nextjs",
env: "production",
version: "1.0.0",
sessionSampleRate: 100,
plugins: [nextjsPlugin()],
})
}, [])
return <RumNextjsAppRouter />
}
Render <RumProvider /> in app/layout.tsx. This approach can capture successfully committed App Router routes, but the initialization timing is later than instrumentation-client.
Pages Router¶
Initialize and render the Pages Router tracker in pages/_app.tsx:
import { useEffect } from "react"
import { datafluxRum } from "@cloudcare/browser-rum"
import {
nextjsPlugin,
RumNextjsPagesRouter,
} from "@cloudcare/browser-rum-nextjs"
let initialized = false
export default function App({ Component, pageProps }) {
useEffect(() => {
if (initialized) return
initialized = true
datafluxRum.init({
applicationId: "<APPLICATION_ID>",
site: "<PUBLIC_OPENWAY_URL>",
clientToken: "<CLIENT_TOKEN>",
service: "web-nextjs",
env: "production",
version: "1.0.0",
sessionSampleRate: 100,
plugins: [nextjsPlugin()],
})
}, [])
return (
<>
<RumNextjsPagesRouter />
<Component {...pageProps} />
</>
)
}
Pages Router uses router.pathname as the template name. For example, the actual URL /users/42 is grouped under /users/[id]. routeChangeError, canceled navigation, and changes to only query or hash do not create a new View.
Next.js View and Error¶
App Router generates file route templates based on usePathname() and useParams():
| Actual URL | View Name |
|---|---|
/ |
/ |
/users/42 |
/users/[id] |
/docs/a/b |
/docs/[...slug] |
When a stable name cannot be automatically generated, you can pass getViewName:
Call addNextjsError() in error.tsx, global-error.tsx, or business error handlers of App Router:
"use client"
import { useEffect } from "react"
import { addNextjsError } from "@cloudcare/browser-rum-nextjs"
export default function ErrorPage({ error, reset }) {
useEffect(() => {
addNextjsError(error, undefined, {
route_boundary: "dashboard",
})
}, [error])
return <button onClick={reset}>Retry</button>
}
When the error object includes a Next.js digest, the plugin writes it into the Error context, making it easier to correlate with server-side logs. The plugin also provides an ErrorBoundary that can be used to protect client-side React subtrees.
Nuxt¶
The Nuxt plugin supports Nuxt 3, 4, as well as Vue 3 and Vue Router 4.
Installation¶
Create a Client Plugin¶
Create rum.client.ts in the project's plugins directory. The .client suffix ensures the code only runs in the browser, and enforce: "pre" makes RUM install route and error listeners as early as possible.
import { datafluxRum } from "@cloudcare/browser-rum"
import { nuxtRumPlugin } from "@cloudcare/browser-rum-nuxt"
export default defineNuxtPlugin({
name: "dataflux-rum",
enforce: "pre",
setup(nuxtApp) {
datafluxRum.init({
applicationId: "<APPLICATION_ID>",
site: "<PUBLIC_OPENWAY_URL>",
clientToken: "<CLIENT_TOKEN>",
service: "web-nuxt",
env: "production",
version: "1.0.0",
sessionSampleRate: 100,
plugins: [
nuxtRumPlugin({
nuxtApp,
router: useRouter(),
}),
],
})
},
})
Nuxt automatically registers plugins at the top level of the plugins directory; no need to write in nuxt.config.ts. Do not use both the Nuxt plugin and the Vue plugin to track the same Router in the same application.
Nuxt View and Error¶
The plugin converts Vue Router parameter paths to Nuxt file route names:
| Vue Router Path | RUM View Name |
|---|---|
/users/:id |
/users/[id] |
/users/:id? |
/users/[[id]] |
/docs/:slug(.*)* |
/docs/[...slug] |
Successful pathname navigations and hash routes create a View; only query changes and failed navigations do not create a View. To customize the name, pass getViewName(route) in nuxtRumPlugin().
When nuxtApp is passed, the plugin handles both Vue component errors and Nuxt app:error. If the same Error object enters both error paths during a single propagation, it will only be reported once, preserving the existing Vue error handler of the application.
Call addNuxtError() when actively catching errors in business logic:
import { addNuxtError } from "@cloudcare/browser-rum-nuxt"
try {
await submitOrder()
} catch (error) {
addNuxtError(error, {
operation: "submit_order",
module: "checkout",
})
}
Verify the Integration¶
- Open the browser developer tools and filter by
/v1/write/rumin the Network tab. - On the first page load, confirm that
type=viewappears. - Navigate to a dynamic route, confirm that the View uses a file route template like
/users/[id]. - Change only the query parameter, confirm that no duplicate View is created.
- Trigger a client component error, confirm that
type=errorappears, and includescontext.framework = nextjsorcontext.framework = nuxt.
Frequently Asked Questions¶
window is not defined during build¶
RUM initialization has entered a server-side module. For Next.js, use instrumentation-client.ts or an initialization component with "use client"; for Nuxt, the plugin file must use the .client.ts or .client.js suffix.
Error exists but no framework View¶
For Next.js, the tracker corresponding to the current Router must be rendered; for Nuxt, the plugin must receive router: useRouter(). Do not mix multiple Router trackers in the same application.
One navigation produces multiple Views¶
Place only one tracker in the entire application, and do not call datafluxRum.startView() for the same navigation.