General Guide: See Global LCP Guide for universal concepts and fixes.
What is LCP?
Largest Contentful Paint measures when the largest content element becomes visible. Google recommends LCP under 2.5 seconds. On Acquia-hosted Drupal sites, LCP is heavily influenced by Varnish cache hit rates, Drupal render times, and Acquia CDN configuration.
Acquia-Specific LCP Causes
Acquia runs Drupal on a managed platform with Varnish caching, Acquia CDN (Akamai/CloudFlare), and its own deployment pipeline. Common LCP bottlenecks:
- Varnish cache misses -- uncacheable pages hit Drupal's PHP render pipeline, adding 500ms-3s to TTFB
- Acquia CDN not configured -- sites not using Acquia's CDN serve assets from origin, adding latency for remote users
- Drupal render pipeline -- complex Views, Paragraphs, or Layout Builder pages with dozens of database queries
- Unoptimized media -- Drupal's default image styles not using WebP or responsive breakpoints
- Module bloat -- contrib modules injecting render-blocking CSS/JS into every page
Fixes
1. Maximize Varnish Cache Hit Rate
Acquia's Varnish layer is the single biggest LCP lever. A cache hit returns in ~50ms; a miss can take 2-5 seconds.
// In settings.php -- set Drupal's page cache maximum age
// Acquia Varnish respects this value
$config['system.performance']['cache']['page']['max_age'] = 86400; // 24 hours
// Ensure no session is started for anonymous users (kills Varnish caching)
// Check services.yml:
// session.storage.options:
// cookie_lifetime: 0
// gc_maxlifetime: 200000
Verify cache status by checking response headers:
curl -sI https://yoursite.com | grep -i "x-cache\|age\|cache-control"
# X-Cache: HIT <-- good
# Age: 3421 <-- seconds since cached
If you see X-Cache: MISS consistently, check for:
- Session cookies being set on anonymous users (common with contrib modules)
Cache-Control: no-cacheheaders from custom middleware- Vary headers that fragment the cache (especially
Vary: Cookie)
2. Enable and Configure Acquia CDN
In the Acquia Cloud UI, enable the CDN under Environments > CDN. Then configure Drupal to use CDN URLs for assets:
// settings.php -- point file URLs to CDN
$config['system.performance']['css']['preprocess'] = TRUE;
$config['system.performance']['js']['preprocess'] = TRUE;
// If using Acquia's Shield module for CDN integration:
// drush en shield -y
// Configure at /admin/config/system/shield
3. Optimize Drupal Image Rendering
Drupal's Responsive Image module with WebP support dramatically reduces LCP for image-heavy pages:
# Enable required modules
drush en responsive_image media -y
Configure image styles at /admin/config/media/image-styles to include WebP conversion, then update your content templates:
{# In your node template (e.g., node--article--full.html.twig) #}
{% if node.field_hero_image.entity %}
{{ node.field_hero_image|view({
type: 'responsive_image',
settings: { responsive_image_style: 'hero_responsive' },
label: 'hidden',
}) }}
{% endif %}
Set up a responsive image style at /admin/config/media/responsive-image-style that maps breakpoints to optimized image styles with WebP fallbacks.
4. Preload the LCP Element
Add a preload hint in your theme's html.html.twig or via a preprocess hook:
// In mytheme.theme
function mytheme_preprocess_html(&$variables) {
// Preload hero image on front page
if (\Drupal::service('path.matcher')->isFrontPage()) {
$variables['#attached']['html_head_link'][] = [
[
'rel' => 'preload',
'as' => 'image',
'href' => '/sites/default/files/styles/hero_1920/public/hero-banner.webp',
'type' => 'image/webp',
],
TRUE,
];
}
}
5. Eliminate Render-Blocking Module Assets
Audit which modules inject CSS/JS on every page:
# List all libraries attached globally
drush eval "print_r(array_keys(\Drupal::service('library.discovery')->getLibrariesByExtension('core')));"
Move non-critical CSS to load asynchronously using your theme's .libraries.yml:
# mytheme.libraries.yml
global-styling:
css:
theme:
css/critical.css: { preprocess: true }
css/non-critical.css: { preprocess: true, attributes: { media: print, onload: "this.media='all'" } }
js:
js/theme.js: { attributes: { defer: true } }
6. Tune Acquia's PHP and Database
In Acquia Cloud, ensure your environment is properly sized. Check slow query logs:
# SSH into Acquia environment
ssh yoursite.prod@server.prod.hosting.acquia.com
cd /var/log/sites/yoursite/logs/
tail -f php-errors.log
# Look for slow database queries in Drupal's dblog or New Relic
Enable Drupal's built-in page cache and Dynamic Page Cache modules (they should be on by default but verify):
drush pm:list --status=enabled | grep cache
# Verify: page_cache, dynamic_page_cache are enabled
Measuring LCP on Acquia
- Acquia New Relic integration -- available on Acquia Cloud Professional and higher, shows server-side render times
- PageSpeed Insights -- test both origin URL and CDN URL to compare
- Acquia Cloud logs -- check
/var/log/sites/{site}/logs/for slow PHP requests that indicate TTFB problems - Drupal's WebProfiler (dev only) --
drush en webprofilerto see render timeline per request
Test these page types since they have different render characteristics:
- Front page -- often heaviest with Views, hero blocks, and Layout Builder
- Node pages -- check both cached and uncached (append
?cache-bust=1) - Views listing pages -- taxonomy terms, search results
- Authenticated pages -- these bypass Varnish entirely and are often 3-5x slower
Analytics Script Impact on Acquia
Drupal's hook system means analytics modules often inject scripts synchronously. Common offenders:
- Google Analytics module (
google_analytics) -- injects synchronous gtag.js by default - Matomo module -- adds blocking script to
<head> - Facebook Pixel modules -- inject inline scripts
Fix by loading analytics via GTM with delayed triggers, or patch the module to use async/defer attributes.