Back to list
nexus-labs-automation

synthetic-monitoring

by nexus-labs-automation

Claude Code plugin for web observability - Core Web Vitals, error tracking, session replay for React, Vue, Svelte, and more

0🍴 0📅 Dec 26, 2025

SKILL.md


name: synthetic-monitoring description: Set up synthetic monitoring with Lighthouse CI and Playwright. Use when implementing automated performance testing, CI/CD performance gates, or proactive monitoring. triggers:

  • "synthetic monitoring"
  • "Lighthouse CI"
  • "Playwright testing"
  • "performance testing"
  • "lab data"
  • "CI performance" priority: 2

Synthetic Monitoring

Automated testing for consistent, proactive performance monitoring.

RUM vs Synthetic

AspectRUM (Real User)Synthetic (Lab)
Data sourceActual usersControlled tests
VariabilityHighLow
CoverageWhat users doWhat you test
IssuesFinds unknownValidates known
TimingReactiveProactive

Use both: Synthetic catches regressions before users; RUM shows real-world impact.

Lighthouse CI

Setup

npm install -D @lhci/cli
// lighthouserc.json
{
  "ci": {
    "collect": {
      "url": [
        "http://localhost:3000/",
        "http://localhost:3000/products",
        "http://localhost:3000/checkout"
      ],
      "numberOfRuns": 3
    },
    "assert": {
      "preset": "lighthouse:recommended",
      "assertions": {
        "categories:performance": ["error", { "minScore": 0.9 }],
        "categories:accessibility": ["error", { "minScore": 0.9 }],
        "first-contentful-paint": ["error", { "maxNumericValue": 2000 }],
        "largest-contentful-paint": ["error", { "maxNumericValue": 2500 }],
        "interactive": ["error", { "maxNumericValue": 3500 }],
        "cumulative-layout-shift": ["error", { "maxNumericValue": 0.1 }]
      }
    },
    "upload": {
      "target": "temporary-public-storage"
    }
  }
}

GitHub Actions

# .github/workflows/lighthouse.yml
name: Lighthouse CI

on: [push]

jobs:
  lighthouse:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Setup Node
        uses: actions/setup-node@v4
        with:
          node-version: '20'

      - name: Install & Build
        run: |
          npm ci
          npm run build

      - name: Start server
        run: npm run start &

      - name: Run Lighthouse
        run: |
          npm install -g @lhci/cli
          lhci autorun
        env:
          LHCI_GITHUB_APP_TOKEN: ${{ secrets.LHCI_GITHUB_APP_TOKEN }}

Playwright Performance Testing

Setup

npm install -D @playwright/test
// tests/performance.spec.ts
import { test, expect } from '@playwright/test';

test.describe('Performance Tests', () => {
  test('homepage loads within budget', async ({ page }) => {
    // Start tracing
    await page.context().tracing.start({ screenshots: true, snapshots: true });

    const startTime = Date.now();
    await page.goto('/');
    await page.waitForLoadState('networkidle');
    const loadTime = Date.now() - startTime;

    // Assert load time
    expect(loadTime).toBeLessThan(3000);

    // Get Core Web Vitals
    const vitals = await page.evaluate(() => {
      return new Promise((resolve) => {
        new PerformanceObserver((list) => {
          const entries = list.getEntries();
          const lcp = entries.find((e) => e.entryType === 'largest-contentful-paint');
          resolve({
            lcp: lcp?.startTime,
            cls: entries
              .filter((e) => e.entryType === 'layout-shift')
              .reduce((sum: number, e: any) => sum + e.value, 0),
          });
        }).observe({ type: 'largest-contentful-paint', buffered: true });

        // Fallback timeout
        setTimeout(() => resolve({ lcp: null, cls: null }), 5000);
      });
    });

    console.log('Vitals:', vitals);

    // Stop tracing
    await page.context().tracing.stop({ path: 'trace.zip' });
  });

  test('checkout flow performance', async ({ page }) => {
    const metrics: Record<string, number> = {};

    // Navigate through checkout
    await page.goto('/products/1');
    metrics.productPageLoad = await measurePageLoad(page);

    await page.click('[data-testid="add-to-cart"]');
    await page.goto('/cart');
    metrics.cartPageLoad = await measurePageLoad(page);

    await page.click('[data-testid="checkout"]');
    metrics.checkoutPageLoad = await measurePageLoad(page);

    // Assert all pages load within budget
    expect(metrics.productPageLoad).toBeLessThan(2000);
    expect(metrics.cartPageLoad).toBeLessThan(1500);
    expect(metrics.checkoutPageLoad).toBeLessThan(2000);
  });
});

