Skip to main content
This guide shows how to measure basic browser performance metrics including Core Web Vitals. Perfect for monitoring page loading speed and user experience.

Use Cases

  • Measure Core Web Vitals (LCP, FCP, CLS)
  • Test page loading performance
  • Monitor resource loading times
  • Check performance across different pages

Simple Implementation

from locust import task, HttpUser
from locust_plugins.users.playwright import PlaywrightUser, pw
import time

class PerformanceUser(PlaywrightUser):
    def on_start(self):
        # Pages to test performance
        self.test_pages = [
            "/",
            "/products",
            "/about",
            "/blog",
            "/contact"
        ]

    @task(3)
    @pw
    def measure_core_web_vitals(self, page):
        """Measure Core Web Vitals for a page"""
        test_url = self.random_page()
        
        # Start timing
        start_time = time.time()
        
        # Navigate to page
        page.goto(test_url)
        
        # Wait for page to fully load
        page.wait_for_load_state("networkidle")
        
        # Measure First Contentful Paint (FCP)
        fcp = page.evaluate("""
            () => {
                const entries = performance.getEntriesByType('paint');
                const fcpEntry = entries.find(entry => entry.name === 'first-contentful-paint');
                return fcpEntry ? fcpEntry.startTime : null;
            }
        """)
        
        # Measure Largest Contentful Paint (LCP)
        lcp = page.evaluate("""
            () => {
                return new Promise((resolve) => {
                    const observer = new PerformanceObserver((list) => {
                        const entries = list.getEntries();
                        const lastEntry = entries[entries.length - 1];
                        resolve(lastEntry.startTime);
                    });
                    observer.observe({entryTypes: ['largest-contentful-paint']});
                    
                    // Fallback timeout
                    setTimeout(() => resolve(null), 3000);
                });
            }
        """)
        
        # Measure Cumulative Layout Shift (CLS)
        cls = page.evaluate("""
            () => {
                let clsValue = 0;
                const observer = new PerformanceObserver((list) => {
                    for (const entry of list.getEntries()) {
                        if (!entry.hadRecentInput) {
                            clsValue += entry.value;
                        }
                    }
                });
                observer.observe({entryTypes: ['layout-shift']});
                
                return new Promise((resolve) => {
                    setTimeout(() => resolve(clsValue), 2000);
                });
            }
        """)
        
        # Calculate total load time
        load_time = (time.time() - start_time) * 1000
        
        # Log results
        print(f"Performance for {test_url}:")
        print(f"  Load Time: {load_time:.0f}ms")
        if fcp:
            print(f"  FCP: {fcp:.0f}ms")
        if lcp:
            print(f"  LCP: {lcp:.0f}ms")
        if cls:
            print(f"  CLS: {cls:.3f}")

    @task(2)
    @pw
    def measure_resource_loading(self, page):
        """Measure resource loading performance"""
        test_url = self.random_page()
        
        # Track network requests
        requests = []
        
        def handle_request(request):
            requests.append({
                'url': request.url,
                'method': request.method,
                'start_time': time.time()
            })
        
        def handle_response(response):
            # Find matching request
            for req in requests:
                if req['url'] == response.url:
                    req['response_time'] = time.time() - req['start_time']
                    req['status'] = response.status
                    req['size'] = len(response.body()) if response.body() else 0
                    break
        
        page.on('request', handle_request)
        page.on('response', handle_response)
        
        # Navigate and measure
        page.goto(test_url)
        page.wait_for_load_state("networkidle")
        
        # Analyze resource performance
        total_size = sum(req.get('size', 0) for req in requests)
        slow_resources = [req for req in requests if req.get('response_time', 0) > 2.0]
        
        print(f"Resource loading for {test_url}:")
        print(f"  Total requests: {len(requests)}")
        print(f"  Total size: {total_size / 1024:.1f}KB")
        print(f"  Slow resources (>2s): {len(slow_resources)}")

    @task(2)
    @pw
    def test_page_speed(self, page):
        """Test basic page loading speed"""
        test_url = self.random_page()
        
        # Measure different loading stages
        start_time = time.time()
        
        # Navigate to page
        page.goto(test_url)
        
        # Measure time to DOM content loaded
        dom_time = time.time()
        
        # Wait for all resources
        page.wait_for_load_state("networkidle")
        
        # Measure total load time
        total_time = time.time()
        
        # Calculate metrics
        dom_load_time = (dom_time - start_time) * 1000
        total_load_time = (total_time - start_time) * 1000
        
        # Get page size
        page_size = page.evaluate("document.documentElement.outerHTML.length")
        
        print(f"Page speed for {test_url}:")
        print(f"  DOM Load: {dom_load_time:.0f}ms")
        print(f"  Total Load: {total_load_time:.0f}ms")
        print(f"  Page Size: {page_size / 1024:.1f}KB")
        
        # Performance thresholds
        if total_load_time > 3000:
            print(f"  WARNING: Slow loading page ({total_load_time:.0f}ms)")

    @task(1)
    @pw
    def test_mobile_performance(self, page):
        """Test performance on mobile viewport"""
        test_url = self.random_page()
        
        # Set mobile viewport
        page.set_viewport_size(width=375, height=667)
        
        # Simulate slower mobile connection
        page.route("**/*", lambda route: (
            time.sleep(0.1),  # Add 100ms delay
            route.continue_()
        ))
        
        start_time = time.time()
        
        # Navigate and measure
        page.goto(test_url)
        page.wait_for_load_state("networkidle")
        
        load_time = (time.time() - start_time) * 1000
        
        print(f"Mobile performance for {test_url}:")
        print(f"  Mobile Load Time: {load_time:.0f}ms")
        
        # Mobile performance is typically slower
        if load_time > 5000:
            print(f"  WARNING: Very slow on mobile ({load_time:.0f}ms)")

    def random_page(self):
        """Get a random test page"""
        import random
        return random.choice(self.test_pages)

Setup Instructions

  1. Ensure Playwright is configured in LoadForge
  2. Test with realistic network conditions
  3. Focus on user-facing performance metrics
  4. Set performance budgets for your site

What This Tests

  • Core Web Vitals: LCP, FCP, and CLS measurements
  • Loading Speed: DOM and total page load times
  • Resource Performance: Network request timing and sizes
  • Mobile Performance: Performance on mobile devices

Performance Metrics

  • FCP (First Contentful Paint): When first content appears (< 1.8s good)
  • LCP (Largest Contentful Paint): When main content loads (< 2.5s good)
  • CLS (Cumulative Layout Shift): Visual stability (< 0.1 good)
  • Total Load Time: Complete page loading (< 3s good)

Performance Tips

  • Optimize Images: Compress and use modern formats
  • Minimize JavaScript: Reduce bundle sizes
  • Use CDN: Serve static assets from edge locations
  • Enable Caching: Set proper cache headers

Common Performance Issues

  • Large Images: Unoptimized images slow loading
  • Too Much JavaScript: Heavy JS bundles block rendering
  • Slow Server: Backend response times affect performance
  • Layout Shifts: Content moving during load hurts CLS
I