Simple Performance Testing

Basic browser performance testing with Core Web Vitals and loading metrics using Playwright

LoadForge can record your browser, graphically build tests, scan your site with a wizard and more. Sign up now to run your first test.

Sign up now


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

Ready to run your test?
Start your first test within minutes.