Agent skill
route-transition-tracking
Measure time from navigation to page fully loaded and interactive. Use when tracking SPA navigation, route changes, or slow page transitions.
Install this agent skill to your Project
npx add-skill https://github.com/majiayu000/claude-skill-registry/tree/main/skills/development/route-transition-tracking-nexus-labs-automatio-web-observability
SKILL.md
Route Transition Tracking
Time from navigation start to destination page interactive.
Phases
CLICK/NAV → ROUTE_CHANGE → DATA_FETCH → RENDER → INTERACTIVE
|_______________________________________________|
Route Transition Time
When to Use
- Tab/menu navigation
- Link clicks within SPA
- Programmatic navigation
- Back/forward browser buttons
- Deep links
Key Thresholds
| Rating | Duration |
|---|---|
| Good | <400ms |
| Acceptable | <1s |
| Poor | >1s |
React Router
import { useLocation, useNavigationType } from 'react-router-dom';
import { useEffect, useRef } from 'react';
function RouteTracker() {
const location = useLocation();
const navigationType = useNavigationType();
const navigationStart = useRef<number>();
useEffect(() => {
navigationStart.current = performance.now();
}, [location.pathname]);
useEffect(() => {
// Called after render completes
if (navigationStart.current) {
const duration = performance.now() - navigationStart.current;
trackRouteTransition({
from: document.referrer,
to: location.pathname,
duration_ms: duration,
navigation_type: navigationType, // 'PUSH', 'POP', 'REPLACE'
});
}
});
return null;
}
Next.js App Router
// app/providers.tsx
'use client';
import { usePathname, useSearchParams } from 'next/navigation';
import { useEffect, useRef } from 'react';
export function RouteChangeTracker() {
const pathname = usePathname();
const searchParams = useSearchParams();
const startTime = useRef<number>();
const previousPath = useRef<string>();
useEffect(() => {
startTime.current = performance.now();
}, [pathname, searchParams]);
useEffect(() => {
if (startTime.current && previousPath.current) {
const duration = performance.now() - startTime.current;
trackRouteTransition({
from: previousPath.current,
to: pathname,
duration_ms: duration,
has_search_params: searchParams.toString().length > 0,
});
}
previousPath.current = pathname;
});
return null;
}
Vue Router
// plugins/route-tracking.ts
import { watch } from 'vue';
import { useRouter, useRoute } from 'vue-router';
export function useRouteTracking() {
const router = useRouter();
const route = useRoute();
let navigationStart: number;
router.beforeEach((to, from) => {
navigationStart = performance.now();
});
router.afterEach((to, from) => {
// Wait for next tick to ensure render complete
nextTick(() => {
const duration = performance.now() - navigationStart;
trackRouteTransition({
from: from.path,
to: to.path,
duration_ms: duration,
route_name: to.name as string,
});
});
});
}
SvelteKit
// src/routes/+layout.svelte
<script lang="ts">
import { page, navigating } from '$app/stores';
import { onMount } from 'svelte';
let navigationStart: number;
$: if ($navigating) {
navigationStart = performance.now();
}
$: if (!$navigating && navigationStart) {
const duration = performance.now() - navigationStart;
trackRouteTransition({
to: $page.url.pathname,
duration_ms: duration,
route_id: $page.route.id,
});
}
</script>
Nuxt
// plugins/route-tracking.client.ts
export default defineNuxtPlugin((nuxtApp) => {
let navigationStart: number;
nuxtApp.hook('page:start', () => {
navigationStart = performance.now();
});
nuxtApp.hook('page:finish', () => {
const route = useRoute();
const duration = performance.now() - navigationStart;
trackRouteTransition({
to: route.path,
duration_ms: duration,
route_name: route.name as string,
});
});
});
With Data Loading
Track data fetching as part of transition:
function ProductPage() {
const { data, isLoading } = useQuery(['product', id], fetchProduct);
const renderStart = useRef(performance.now());
useEffect(() => {
if (!isLoading && data) {
trackRouteTransition({
route: `/products/${id}`,
total_duration_ms: performance.now() - renderStart.current,
data_fetch_complete: true,
});
}
}, [isLoading, data]);
// ...
}
Common Mistakes
- Measuring only route change (missing data load)
- Not distinguishing warm vs cold loads
- Ignoring prefetched routes (artificially fast)
- Missing back/forward navigation
- Not tracking by route pattern (aggregate hides issues)
Related Skills
- See
skills/core-web-vitalsfor LCP during navigation - See
skills/hydration-performancefor SSR page loads - See
skills/api-tracingfor data fetch timing - See
skills/user-journey-trackingfor correlating with user intent
References
references/ui-performance.md- Navigation performance patternsreferences/frameworks/*.md- Framework-specific routing
Recommended Agent Skills
Expand your agent's capabilities with these related and highly-rated skills.
agent-ops-spec
Manage specification documents in .agent/specs/. Use when user provides requirements, acceptance criteria, or feature descriptions that need to be tracked and validated against implementation.
agent-ops-state
Maintain .agent state files. Use at session start, after meaningful steps, and before concluding: read/update constitution/memory/focus/issues/baseline consistently.
agent-ops-spec
Manage specification documents in .agent/specs/. Use when user provides requirements, acceptance criteria, or feature descriptions that need to be tracked and validated against implementation.
agent-ops-testing
Test strategy, execution, and coverage analysis. Use when designing tests, running test suites, or analyzing test results beyond baseline checks.
agent-ops-testing
Test strategy, execution, and coverage analysis. Use when designing tests, running test suites, or analyzing test results beyond baseline checks.
agent-ops-state
Maintain .agent state files. Use at session start, after meaningful steps, and before concluding: read/update constitution/memory/focus/issues/baseline consistently.
Didn't find tool you were looking for?