This is a simple (yet in-depth) guide on improving first contentful paint in WordPress.
First contentful paint (FCP) is the point when users see anything on your site (very similar to LCP where users see your largest image or text block in the viewport). Anything before that (including TTFB, DNS lookups, as well as the first content shown) is part of both FCP and LCP.
The Waterfall chart in WebPageTest shows which files load in your FCP time (test your site then click the Waterfall image). In the example below, all files loading in green are part of FCP.
The first request is usually the longest and includes factors like TTFB, DNS, and SSL. The other requests are related to whatever files load first which can be CSS, JavaScript, fonts, and images.
Pay special attention to files loading in the viewport: preloading images/fonts, avoiding bloated headers created by page builders (by hard coding them in CSS), and pushing plugins + third-party code below the fold can help. Aside from reducing the size of files loading in your viewport, using a performant setup (hosting, theme, plugins, CDN) are two big FCP/LCP factors.
First Contentful Paint | Score |
---|---|
0–1.8s | Good |
1.8–3s | Needs Improvement |
Over 3s | Poor |
- Aim for a <100ms TTFB
- Reduce CSS + JavaScript files
- Use local fonts, preload them, and use “swap”
- Preload viewport images and exclude from lazy load
- Avoid page builders for headers
- Defer JavaScript
- Use full page caching
- Avoid loading plugins/scripts in the viewport
- Use a performant DNS/CDN
- Use multiple caching layers
- Generate critical CSS and inline it
- Delay JavaScript
- Fix errors in your Waterfall chart
- Set a longer cache expiration
- Test Cloudflare’s Rocket Loader
1. Aim For A <100ms TTFB
TTFB is 40% of LCP, which means it’s also a big part of FCP. The 2 biggest TTFB factors are:
- Hosting
- CDN, ideally with a large network (PoPs) and full page caching
I always recommend Rocket.net with their Cloudflare Enterprise who averages a TTFB of <100ms globally which you can test in KeyCDN (or click through my site since I’m using them).
Here are the specs if you want to do your research:
SiteGround | Kinsta | WPX | Cloudways Vultr High Frequency | Rocket.net | |
---|---|---|---|---|---|
Hosting type | Shared | Cloud | Shared | Cloud | Private cloud |
CPU cores + RAM | Not listed | 12 cores + 8GB | Not listed | 1 core + 1GB | 32 cores + 128GB |
Storage | SATA | SATA | SATA | NVMe | NVMe |
Storage (GB) | 40 | 10 | 15 | 32 | 10 |
Object cache | Memcached | Redis ($100/mo) | x | Redis (Pro) | Redis (Pro) |
Server | Apache + Nginx | Nginx | LiteSpeed | Apache | Apache + Nginx |
PHP processing | FastCGI | FastCGI | FastCGI | PHP-FPM | LiteSpeed |
Bandwidth (or monthly visits) | 5TB | 25k visits/mo | 200GB | 1TB | 50GB + 250k visits/mo |
CDN | SiteGround CDN | Cloudflare Enterprise | QUIC.cloud or XDN | Cloudflare Enterprise | Cloudflare Enterprise |
CDN PoPs | 14 | 270 | 73 | 270 | 270 |
Full page caching | ✓ | ✓ | ✓ | Coming soon | ✓ |
HTTP/3 | ✓ | ✓ | ✓ | ✓ | ✓ |
WAF | ✓ | ✓ | ✓ | ✓ | ✓ |
Argo smart routing | x | x | x | ✓ | ✓ |
Load balancing | x | x | x | ✓ | ✓ |
Image optimization | Limited | x | ✓ | ✓ | ✓ |
Compression | Brotli | Brotli | Brotli | GZIP | Brotli |
CDN price | Freemium | Free | $.01 – $.04/GB | $5/mo | Free |
CPU limits | Common | Low PHP workers | At their discretion | Average | None |
Cache plugin | SG Optimizer | x | LSC or W3TC | Breeze | x |
Email hosting | ✓ | x | Very limited | x | x |
Major incidents | Google blocked DNS for 4 days | None | Worldwide outage | None | None |
Free migration | $30/site | Unlimited free | 5-35 sites free | 1 free | Unlimited free |
Renewals | Yearly (high) | Monthly | Monthly | Monthly | Monthly |
TrustPilot rating | 4.6/5 | 4.4/5 | 4.9/5 | 4.6/5 | 4.9/5 |
Price | $3-8/mo (1 year) then $15-40/mo | $29/mo (yearly) | $20.83 (yearly) | $18/mo (with CF Enterprise) | $25/mo (yearly) |
I’ve written plenty of bad reviews on SiteGround, Hostinger, Kinsta, Bluehost, GoDaddy, and “mainstream hosts” who are only popular because of marketing, but have less CPU cores/RAM, slower SATA SSDs, low CPU and PHP worker limits, and are mostly overglorified shared hosting.
Cloudways and Scala Hosting are 2 other solid cloud hosts, or RunCloud/GridPane for more DIY. If you absolutely must use shared hosting because of a tight budget, at least use someone who uses LiteSpeed like NameHero or ChemiCloud. Both use NVMe SSDs with more CPU/RAM than other LiteSpeed hosts like Hostinger. Not only is LiteSpeed faster than Apache/Nginx, but it can handle more traffic, is more efficient regarding CPU usage, and you’ll use LiteSpeed Cache with QUIC.cloud. Rocket.net is still faster – but that is arguably the fastest setup if you’re on a budget.


