vunet_flutter_plugin_go_router

go_router navigation instrumentation for vuTelemetry Flutter.

App developers import this package instead of registering the core's RouteObserverService. The extension points it builds on live on package:vunet_flutter_plugin/nav_instrumentation.dart (for official integrations and advanced custom observers). Day-to-day RUM APIs remain on package:vunet_flutter_plugin/flutter_sdk.dart.

Setup

  1. Initialize the core SDK with VuTelemetry.initialize.
  2. Add this package alongside vunet_flutter_plugin and go_router.
  3. Register an observer on every Navigator go_router builds:
import 'package:go_router/go_router.dart';
import 'package:vunet_flutter_plugin_go_router/vunet_flutter_plugin_go_router.dart';

final router = GoRouter(
  observers: [VuGoRouterObserver()],
  routes: [
    GoRoute(path: '/', name: 'home', builder: ...),
    GoRoute(path: '/users/:id', name: 'user', builder: ...),
    ShellRoute(
      observers: [VuGoRouterObserver()],
      builder: (context, state, child) => AppScaffold(child: child),
      routes: [...],
    ),
  ],
);

Do not also register RouteObserverService — every transition would be reported twice. A NavigatorObserver may watch exactly one Navigator, so each ShellRoute and StatefulShellBranch needs its own VuGoRouterObserver() instance — the constructor returns a fresh instance on every call, so the same call works for the root router and every nested shell/branch.

What you get

On top of the core's navigation attributes:

Attribute Example Use
navigation.destination.route / navigation.source.route /users/:id low-cardinality grouping key
navigation.destination.uri / navigation.source.uri /users/42 the concrete visit, query stripped

navigation.transition.type gains go for lateral location changes, and navigation.entry.type gains deep_link for arrivals from outside the app — a universal/app link, a custom scheme, or a cold start into a non-/ location.

Screen names come from routes

go_router invokes your builder behind a Builder it inserts so the page can rebuild against fresh route state, so the widget class is not recoverable. screen.name is GoRoute.name when declared, otherwise the matched path pattern. Override it per app:

VuGoRouterObserver(
  screenNameBuilder: (identity) => switch (identity.routePattern) {
    '/users/:id' => 'User profile',
    _ => null, // null accepts the default
  },
)

The builder also sees routes the router knows nothing about — a dialog, an imperative Navigator.push onto go_router's navigator — so a naming scheme has no gaps in it. Those have no match to look up, so routePattern and uriPath are null and returning null falls back to the widget class.

StatefulShellRoute

Switching branches pushes and pops nothing — the shell swaps which Navigator is visible — so no route observer can see it. Wrap what the builder returns:

StatefulShellRoute.indexedStack(
  builder: (context, state, navigationShell) => VuStatefulShellScope(
    navigationShell: navigationShell,
    branchNames: const ['Feed', 'Search', 'Profile'],
    child: AppScaffold(navigationShell: navigationShell),
  ),
  branches: [...],
)

Each switch emits a ui.navigation span with navigation.transition.type: tab_switch plus navigation.tab.group, navigation.tab.name and navigation.tab.index. branchNames defaults to each branch's initialLocation.

Caveats

  • GoRouter.replace emits no span. It reuses the page key of the match it replaces — that is how it skips the transition animation — so Flutter updates the existing route in place and announces nothing to any observer. The following transition is still classified from the Navigator as usual (pop stays pop). Use pushReplacement, which is reported as replace.
  • notifyRootObserver needs no configuration. go_router forwards a nested navigator's callbacks to the root observer too; the core observer ignores callbacks for routes belonging to a different Navigator.
  • An observer attached to a plain Navigator (no GoRouter above it) logs a warning once and falls back to widget-class screen names.

License

VuNet Systems Ltd. proprietary and confidential (LicenseRef-VuNet-Proprietary). See LICENSE.

Libraries

vunet_flutter_plugin_go_router
go_router instrumentation for the vuTelemetry Flutter RUM SDK.