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
Method 1: PageSpeed Insights (Recommended)
- Navigate to PageSpeed Insights
- Enter your website URL
- Click "Analyze"
- Review FCP score in the metrics section
- Check "Diagnostics" for specific issues affecting FCP
- Review "Opportunities" for optimization suggestions
What to Look For:
- FCP time in seconds
- How FCP compares to other metrics (TTFB, LCP)
- Render-blocking resources
- Server response time issues
Method 2: Chrome DevTools
- Open your website in Chrome
- Press
F12to open DevTools - Navigate to "Performance" tab
- Click record button (circle icon)
- Refresh the page (
Cmd+RorCtrl+R) - Stop recording after page loads
- Look for "FCP" marker in the timeline
- 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
- Open Chrome DevTools (
F12) - Navigate to "Lighthouse" tab
- Select "Performance" category
- Click "Generate report"
- Review FCP in the metrics section
- 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
- Install Web Vitals Chrome Extension
- Visit your website
- Click extension icon
- 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
Enable FCP tracking in Google Analytics 4:
// Web Vitals tracking import {onFCP} from 'web-vitals'; onFCP(console.log);Check Google Search Console > Core Web Vitals
Review field data for real user experience
Identify problematic pages and devices
General Fixes
Fix 1: Reduce Server Response Time (TTFB)
FCP cannot happen before server responds:
Use a CDN:
Enable server-side caching:
Optimize backend performance:
- Optimize database queries
- Add database indexes
- Reduce server processing time
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:
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>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>Use async for third-party scripts:
<script src="https://example.com/widget.js" async></script>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:
Minimize CSS file size:
- Remove unused styles
- Minify CSS files
- Combine multiple CSS files
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)">Use CSS containment:
.widget { contain: layout style paint; }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:
Use font-display: swap:
@font-face { font-family: 'CustomFont'; src: url('font.woff2') format('woff2'); font-display: swap; /* Show text immediately */ }Preload critical fonts:
<link rel="preload" href="/fonts/custom-font.woff2" as="font" type="font/woff2" crossorigin >Subset fonts:
- Include only needed characters
- Reduces font file size
- Tools: Google Fonts subset parameter
Consider system fonts:
body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; }
Fix 5: Optimize Resource Loading
Prioritize critical resources:
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">Set appropriate fetchpriority:
<img src="hero.jpg" fetchpriority="high"> <img src="footer.jpg" fetchpriority="low">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:
Defer non-essential scripts:
<script src="analytics.js" defer></script>Code split large bundles:
// Dynamic imports import('./feature.js').then(module => { module.init(); });Reduce JavaScript execution time:
- Profile with Chrome DevTools
- Optimize or defer expensive operations
- Remove unused dependencies
Use Web Workers for heavy computation:
const worker = new Worker('worker.js'); worker.postMessage(data);
Fix 7: Optimize Server Configuration
Server configuration affects FCP:
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;Enable HTTP/2 or HTTP/3:
- Allows parallel resource loading
- Reduces connection overhead
- Check server configuration
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:
Test with Chrome DevTools:
- Record performance profile
- Verify FCP occurs earlier
- Check that content appears quickly
Run PageSpeed Insights:
- Test multiple times (3-5 runs)
- Verify FCP < 1.8 seconds
- Confirm score is in "Good" range
Test on real devices:
- Mobile device on 4G connection
- Slow 3G simulation
- Different browsers
Monitor continuously:
- Track FCP over time
- Set up alerts for regressions
- Review real user data monthly
Common Mistakes
- Render-blocking CSS in
<head>- Inline critical CSS instead - Synchronous JavaScript in
<head>- Use defer or async - Large CSS files - Split and load progressively
- Unoptimized web fonts - Use font-display: swap
- Slow server response - Optimize TTFB first
- Too many resources - Reduce, combine, or defer
- No resource prioritization - Use preload/preconnect
- 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