A few notes about Rocket.net:
- Here’s a Facebook thread if you’re still not sure.
- You get your first month for $1 when you create an account.
- Support is the best I’ve used (by far) and does free migrations.
- Cloudflare Enterprise is automatically setup (no need to do anything).
- The only “tweaks” I did were PHP 8 and requesting Redis Object Cache Pro.
- There are no PHP workers limits and 10-25x more monthly visits than Kinsta.
- You can see other people who improved TTFB in Rocket’s TrustPilot reviews.
- It’s owned by Ben Gabler who has extensive experience with hosting + CDNs.
- Here’s an interview I did with Ben where he answers several helpful questions.
- Test your before & after results and I also suggest using the WP Hosting Benchmarks plugin (here are my results, my GTmetrix report, and all my URLs pass core web vitals).
2. Reduce CSS + JavaScript Files
Are CSS/JS files part of FCP in your waterfall chart? You can also use the coverage report in Chrome Dev Tools to see your largest files:
Themes, plugins, and third-party code are usually the biggest culprits. After that, you can further reduce files through the “remove unused CSS” setting in FlyingPress or Perfmatters (faster than WP Rocket’s setting), delaying JavaScript, and replacing plugins. For example, I replaced wpDiscuz with native comments and started using Gutenberg for galleries + tables.
- Minify CSS/JS.
- Avoid Elementor, Divi, Avada.
- If using them, code your header/sidebar in CSS.
- If using them, activate their performance settings.
- Elementor can host fonts locally and preload them.
- Don’t overdo third-party tracking tools, or delay them.
- Avoid jQuery-dependent plugins (check Perfmatters for this).
- Use a smaller GA tracking code with Perfmatters or Flying Analytics.
- Disable WooCommerce scripts/styles and non-eCommerce content.
- The “remove unused CSS” setting is better in FlyingPress/Perfmatters.
- Use Perfmatters’ script manager to unload CSS/JS on pages they’re not used.
3. Use Local Fonts, Preload Them, And Use “Swap”
Fonts loading in your first contentful paint time? No problem…
Use Local Fonts – check your Waterfall chart to make sure fonts load from your domain, not fonts.gstatic.com or use.fontawesome.com. If they do, there are several tools to host them locally: several cache plugins can do this (but not WP Rocket), Perfmatters, OMGF, Elementor, Transfonter, etc. Also use woff or better, woff2 which are faster than alternative formats like .ttf. Finally, only use 1 font without loading too many font weights/icons (obvious but still common).
Preload Fonts – fonts loading above the fold or those in CSS files should be preloaded. There’s no magic tool to learn which fonts to preload, so this requires testing them in a Waterfall chart (preloading too many fonts or preloading fonts not being used can result in a negative impact).
Use Font-Display: Swap – if you need to ensure text remains visible during webfont load, PSI tells you which fonts are causing FOIT (flash of invisible text). Basically, you want to locate that file using String Locator, then add font-display: swap to the @font-face. Some plugins may also be able to do this: Elementor, Perfmatters, FlyingPress, WP Rocket, Swap Google Fonts Display.
@font-face {
font-family: "Lato Regular";
font-weight: 300;
font-style: normal;
src: url("fonts/Lato-Regular-BasicLatin.woff2") format("woff2");
font-display: swap;
}
4. Preload Viewport Images And Exclude From Lazy Load
Since viewport images should be loaded with high priority, they should be preloaded and excluded from lazy load. Again, FlyingPress/Perfmatters are more effective than WP Rocket.

Both can preload critical images where you set the number of images that usually load in the viewport (i.e. 2-3), then they will be automatically excluded from lazy load while preloaded. With WP Rocket, you need to follow an 8-step process just to specify the number of images to exclude from lazy load. Then you need to preload them individually (with code or a plugin like Pre* Party Resource Hints) which is a pain since usually, each page has unique viewport images.
If you have background images loading in the viewport, they’re treated differently, but you’ll want to exclude those from lazy load as well. Cache plugins and page builders usually have documentation on how to do it, for example, some plugins have a “skip-lazy” class you can add.
5. Avoid Page Builders For Headers
Your header/menu is part of the viewport and one of the first things people see.
Creating these with a page builder adds a lot of unnecessary code. So if you insist on using a page builder, code these in CSS (or hire a developer to do this). When I was trying to remove Elementor, I hired WP Johnny and this was the first thing he did which made a huge difference. And while we’re on the topic, stay clear of hamburger menus and other bloated menu plugins.