async function measurePageLoad(page: any): Promise<number> {
  const timing = await page.evaluate(() => {
    const nav = performance.getEntriesByType('navigation')[0] as PerformanceNavigationTiming;
    return nav.loadEventEnd - nav.fetchStart;
  });
  return timing;
}

Performance Trace Collection

// playwright.config.ts
import { defineConfig } from '@playwright/test';

export default defineConfig({
  use: {
    trace: 'retain-on-failure',
    video: 'retain-on-failure',
  },
  projects: [
    {
      name: 'Desktop Chrome',
      use: {
        browserName: 'chromium',
        viewport: { width: 1280, height: 720 },
      },
    },
    {
      name: 'Mobile Chrome',
      use: {
        browserName: 'chromium',
        ...devices['Pixel 5'],
      },
    },
    {
      name: 'Slow 3G',
      use: {
        browserName: 'chromium',
        // Simulate slow network
        launchOptions: {
          args: ['--force-effective-connection-type=3g'],
        },
      },
    },
  ],
});

Scheduled Monitoring

Checkly (or similar)

// __checks__/homepage.check.ts
import { check, group } from 'checkly';
import { Playwright } from 'checkly/constructs';

const homepage = new Playwright('homepage-check', {
  name: 'Homepage Performance',
  frequency: 5, // Every 5 minutes
  locations: ['us-east-1', 'eu-west-1'],
  runtimeId: '2024.02',
  script: `
    const { expect } = require('@playwright/test');

    async function run({ page }) {
      const response = await page.goto('https://yoursite.com');

      expect(response.status()).toBe(200);

      const timing = await page.evaluate(() => {
        const nav = performance.getEntriesByType('navigation')[0];
        return nav.loadEventEnd - nav.fetchStart;
      });

      expect(timing).toBeLessThan(3000);
    }

    module.exports = { run };
  `,
  alertChannels: ['email-oncall'],
});

Metrics to Track

MetricThresholdPriority
LCP<2.5sP0
TTI<3.5sP0
Total Blocking Time<200msP0
CLS<0.1P0
Speed Index<3.4sP1
Time to First Byte<600msP1

CI/CD Integration Pattern

# Performance gate in CI
performance:
  runs-on: ubuntu-latest
  steps:
    - name: Run Lighthouse
      run: lhci autorun

    - name: Run Playwright
      run: npx playwright test tests/performance/

    - name: Upload results
      run: |
        # Send to your observability platform
        curl -X POST \
          -H "Authorization: Bearer $TOKEN" \
          -d @lighthouse-results.json \
          https://api.yourplatform.com/synthetic-results

Anti-Patterns

  • Only running in CI (miss production issues)
  • Testing only happy path
  • Ignoring mobile/slow network
  • No alerting on failures
  • Not tracking trends over time
  • Missing real user comparison
  • See skills/core-web-vitals for RUM comparison
  • See skills/bundle-performance for what to optimize
  • See skills/route-transition-tracking for SPA performance

References

  • references/performance.md - Performance budgets
  • references/platforms/*.md - Vendor integrations

Score

Total Score

70/100

Based on repository quality metrics

SKILL.md

SKILL.mdファイルが含まれている

+20
LICENSE

ライセンスが設定されている

+10
説明文

100文字以上の説明がある

+10
人気

GitHub Stars 100以上

0/15
最近の活動

3ヶ月以内に更新がある

0/10
フォーク

10回以上フォークされている

0/5
Issue管理

オープンIssueが50未満

+5
言語

プログラミング言語が設定されている

+5
タグ

1つ以上のタグが設定されている

0/5

Reviews

💬

Reviews coming soon