Largest Contentful Paint (LCP) measures how quickly the main content of a page loads. This guide provides Kentico-specific solutions to achieve LCP under 2.5 seconds.
What is LCP?
LCP measures: The render time of the largest visible content element in the viewport.
Good LCP scores:
- Good: < 2.5 seconds
- Needs Improvement: 2.5 - 4.0 seconds
- Poor: > 4.0 seconds
Common LCP elements:
- Hero images
- Header images
- Video thumbnails
- Background images
- Large text blocks
Diagnosing LCP Issues
Using PageSpeed Insights
- Visit https://pagespeed.web.dev/
- Enter your Kentico site URL
- Review the Diagnostics section
- Look for:
- Largest Contentful Paint element
- Slow server response times
- Render-blocking resources
- Large image files
Using Chrome DevTools
- Open DevTools (F12)
- Go to Performance tab
- Click Record and load page
- Look for LCP marker in timeline
- Identify which element is LCP
- Review loading time
Enable Kentico Debug
<!-- web.config -->
<appSettings>
<add key="CMSDebugEverything" value="true" />
<add key="CMSDebugResources" value="true" />
</appSettings>
Access: yoursite.com?debug=1
Kentico-Specific LCP Optimizations
1. Optimize Media Library Images
Kentico Media Library images are often the LCP element.
Enable Automatic Image Resizing
// In your layout or controller
@using CMS.Helpers
@{
var imageUrl = MediaFileURLProvider.GetMediaFileUrl(mediaFile.FileGUID, mediaFile.FileName);
// Add resizing parameters
var optimizedUrl = URLHelper.AddParameterToUrl(imageUrl, "width", "1200");
optimizedUrl = URLHelper.AddParameterToUrl(optimizedUrl, "height", "600");
}
<img src="@optimizedUrl" alt="Hero image" loading="eager" fetchpriority="high">
Configure Image Processing
<!-- web.config -->
<appSettings>
<add key="CMSImageQuality" value="85" />
<add key="CMSMaxImageWidth" value="2000" />
<add key="CMSMaxImageHeight" value="2000" />
</appSettings>
Use WebP Format
Create a custom transformation:
@using CMS.Helpers
@{
var supportsWebP = BrowserHelper.IsWebPSupported();
var imageUrl = MediaFileURLProvider.GetMediaFileUrl(mediaFile.FileGUID, mediaFile.FileName);
if (supportsWebP)
{
imageUrl = URLHelper.AddParameterToUrl(imageUrl, "format", "webp");
}
}
<img src="@imageUrl" alt="@mediaFile.FileDescription">
Implement Responsive Images
@using CMS.MediaLibrary
@{
var mediaFile = MediaFileInfoProvider.GetMediaFileInfo(mediaGuid);
var baseUrl = MediaFileURLProvider.GetMediaFileUrl(mediaFile.FileGUID, mediaFile.FileName);
}
<picture>
<source
type="image/webp"
srcset="@URLHelper.AddParameterToUrl(baseUrl, "width", "400")&format=webp 400w,
@URLHelper.AddParameterToUrl(baseUrl, "width", "800")&format=webp 800w,
@URLHelper.AddParameterToUrl(baseUrl, "width", "1200")&format=webp 1200w"
sizes="(max-width: 768px) 100vw, 1200px">
<source
type="image/jpeg"
srcset="@URLHelper.AddParameterToUrl(baseUrl, "width", "400") 400w,
@URLHelper.AddParameterToUrl(baseUrl, "width", "800") 800w,
@URLHelper.AddParameterToUrl(baseUrl, "width", "1200") 1200w"
sizes="(max-width: 768px) 100vw, 1200px">
<img src="@URLHelper.AddParameterToUrl(baseUrl, "width", "1200")"
alt="@mediaFile.FileDescription"
loading="eager"
fetchpriority="high">
</picture>
2. Preload LCP Image
In Layout File (_Layout.cshtml)
@using CMS.DocumentEngine
@{
var currentDoc = DocumentContext.CurrentDocument;
var heroImage = currentDoc.GetValue("HeroImage");
if (heroImage != null)
{
var imageUrl = MediaFileURLProvider.GetMediaFileUrl((Guid)heroImage, "hero.jpg");
var optimizedUrl = URLHelper.AddParameterToUrl(imageUrl, "width", "1200");
<link rel="preload" as="image" href="@optimizedUrl" fetchpriority="high">
}
}
For Background Images
<link rel="preload"
as="image"
href="@heroImageUrl"
fetchpriority="high">
<style>
.hero-section {
background-image: url('@heroImageUrl');
background-size: cover;
}
</style>
3. Reduce Server Response Time (TTFB)
Enable Output Caching
For entire pages:
// In your controller
[OutputCache(Duration = 3600, VaryByParam = "none")]
public ActionResult Index()
{
return View();
}
In web.config:
<system.webServer>
<caching>
<profiles>
<add extension=".html" policy="CacheUntilChange" kernelCachePolicy="CacheUntilChange" />
<add extension=".aspx" policy="CacheUntilChange" kernelCachePolicy="CacheUntilChange" />
</profiles>
</caching>
</system.webServer>
Enable Kentico Output Caching
- Go to Settings → System → Performance
- Enable Enable partial caching
- Enable Cache pages
- Set cache minutes appropriately
Optimize Database Queries
using CMS.DocumentEngine;
// BAD: Multiple database calls
var pages = DocumentHelper.GetDocuments()
.Path("/Products")
.ToList();
foreach (var page in pages)
{
var relatedData = page.GetValue("RelatedData"); // Additional query per item
}
// GOOD: Single query with all data
var pages = DocumentHelper.GetDocuments()
.Path("/Products")
.Columns("DocumentName", "RelatedData") // Specify needed columns only
.CombineWithDefaultCulture(false)
.ToList();
Enable SQL Server Query Store
-- Enable Query Store for performance monitoring
ALTER DATABASE [YourKenticoDB] SET QUERY_STORE = ON;
4. Eliminate Render-Blocking Resources
Defer Non-Critical CSS
<!-- Critical CSS inline -->
<style>
/* Critical above-the-fold styles */
.hero { display: block; }
</style>
<!-- Defer non-critical CSS -->
<link rel="preload" href="~/Content/styles.css" as="style"
<noscript><link rel="stylesheet" href="~/Content/styles.css"></noscript>
Bundle and Minify Resources
Using BundleConfig.cs:
using System.Web.Optimization;
public class BundleConfig
{
public static void RegisterBundles(BundleCollection bundles)
{
// JavaScript bundles
bundles.Add(new ScriptBundle("~/bundles/jquery").Include(
"~/Scripts/jquery-{version}.js"));
bundles.Add(new ScriptBundle("~/bundles/app").Include(
"~/Scripts/app.js",
"~/Scripts/components.js"));
// CSS bundles
bundles.Add(new StyleBundle("~/Content/css").Include(
"~/Content/site.css",
"~/Content/components.css"));
// Enable optimization
BundleTable.EnableOptimizations = true;
}
}
In layout:
@Scripts.Render("~/bundles/jquery")
@Scripts.Render("~/bundles/app")
@Styles.Render("~/Content/css")
Defer JavaScript
<!-- Defer non-critical scripts -->
<script src="~/Scripts/analytics.js" defer></script>
<script src="~/Scripts/app.js" defer></script>
<!-- Async for independent scripts -->
<script src="~/Scripts/social-widgets.js" async></script>
Move Scripts to Footer
<!DOCTYPE html>
<html>
<head>
<!-- Only critical resources in head -->
<link rel="stylesheet" href="~/Content/critical.css">
</head>
<body>
@RenderBody()
<!-- Scripts at end of body -->
@Scripts.Render("~/bundles/jquery")
@Scripts.Render("~/bundles/app")
@RenderSection("scripts", required: false)
</body>
</html>
5. Optimize Web Part Loading (Portal Engine)
Enable Web Part Caching
In web part properties:
- Go to Performance tab
- Enable Cache minutes
- Set appropriate cache duration
- Configure Cache dependencies
Use Partial Caching
<%@ OutputCache Duration="3600" VaryByParam="*" %>
<!-- Web part content -->
Lazy Load Below-Fold Web Parts
<script>
// Lazy load web parts below the fold
document.addEventListener('DOMContentLoaded', function() {
var lazyWebParts = document.querySelectorAll('.lazy-webpart');
if ('IntersectionObserver' in window) {
var observer = new IntersectionObserver(function(entries) {
entries.forEach(function(entry) {
if (entry.isIntersecting) {
// Load web part content via AJAX
loadWebPartContent(entry.target);
observer.unobserve(entry.target);
}
});
});
lazyWebParts.forEach(function(webpart) {
observer.observe(webpart);
});
}
});
</script>
6. Optimize Kentico Settings
Disable Unnecessary Features
<!-- web.config -->
<appSettings>
<!-- Disable features not in use -->
<add key="CMSEnableCodeEditSiteAdministration" value="false" />
<add key="CMSEnableOnlineMarketing" value="false" /> <!-- If not using -->
<add key="CMSEnableTranslations" value="false" /> <!-- If not using -->
<!-- Optimize ViewState (Portal Engine) -->
<add key="CMSControlState" value="false" />
<!-- Enable compression -->
<add key="CMSEnableOutputFilter" value="true" />
<add key="CMSEnableOutputCompression" value="true" />
</appSettings>
Configure IIS Compression
<!-- web.config -->
<system.webServer>
<urlCompression doStaticCompression="true" doDynamicCompression="true" />
<httpCompression>
<dynamicTypes>
<add mimeType="text/*" enabled="true" />
<add mimeType="application/javascript" enabled="true" />
<add mimeType="application/json" enabled="true" />
</dynamicTypes>
<staticTypes>
<add mimeType="text/*" enabled="true" />
<add mimeType="application/javascript" enabled="true" />
<add mimeType="image/svg+xml" enabled="true" />
</staticTypes>
</httpCompression>
</system.webServer>
7. Use CDN for Static Resources
Configure CDN in Kentico
// In App_Start or Global.asax.cs
public class Application : System.Web.HttpApplication
{
protected void Application_Start()
{
// Set CDN URL for media files
URLHelper.MediaFileUrlFormat = "https://cdn.yoursite.com/media/{0}";
}
}
CDN for JavaScript/CSS
<environment names="Production">
<link rel="stylesheet" href="https://cdn.yoursite.com/Content/site.css" />
<script src="https://cdn.yoursite.com/Scripts/app.js"></script>
</environment>
<environment names="Development,Staging">
<link rel="stylesheet" href="~/Content/site.css" />
<script src="~/Scripts/app.js"></script>
</environment>
8. Implement Critical CSS
Create inline critical CSS for above-the-fold content:
<!DOCTYPE html>
<html>
<head>
<style>
/* Critical CSS for above-the-fold content */
body { margin: 0; font-family: Arial, sans-serif; }
.header { background: #333; color: #fff; padding: 20px; }
.hero { min-height: 400px; background-size: cover; }
.hero h1 { font-size: 48px; margin: 0; }
</style>
<!-- Preload full stylesheet -->
<link rel="preload" href="~/Content/site.css" as="style"
<noscript><link rel="stylesheet" href="~/Content/site.css"></noscript>
</head>
<body>
<!-- Content -->
</body>
</html>
Testing Your Improvements
1. Before and After Comparison
# Test with PageSpeed Insights
# Record baseline LCP score
# Make optimizations
# Test again and compare
2. Real User Monitoring
Implement RUM with GA4:
<script>
// Send Core Web Vitals to GA4
new PerformanceObserver((entryList) => {
for (const entry of entryList.getEntries()) {
if (entry.entryType === 'largest-contentful-paint') {
gtag('event', 'web_vitals', {
'metric_name': 'LCP',
'metric_value': Math.round(entry.renderTime || entry.loadTime),
'metric_rating': entry.renderTime < 2500 ? 'good' : entry.renderTime < 4000 ? 'needs_improvement' : 'poor'
});
}
}
}).observe({type: 'largest-contentful-paint', buffered: true});
</script>
3. Continuous Monitoring
Set up automated monitoring:
- Google Search Console: Core Web Vitals report
- PageSpeed Insights API: Automated testing
- Application Insights: Server-side monitoring
Common LCP Issues and Fixes
Issue: Large Unoptimized Hero Image
Symptoms:
- LCP > 4 seconds
- Large image file size (>500KB)
- Image loads slowly
Solutions:
- Resize image to appropriate dimensions
- Convert to WebP format
- Add preload link
- Use
fetchpriority="high" - Consider using CDN
Issue: Slow TTFB
Symptoms:
- Server response >600ms
- Database queries slow
- Kentico debug shows slow page processing
Solutions:
- Enable output caching
- Optimize database queries
- Add database indexes
- Increase server resources
- Enable partial caching
Issue: Render-Blocking Resources
Symptoms:
Solutions:
- Inline critical CSS
- Defer non-critical CSS
- Move scripts to footer
- Use async/defer attributes
- Bundle and minify resources
Issue: ViewState Size (Portal Engine)
Symptoms:
- Large HTML payload
- Hidden
__VIEWSTATEfield is huge - Slow page load
Solutions:
<!-- web.config -->
<appSettings>
<add key="CMSControlState" value="false" />
</appSettings>
<pages enableViewState="false" />
Or per-page:
<%@ Page EnableViewState="false" %>
Monitoring LCP Over Time
Set Up Alerts
Create alerts for LCP degradation:
- Create custom event for LCP
- Set up alert for LCP > threshold
- Receive notifications
Application Insights:
var telemetry = new TelemetryClient();
telemetry.TrackMetric("LCP", lcpValue);
Regular Audits
Schedule regular performance audits:
- Weekly: PageSpeed Insights tests
- Monthly: Full performance review
- Quarterly: Comprehensive optimization
Best Practices
- Optimize Images: Always resize and compress
- Preload LCP Element: Use
<link rel="preload"> - Enable Caching: Output and browser caching
- Minimize TTFB: Server and database optimization
- Remove Unused Code: Clean up CSS/JS
- Use CDN: Serve static assets from CDN
- Monitor Regularly: Track LCP metrics
- Test on Real Devices: Mobile and desktop