supaguardsupaguardDocs
Use cases

Monitoring Modern SPAs (React, Vue, Next.js)

Synthetic monitoring for single-page applications (SPAs) requires a different approach. Learn how to handle client-side routing, hydrations, and state transitions with Playwright.

Monitoring a traditional server-rendered site is simple: check if the HTML contains a string. Monitoring a Modern Single-Page Application (SPA) built with React, Vue, or Next.js is significantly more complex. In an SPA, a 200 OK from the server doesn't mean your app is working—it just means the shell loaded.

This guide covers the specialized techniques required for robust SPA monitoring.

The SPA "Liveness" Problem

In an SPA, the critical failure points are often client-side:

  • JavaScript Runtime Errors: The app crashes before it can render.
  • Hydration Mismatches: React fails to attach to the server-rendered DOM.
  • Client-Side Routing Flakes: The URL changes but the view doesn't update.
  • API Race Conditions: The UI renders before the data is ready.

Techniques for Reliable SPA Monitoring

1. Wait for Critical UI States

Don't just check for a URL. Check for a "Final State" element that confirms the application is interactive.

// ❌ Weak: URL changed, but page might still be "Loading..."
await page.goto('/dashboard');
await expect(page).toHaveURL(/.*dashboard/);

// ✅ Strong: Wait for data-driven element
await expect(page.getByTestId('revenue-chart')).toBeVisible({ timeout: 15000 });

2. Monitoring Client-Side Navigation

Test your app's internal router (e.g., react-router or next/navigation) by clicking internal links rather than navigating directly to every URL.

await page.goto('/');
await page.getByRole('link', { name: 'Settings' }).click();
await expect(page.getByRole('heading', { name: 'Account Settings' })).toBeVisible();

3. Handling API Hydration

Many SPAs show "Skeleton Loaders" while fetching data. Ensure your check waits for the real data to replace the skeleton.

// Wait until the 'Loading' text or skeleton is hidden
await expect(page.getByText('Loading projects...')).toBeHidden();
await expect(page.getByRole('listitem')).toHaveCount(5);

4. Capturing Console Errors

supaguard automatically captures console logs, but you can also assert against them in your Playwright script to catch "Silent Failures."

page.on('console', msg => {
  if (msg.type() === 'error') {
    throw new Error(`Browser Error: ${msg.text()}`);
  }
});

SPA Framework Best Practices

Next.js

If using Next.js, monitor your Server Components vs Client Components.

  • Use waitUntil: 'networkidle' to ensure all chunks have loaded.
  • Monitor your /api/trpc or /api/graphql endpoints alongside the UI.

React

  • Use data-testid for elements that are deeply nested in the component tree.
  • Ensure your monitors cover "Error Boundary" states.

Why supaguard is Built for SPAs

Traditional monitoring tools often timeout or provide "Static Snapshots" that don't reflect an SPA's dynamic nature.

  • Video-First Debugging: Watch the actual state transitions to see if a component "flickered" or failed to hydrate.
  • HAR Inspection: Inspect the exact JSON payloads that were returned to the client to debug data-driven UI bugs.
  • Reviewer AI: Our AI understands that a "Spinner" is a temporary state and will wait for the final render before classifying a result.

Master SPA Monitoring

On this page