First Contentful Paint (FCP) | Blue Frog Docs

First Contentful Paint (FCP)

Diagnose and fix slow First Contentful Paint to improve perceived loading speed and user engagement

First Contentful Paint (FCP)

What This Means

First Contentful Paint (FCP) measures the time from when a page starts loading to when any part of the page's content is rendered on screen. This includes text, images, SVGs, or non-white canvas elements. FCP provides critical feedback to users that the page is actually loading.

FCP Thresholds

  • Good: < 1.8 seconds (green)
  • Needs Improvement: 1.8 - 3.0 seconds (yellow)
  • Poor: > 3.0 seconds (red)

Impact on Your Business

User Experience:

  • Fast FCP reassures users the page is loading
  • Slow FCP creates perception of broken or unresponsive site
  • Critical for perceived performance and engagement

User Engagement:

  • Users are more likely to wait if they see content quickly
  • Slow FCP increases bounce rates significantly
  • Fast FCP improves time on site and page views

Mobile Performance:

  • Mobile users especially sensitive to FCP delays
  • Mobile connections make FCP optimization critical
  • Affects mobile search rankings

What FCP Measures

FCP captures the first moment when:

  • Text appears (even if web fonts haven't loaded)
  • Images render (even partially)
  • SVG elements display
  • Non-white canvas elements appear

FCP does NOT include:

  • White or transparent backgrounds
  • Iframes
  • Elements not yet rendered

How to Diagnose

  1. Navigate to PageSpeed Insights
  2. Enter your website URL
  3. Click "Analyze"
  4. Review FCP score in the metrics section
  5. Check "Diagnostics" for specific issues affecting FCP
  6. Review "Opportunities" for optimization suggestions

What to Look For:

Method 2: Chrome DevTools

  1. Open your website in Chrome
  2. Press F12 to open DevTools
  3. Navigate to "Performance" tab
  4. Click record button (circle icon)
  5. Refresh the page (Cmd+R or Ctrl+R)
  6. Stop recording after page loads
  7. Look for "FCP" marker in the timeline
  8. Click marker to see timing details

What to Look For:

  • Time from navigation start to FCP
  • Resources loaded before FCP
  • Scripts blocking rendering
  • Network waterfall before FCP

Method 3: Lighthouse

  1. Open Chrome DevTools (F12)
  2. Navigate to "Lighthouse" tab
  3. Select "Performance" category
  4. Click "Generate report"
  5. Review FCP in the metrics section
  6. Check opportunities and diagnostics

What to Look For:

  • FCP score and timing
  • Comparison with other metrics
  • Specific blocking resources
  • Optimization recommendations

Method 4: Web Vitals Extension

  1. Install Web Vitals Chrome Extension
  2. Visit your website
  3. Click extension icon
  4. View real-time FCP measurement

What to Look For:

  • FCP time in milliseconds
  • Whether score is Good/Needs Improvement/Poor
  • Real-time measurement during page load

Method 5: Real User Monitoring

  1. Enable FCP tracking in Google Analytics 4:

    // Web Vitals tracking
    import {onFCP} from 'web-vitals';
    
    onFCP(console.log);
    
  2. Check Google Search Console > Core Web Vitals

  3. Review field data for real user experience

  4. Identify problematic pages and devices

General Fixes

Fix 1: Reduce Server Response Time (TTFB)

FCP cannot happen before server responds:

  1. Use a CDN:

    • Serve content from edge locations
    • Reduces latency for global users
    • Recommended: Cloudflare, Fastly, AWS CloudFront
  2. Enable server-side caching:

    • Cache rendered HTML pages
    • Use Redis or Memcached
    • Configure cache headers properly
  3. Optimize backend performance:

    • Optimize database queries
    • Add database indexes
    • Reduce server processing time
  4. Upgrade hosting if needed:

    • Ensure adequate CPU and RAM
    • Consider dedicated or VPS hosting
    • Use hosting optimized for your platform

Fix 2: Eliminate Render-Blocking Resources

CSS and JavaScript can block first paint:

  1. Inline critical CSS:

    <head>
      <style>
        /* Critical above-fold CSS inlined here */
        .header { background: #fff; }
        .hero { font-size: 2rem; }
      </style>
    
      <!-- Defer non-critical CSS -->
      <link rel="preload" href="styles.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
      <noscript><link rel="stylesheet" href="styles.css"></noscript>
    </head>
    
  2. Defer non-critical JavaScript:

    <!-- Critical scripts -->
    <script src="critical.js"></script>
    
    <!-- Non-critical scripts -->
    <script src="analytics.js" defer></script>
    <script src="features.js" defer></script>
    
  3. Use async for third-party scripts:

    <script src="https://example.com/widget.js" async></script>
    
  4. Remove unused CSS and JavaScript:

    • Audit Coverage tab in Chrome DevTools
    • Remove or split unused code
    • Use tree-shaking for JavaScript

Fix 3: Optimize CSS Delivery

CSS blocks rendering until loaded:

  1. Minimize CSS file size:

    • Remove unused styles
    • Minify CSS files
    • Combine multiple CSS files
  2. Split CSS by media type:

    <!-- Only blocks on matching media -->
    <link rel="stylesheet" href="print.css" media="print">
    <link rel="stylesheet" href="mobile.css" media="(max-width: 640px)">
    
  3. Use CSS containment:

    .widget {
      contain: layout style paint;
    }
    
  4. Avoid @import in CSS:

    /* Bad - creates additional round trip */
    @import url('other.css');
    
    /* Good - parallel loading */
    /* Use multiple <link> tags instead */
    

Fix 4: Optimize Web Fonts

Font loading can delay FCP:

  1. Use font-display: swap:

    @font-face {
      font-family: 'CustomFont';
      src: url('font.woff2') format('woff2');
      font-display: swap; /* Show text immediately */
    }
    
  2. Preload critical fonts:

    <link
      rel="preload"
      href="/fonts/custom-font.woff2"
      as="font"
      type="font/woff2"
      crossorigin
    >
    
  3. Subset fonts:

    • Include only needed characters
    • Reduces font file size
    • Tools: Google Fonts subset parameter
  4. Consider system fonts:

    body {
      font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
    }
    

Fix 5: Optimize Resource Loading

Prioritize critical resources:

  1. Use resource hints:

    <!-- Preconnect to required origins -->
    <link rel="preconnect" href="https://fonts.googleapis.com">
    
    <!-- DNS prefetch for third-party domains -->
    <link rel="dns-prefetch" href="https://analytics.google.com">
    
    <!-- Preload critical resources -->
    <link rel="preload" href="hero.jpg" as="image">
    
  2. Set appropriate fetchpriority:

    <img src="hero.jpg" fetchpriority="high">
    <img src="footer.jpg" fetchpriority="low">
    
  3. Reduce number of resources:

    • Combine files where appropriate
    • Use CSS sprites for icons
    • Inline small SVGs

Fix 6: Minimize Main Thread Work

Reduce JavaScript execution before FCP:

  1. Defer non-essential scripts:

    <script src="analytics.js" defer></script>
    
  2. Code split large bundles:

    // Dynamic imports
    import('./feature.js').then(module => {
      module.init();
    });
    
  3. Reduce JavaScript execution time:

    • Profile with Chrome DevTools
    • Optimize or defer expensive operations
    • Remove unused dependencies
  4. Use Web Workers for heavy computation:

    const worker = new Worker('worker.js');
    worker.postMessage(data);
    

Fix 7: Optimize Server Configuration

Server configuration affects FCP:

  1. Enable compression:

    # Nginx configuration
    gzip on;
    gzip_types text/css application/javascript image/svg+xml;
    
    # Or use Brotli for better compression
    brotli on;
    brotli_types text/css application/javascript;
    
  2. Enable HTTP/2 or HTTP/3:

    • Allows parallel resource loading
    • Reduces connection overhead
    • Check server configuration
  3. Set appropriate cache headers:

    # Cache static assets
    location ~* \.(jpg|jpeg|png|gif|css|js)$ {
      expires 1y;
      add_header Cache-Control "public, immutable";
    }
    

Platform-Specific Guides

Detailed implementation instructions for your specific platform:

Platform Troubleshooting Guide
Shopify Shopify FCP Optimization
WordPress WordPress FCP Optimization
Wix Wix FCP Optimization
Squarespace Squarespace FCP Optimization
Webflow Webflow FCP Optimization

Verification

After implementing fixes:

  1. Test with Chrome DevTools:

    • Record performance profile
    • Verify FCP occurs earlier
    • Check that content appears quickly
  2. Run PageSpeed Insights:

    • Test multiple times (3-5 runs)
    • Verify FCP < 1.8 seconds
    • Confirm score is in "Good" range
  3. Test on real devices:

    • Mobile device on 4G connection
    • Slow 3G simulation
    • Different browsers
  4. Monitor continuously:

    • Track FCP over time
    • Set up alerts for regressions
    • Review real user data monthly

Common Mistakes

  1. Render-blocking CSS in <head> - Inline critical CSS instead
  2. Synchronous JavaScript in <head> - Use defer or async
  3. Large CSS files - Split and load progressively
  4. Unoptimized web fonts - Use font-display: swap
  5. Slow server response - Optimize TTFB first
  6. Too many resources - Reduce, combine, or defer
  7. No resource prioritization - Use preload/preconnect
  8. Ignoring mobile performance - Test on real mobile devices

FCP vs Other Metrics

FCP vs LCP

  • FCP: First content of any kind
  • LCP: Largest meaningful content
  • FCP usually happens before LCP
  • Both important for perceived performance

FCP vs TTFB

  • TTFB: Server response time
  • FCP: First visual feedback
  • FCP cannot happen before TTFB completes
  • Optimize TTFB to improve FCP

FCP vs Speed Index

  • FCP: Single moment (first paint)
  • Speed Index: Average time content becomes visible
  • FCP is component of Speed Index
  • Both measure perceived loading speed

Additional Resources

// SYS.FOOTER