CASE STUDY · E-COMMERCE

Korean cosmetics on WooCommerce: LCP halved on mobile

A Korean skincare WooCommerce store in three languages, with 2,400 products and dozens of marketing scripts: all mobile Core Web Vitals back in the good range, without giving up any feature.

Three colorful cosmetics bottles next to a product page in an online store

Background

Miloon, the online store of ZVM SRL, is an e-commerce site specializing in Korean cosmetics: skincare, makeup and body care from about thirty brands, with a catalog of roughly 2,400 products sold in three languages (Italian, French and English). The store runs on WooCommerce with a commercial page-builder theme and a mega menu that organizes products by skin need, ingredient and brand.

Like many stores that grew fast, it had accumulated features added one at a time: wishlist, AJAX filters, a loyalty program, promotional badges, a waiting list for sold-out products, verified reviews, push notifications, a notice bar, buy-now-pay-later and a dozen marketing tags managed through Google Tag Manager. None of them was superfluous for the business; the problem was how they were loaded.

What the data said

Over 80% of traffic comes from smartphones, often from social campaigns, and the mobile CrUX data described a slow site exactly where it matters: LCP at 4.4 seconds, INP at 410 milliseconds and CLS at 0.22 at the 75th percentile. Product pages and categories exceeded the thresholds of all three metrics; the home page, heavy with promotional sliders, was the worst for LCP.

The lab score swung widely from one test to the next and did not explain the problem on its own, so alongside the CrUX data we set up real user monitoring (RUM) with metric attribution, to know which element was the LCP, which interaction was slow and what was shifting.

The diagnosis

Two weeks of analysis revealed a different cause for each metric, on both the server side and the application side:

  • High and irregular TTFB: 1.3 seconds at the 75th percentile. The page cache was bypassed by a session cookie set for every visitor, even with nothing in the cart; the database had over 4 MB of options loaded on every request and hundreds of thousands of already completed scheduled actions.
  • Delayed LCP: the main image was the first slide of a carousel initialized in JavaScript, lazy-loaded and without priority, after 38 stylesheets and more than 140 scripts.
  • INP from heavy interactions: opening the mega menu, adding to the cart and category filters triggered long main-thread tasks, made worse by third-party pixels and widgets all running at load.
  • CLS from injected elements: the notice bar, review badges, cookie banner and promotional badges appeared after the first render, pushing the content down.

Server-side work

The first job was to make the server response fast and predictable, because every millisecond of TTFB adds to LCP.

  • Upgrade from PHP 7.4 to PHP 8.3, with OPcache sized on the real code and JIT disabled after testing.
  • Page cache at web server level, with exclusion rules based on the cart and customer session cookies, not on any cookie: anonymous visitors always get the cached page.
  • Persistent object cache with Redis to reduce repeated queries on products, variations and translations.
  • Database cleanup: options loaded on every request down from 4.1 MB to 0.6 MB, expired sessions and completed scheduled actions removed by a periodic routine.
  • HTTP/3, Brotli compression and correct cache headers for images, fonts and static files.

Application-side work

On the front end the goal was to keep every marketing feature, changing only when and how they load.

  • On the home page the carousel was replaced by a static main image, served in AVIF and WebP with srcset, preloaded and with fetchpriority="high"; the other promotions moved below the fold.
  • Fonts hosted locally, reduced to the weights actually used and with aligned fallback metrics, to avoid both invisible text and the shift when the font swaps.
  • Plugin scripts and styles loaded only where needed: the wishlist and waiting list on product pages, AJAX filters on categories, buy-now-pay-later in the cart and checkout. Six plugins no longer in use were removed.
  • Marketing tags reorganized in Google Tag Manager: those not needed for the first render fire after load or on the first interaction, in compliance with the consent collected by the cookie banner.
  • Mega menu rendered server-side and opened with CSS, category filters with batched requests and DOM updates limited to the product grid only.
  • Space reserved in advance for the notice bar, review badges and promotional badges, so no element shifts the content once it appears.

Results

CrUX data is a rolling 28-day average, so we compared the window before the work with the one closed four weeks after the last release, always on mobile and at the 75th percentile.

Metric (mobile, p75)BeforeAfter
TTFB1.3 s0.4 s
LCP4.4 s2.3 s
INP410 ms180 ms
CLS0.220.04

All three Core Web Vitals moved into the “good” range on mobile, and the origin’s CrUX assessment went from “failed” to “passed”. Over the same period the smartphone conversion rate grew, but the seasonality of the promotions means we cannot attribute that to the performance work alone, so we do not use it as a result of the project.

How we maintain the result

An e-commerce site changes every week: new campaigns, new plugins, new tags. To avoid slipping back, we left RUM monitoring active with alerts on the Core Web Vitals thresholds, an automated Lighthouse check before every release and a short list of rules shared with the marketing team on images, banners and new scripts. Every month we review the data and any regressions together.

THE NEXT STEP

Let’s start
with your site.

Tell us about the project, the problems you are seeing and your goals. Together we will define tailored work.

Request an analysis

Takes you to the form on the Contact page.

MANAGED SERVER S.R.L.info@corewebvitals.eu +39 02 5656 9681

Monday – Friday · 9:30 am – 7:30 pm (CET)

Prefer an online form?
Contact us on managedserver.it ↗