Frontend Framework Plugin Integration¶
Starting from RUM SDK 3.3.6, framework plugins can be used to collect framework router Views and framework errors.
Framework plugins are independent of the main RUM package. An application only needs to install the plugins it actually uses.
Supported Ranges¶
| Framework | Supported Versions | Router Capability | Error Capability |
|---|---|---|---|
| React | React 18, 19; React Router 6, 7, 8; TanStack Router 1.x | Names Views using route templates, ignore only query or hash changes | ErrorBoundary, addReactError() |
| Vue | Vue 2.7 + Vue Router 3; Vue 3 + Vue Router 4 | Names Views using matched route templates, ignore only query changes | Vue global error handler, addVueError() |
| Angular | Angular 15 to 22; RxJS 7 and above | Starts View after NavigationEnd, ignores canceled, failed, or only query or hash changes |
Angular ErrorHandler, addAngularError() |
| Next.js | Next.js 13 and above, React 18 and above | Supports App Router and Pages Router | See SSR framework access |
| Nuxt | Nuxt 3, 4; Vue 3; Vue Router 4 | Supports Nuxt file-based routing and client-side navigation | See SSR framework access |
Version Requirements
The main RUM package version must not be lower than the framework plugin version. An application can only initialize either the full RUM package or the slim RUM package, not both at the same time.
The full RUM package supports Session Replay and compressed reporting; the slim RUM package does not include these two capabilities.
Both RUM packages can use framework plugins to collect Views and Errors.
When using the slim RUM package, only replace the RUM import, the framework plugin configuration remains unchanged:
The following examples use the public OpenWay's site and clientToken. When connecting directly via DataKit, replace these two parameters with datakitOrigin. Do not configure both reporting addresses simultaneously.
React¶
Installation¶
React Router¶
To enable Router integration, you need to:
- Set
router: trueinreactPlugin(); - Import the Router creation API,
Routes, oruseRoutesfrom the plugin subpath matching the React Router major version.
The following example uses React Router 6:
import { RouterProvider } from "react-router-dom"
import { datafluxRum } from "@cloudcare/browser-rum"
import { reactPlugin } from "@cloudcare/browser-rum-react"
import {
createBrowserRouter,
} from "@cloudcare/browser-rum-react/react-router-v6"
const router = createBrowserRouter([
{ path: "/", element: <Home /> },
{ path: "/users/:id", element: <UserDetail /> },
])
datafluxRum.init({
applicationId: "<APPLICATION_ID>",
site: "<PUBLIC_OPENWAY_URL>",
clientToken: "<CLIENT_TOKEN>",
service: "web-react",
env: "production",
version: "1.0.0",
sessionSampleRate: 100,
plugins: [reactPlugin({ router: true })],
})
root.render(<RouterProvider router={router} />)
Select the entry based on the Router version:
| Router | Plugin Entry | APIs exported from the plugin entry |
|---|---|---|
| React Router 6 | @cloudcare/browser-rum-react/react-router-v6 |
createBrowserRouter, createHashRouter, createMemoryRouter, Routes, useRoutes |
| React Router 7 | @cloudcare/browser-rum-react/react-router-v7 |
Same as above |
| React Router 8 | @cloudcare/browser-rum-react/react-router-v8 |
Same as above |
| TanStack Router 1.x | @cloudcare/browser-rum-react/tanstack-router |
createRouter |
Other Router APIs are still imported from the Router package installed in the application. Do not import Router wrappers from the framework plugin's main entry, otherwise the plugin cannot distinguish the Router major version.
React Errors¶
Use ErrorBoundary at the application root node or around critical business areas:
import { ErrorBoundary } from "@cloudcare/browser-rum-react"
root.render(
<ErrorBoundary
fallback={({ resetError }) => (
<button type="button" onClick={resetError}>Retry</button>
)}
context={{ module: "checkout" }}
>
<App />
</ErrorBoundary>
)
If you already have an ErrorBoundary, React 19 root error callback, or manually caught errors, call addReactError(error, errorInfo, context). React Error events will include context.framework = react, and if a component stack exists, context.component_stack will also be included.
Vue¶
Installation¶
Vue 3 and Vue Router 4¶
import { createApp } from "vue"
import { createWebHistory } from "vue-router"
import { datafluxRum } from "@cloudcare/browser-rum"
import { vuePlugin } from "@cloudcare/browser-rum-vue"
import {
createRouter,
} from "@cloudcare/browser-rum-vue/vue-router-v4"
const app = createApp(App)
const router = createRouter({
history: createWebHistory(),
routes: [
{ path: "/", component: Home },
{ path: "/users/:id", component: UserDetail },
],
})
datafluxRum.init({
applicationId: "<APPLICATION_ID>",
site: "<PUBLIC_OPENWAY_URL>",
clientToken: "<CLIENT_TOKEN>",
service: "web-vue",
env: "production",
version: "1.0.0",
sessionSampleRate: 100,
plugins: [vuePlugin({ app, router: true })],
})
app.use(router)
app.mount("#app")
After passing in app, the plugin will install the Vue global error handler, while preserving any existing app.config.errorHandler in the application.
Vue 2.7 and Vue Router 3¶
import Vue from "vue"
import { datafluxRum } from "@cloudcare/browser-rum"
import { vuePlugin } from "@cloudcare/browser-rum-vue"
import VueRouter from "@cloudcare/browser-rum-vue/vue-router-v3"
Vue.use(VueRouter)
const router = new VueRouter({ routes })
datafluxRum.init({
applicationId: "<APPLICATION_ID>",
site: "<PUBLIC_OPENWAY_URL>",
clientToken: "<CLIENT_TOKEN>",
plugins: [vuePlugin({ app: Vue, router: true })],
})
new Vue({ router, render: (h) => h(App) }).$mount("#app")
If you already have a custom error handler, you can also call addVueError(error, componentInstance, info, context). Vue Error events will include context.framework = vue, and will record the component name and component path if possible.
Angular¶
Installation¶
Standalone Application¶
import { bootstrapApplication } from "@angular/platform-browser"
import { provideRouter } from "@angular/router"
import { datafluxRum } from "@cloudcare/browser-rum"
import { angularPlugin } from "@cloudcare/browser-rum-angular"
import {
provideRumErrorHandler,
provideRumRouter,
} from "@cloudcare/browser-rum-angular/providers"
datafluxRum.init({
applicationId: "<APPLICATION_ID>",
site: "<PUBLIC_OPENWAY_URL>",
clientToken: "<CLIENT_TOKEN>",
service: "web-angular",
env: "production",
version: "1.0.0",
sessionSampleRate: 100,
plugins: [angularPlugin({ router: true })],
})
bootstrapApplication(AppComponent, {
providers: [
provideRouter(routes),
provideRumRouter(),
provideRumErrorHandler(),
],
})
provideRumRouter() only starts a View after the Angular Router successfully triggers NavigationEnd. Canceled or failed navigations do not generate Views. provideRumErrorHandler() reports Errors while preserving Angular's default console error handling behavior.
If you already have a custom ErrorHandler, you can call addAngularError(error, context); if you already have a custom Router integration, you can call trackAngularRouter(router).
View Naming and Lifecycle¶
After enabling the framework Router integration, the plugin will take over manual Views:
| Scenario | Collection Behavior |
|---|---|
| First entry into a route | Creates an initial View |
| Pathname change with successful navigation | Creates a new View |
| Only query change | Does not create a new View |
| Only hash change | React, Angular do not create a new View; Nuxt can track hash routes |
| Dynamic routes | Uses template names like /users/:id, /users/[id], etc. |
| Navigation canceled, failed, or new page not committed | Does not create a View |
Do not use both the Router plugin and datafluxRum.startView() in business code to track the same route, otherwise duplicate Views may be generated.
The React, Vue, and Angular plugins all support the getViewName callback. Returning a custom string can override the default route template; returning undefined will skip creating a View for the current route.
Verifying Integration¶
- Open the browser developer tools, filter by
/v1/write/rumin the Network tab. - Navigate to a dynamic route, for example, from
/users/1to/users/2. - Confirm that the View name remains as the route template, not the specific user ID.
- Modify only the query parameters, confirm that no duplicate Views are created.
- Trigger a framework rendering error, confirm that an event with
type=errorappears, along with the correspondingcontext.framework.
Frequently Asked Questions¶
No View after enabling router: true¶
Ensure that the Router creation API, Routes, or useRoutes are imported from the plugin subpath matching the current Router major version. If you only register the plugin but continue using the original Router creation API, the plugin cannot obtain the full route state.
Multiple Views generated for a single route navigation¶
Ensure that the Router plugin is not registered multiple times, and that no extra call to datafluxRum.startView() is made for the same route change.
Dynamic routes generate a large number of View names¶
Prefer using Router template paths. If a stable name cannot be automatically obtained from the route configuration, use getViewName to map entity IDs to fixed business names.