6. Defer JavaScript
Eliminating render-blocking resources is the first thing Google recommends to improve first contentful paint, which usually means deferring JavaScript.
If your site breaks, you’ll need to exclude problematic JS files from being deferred. And if you still don’t see good results, try installing Async JavaScript and click “apply defer” in the settings.
7. Use Full Page Caching
In Cloudflare’s test, APO improved first contentful paint by around 5% for desktop/mobile.
Of course, there are other options if you don’t want to pay $5/mo for APO: QUIC.cloud’s CDN, Super Page Cache plugin, and Rocket.net’s Cloudflare Enterprise all include full page caching.
8. Avoid Loading Plugins/Scripts In The Viewport
Since the viewport is high priority, consider moving heavy plugins/scripts down on the page.
Ads, social sharing buttons, and other files can be pushed down below the fold so they won’t load in the viewport. And, they can usually be delayed which can further improve web vitals.
9. Use A Performant DNS/CDN
Going back to your Waterfall chart, DNS lookup time is part of that long first request, and CDNs are also one of the best ways to improve TTFB.
Cloudflare’s DNS is my go-to which performs well on cdnperf.com (just sign up and change nameservers). If using QUIC.cloud, their DNS seems to perform well. But if you registered your domain with someone like GoDaddy or NameCheap, you’re using their DNS by default which is usually slow. And because DNS speed is part of TTFB, you’ll want to move it from your registrar.
While the best CDN is debatable, there’s no arguing Cloudflare Enterprise, QUIC.cloud (for LiteSpeed), and BunnyCDN are 3 solid options. Cloudflare has a massive network of 270+ locations with extensive speed/security features. QUIC.cloud’s CDN is newer but still has 75+ PoPs with powerful CSS/image optimizations when used with LiteSpeed Cache (but use the paid plan since the free version only uses 6 PoPs). BunnyCDN is another one of my favorites.
Cloudflare settings that can improve FCP include: Signed Exchanges, TCP Turbo, TLS settings, APO, using Workers for serverless rendering, and Brotli (although your host must support this).
10. Use Multiple Caching Layers
Did you know there are 6 different caching layers?
You might know 4 of them: browser cache (done by your cache plugin), CDN cache (done by your CDN), full page cache (done by your CDN), and HTTP accelerators like Varnish/FastCGI (done through your host). There are 2 other important caching types you may not know about:
- Object Cache – database cache. It’s hard to beat Redis which is more efficient than Memcached, especially Redis Object Cache Pro (included with Rocket.net and Cloudways). Check your host’s documentation/support on how to add it. Rocket.net requires you to install WP Redis, Cloudways involves activating the Redis add-on in their dashboard, or it’s found under PHP Extensions in cPanel.
- OPcache – compiles PHP scripts in memory and helps reduce CPU usage. Setting this up is unique for each host but in cPanel, it’s also found under PHP Extensions.
11. Generate Critical CSS And Inline It
Some plugins like WP Rocket generate critical CSS and inline it for you.
Otherwise, you can also use a free critical CSS generator tool which prevents FOUC (flash of unstyled text). The next step would be to inline it. Because the browser won’t have to wait for the CSS, it can start rendering your page sooner which will also improve first contentful paint.

12. Delay JavaScript
Delaying JavaScript can improve both your largest and first contentful paint.
Several cache plugins do this (FlyingPress, Perfmatters, Flying Scripts, WP Rocket). Just make sure you read the documentation and view common scripts to delay. You can even delay entire plugins when they load below the fold, such as third-party comments or social sharing plugins.
13. Fix Errors In Your Waterfall Chart
Sounds obvious, but you’d be surprised how many websites have red errors (which probably means you’re loading something that’s not being used, therefore creating a canceled request). Errors can often create the largest requests on your site, so you’ll want to fix them immediately.
14. Set A Longer Cache Expiration
Serving static assets with an efficient cache policy is an easy one to fix. Check your hosting account to see if there’s a setting. For example in Cloudways, it’s static cache expiry. Google wants a cache expiration of 365 days, but WooCommerce sites should generally use 1 month.
15. Test Cloudflare’s Rocket Loader
Rocket Loader defers JavaScript and can improve your site’s first contentful paint. However, it can also break your site, so use with caution. I personally prefer to keep Rocket Loader disabled.
Retest Your First Contentful Paint
PageSpeed Insights can take 28 days to update, so use SpeedVitals which uses Lighthouse.
Frequently Asked Questions
What is first contentful paint?
First contentful paint (FCP) measures the point when users see anything on your website. Anything that loads before that (including TTFB, DNS lookup time, and SSL) are part of FCP.
How do I improve first contentful paint in WordPress?
Reducing files loading in the viewport and ensuring a fast setup (hosting, CDN, theme, cache plugin) are two ways to improve first contentful paint. You can also preload fonts/images, defer and delay JavaScript, and avoid using page builders for headers.
Which WordPress plugins improve first contentful paint?
FlyingPress is better at optimizing first contentful paint than WP Rocket since it preloads images, hosts fonts locally, has a faster CDN, and is more effective at removing unused CSS.
How do I improve first contentful paint in Elementor?
Elementor optimizes first contentful paint with Experiments settings and hosting fonts locally while preloading them with font-display: swap. However, Elementor adds extra code compared to other lightweight options. Therefore, Elementor is NOT good for FCP.
Feel free to ask me any questions in the comments. Hope this helped :)
Cheers,
Tom