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. Liferay DXP is a Java-based portal platform. LCP is driven by page cache configuration, Adaptive Media image processing, and theme/portlet asset loading.
Liferay-Specific LCP Causes
- Portal page cache disabled -- without caching, Liferay renders every page through the full portlet lifecycle (init, processAction, render), resulting in 1-5s TTFB
- Adaptive Media not configured -- Liferay's Adaptive Media module generates responsive image variants, but requires configuration
- Theme CSS/JS not minified -- Liferay themes can include unminified frontend assets
- Portlet render chain -- each portlet on a page renders independently, and slow portlets block the entire page
- Fragment rendering overhead -- Liferay 7.x Content Pages use fragments that each require separate rendering
Fixes
1. Enable Page Caching
Configure Liferay's built-in page cache:
# portal-ext.properties
# Enable Ehcache-based page caching
ehcache.multi.vm.config.location=/ehcache/liferay-multi-vm-clustered.xml
layout.cache.enabled=true
# Set cache size and TTL
layout.cache.max.size=10000
layout.cache.ttl=3600
Or use the Admin Panel: Control Panel > Configuration > System Settings > Infrastructure > Cache
2. Configure Adaptive Media
Set up image resolutions at Control Panel > Configuration > Adaptive Media:
Resolution: Hero (1920x600)
Resolution: Thumbnail (400x300)
Resolution: Mobile Hero (640x320)
In your theme's FreeMarker templates:
<#-- Use Adaptive Media for responsive hero images -->
<#assign heroImage = journalArticle.getDocument().selectSingleNode("//dynamic-element[@name='heroImage']/dynamic-content")>
<#if heroImage?has_content>
<img
src="${heroImage.getText()}"
srcset="
${adaptiveMedia.getAdaptiveMediaURL(heroImage.getText(), 640, 320)} 640w,
${adaptiveMedia.getAdaptiveMediaURL(heroImage.getText(), 1024, 400)} 1024w,
${adaptiveMedia.getAdaptiveMediaURL(heroImage.getText(), 1920, 600)} 1920w"
sizes="100vw"
width="1920" height="600"
alt="${title}"
loading="eager"
fetchpriority="high"
>
</#if>
3. Minify Theme Assets
In your Liferay theme's liferay-look-and-feel.xml:
<look-and-feel>
<theme id="mytheme" name="My Theme">
<settings>
<setting key="minified-css" value="true" />
<setting key="minified-js" value="true" />
</settings>
</theme>
</look-and-feel>
Enable portal-wide minification:
# portal-ext.properties
minifier.enabled=true
theme.css.fast.load=true
theme.images.fast.load=true
javascript.fast.load=true
4. Optimize Portlet Rendering
Identify slow portlets using Liferay's built-in profiling:
# Enable portlet render timing
portlet.container.render.timeout=5000
Cache portlet output:
<!-- In portlet.xml -->
<portlet>
<portlet-name>MyPortlet</portlet-name>
<expiration-cache>3600</expiration-cache>
</portlet>
5. Preload Critical Assets
<#-- In theme's portal_normal.ftl -->
<link rel="preconnect" href="${themeDisplay.getCDNBaseURL()}" />
<link rel="preload" as="image" href="${heroImageURL}" />
<link rel="preload" as="style" href="${themeDisplay.getPathThemeCSS()}/main.css" />
Measuring LCP on Liferay
- Liferay's Performance tab (Control Panel) -- shows page render times per portlet
- Gogo Shell --
cache:listAllshows cache statistics - PageSpeed Insights -- test key portal pages
- JMX monitoring -- connect JConsole for JVM-level performance data
Analytics Script Impact
Liferay's analytics integration (Analytics Cloud) is built-in and loads asynchronously. For third-party analytics, add via theme modules with async/defer attributes.