Magento 2 고객 데이터 섹션 및 localStorage 성능 최적화

작성자

카테고리:

← 피드로
DEV Community · Magevanta · 2026-08-01 개발(SW)

Magevanta

Magento 2 Customer Data Sections & localStorage Performance Optimization

Every Magento 2 storefront uses customer data sections — the mechanism behind the mini-cart, customer name display, wishlist counters, and checkout summaries. It looks seamless to shoppers, but under the hood it can silently murder your page load performance.

If you’ve ever wondered why your pages fire an extra AJAX request immediately after the initial load, or why your localStorage balloons to several megabytes, this post is for you.

What Are Customer Data Sections?

Magento 2 splits page rendering into two phases: server-side (Astro/Varnish/FPC) and client-side (JavaScript). Because full-page cache serves the same HTML to every visitor, personalized data — cart contents, logged-in customer name, wishlist count — cannot be rendered server-side for cached pages.

Enter sections.xml and the Customer Data JS API:

<!-- Vendor_Module/etc/frontend/sections.xml -->
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Customer:etc/sections.xsd">
    <action name="checkout/cart/add">
        <section name="cart"/>
        <section name="checkout-data"/>
    </action>
</config>

Enter fullscreen mode Exit fullscreen mode

This file tells Magento: “When the checkout/cart/add action runs, invalidate the cart and checkout-data sections.” On the next page load, JavaScript detects these invalidated sections and fetches fresh data via customer/section/load/ AJAX.

The Data Flow

  1. Page loads from FPC/Varnish (no personalization)
  2. JS initializes Magento_Customer/js/customer-data
  3. localStorage is checked for cached section data (by sectionLoadUrl + storeId key)
  4. Invalidated sections trigger POST /customer/section/load/ with section names
  5. Response updates localStorage, ko.observables, and UI (mini-cart, messages, etc.)

This sounds efficient, but it has three major performance traps.

Performance Trap #1: The “Sections Hell” AJAX Request

Out of the box, Magento 2’s customer-data module calls customer/section/load/ with every registered section on the first uncached hit:

// vendor/magento/module-customer/view/frontend/web/js/customer-data.js
// (simplified)
getFromServer: function (sectionNames) {
    return storage.post('customer/section/load/', {
        sections: sectionNames,
        update_section_id: true
    });
}

Enter fullscreen mode Exit fullscreen mode

A typical Magento installation registers 15–25 sections: cart, checkout-data, comparison, directory-data, customer, wishlist, messages, last-ordered-items, review, product_data_storage, recently_viewed_product, recently_compared_product, paypalbilling_agreement, persistent, and any custom sections added by extensions.

Each section requires database queries on the backend:

Section Typical Backend Cost cart Quote load + items + totals calculation customer Customer entity load + address collection wishlist Wishlist item collection directory-data Country/region data + shipping rates cache checkout-data Quote address validation + shipping method resolution

On a high-traffic store, that single section/load/ call can take 300ms–1.2s depending on cart complexity, catalog size, and whether Redis is configured for session storage.

The Real Kicker: It Runs on Every Page

Unlike cart/checkout pages (where you expect some backend work), this request fires on every cached CMS page, category page, and product page. A shopper browsing 20 products generates 20 section/load requests — all doing the same work.

Performance Trap #2: localStorage Bloat

Section data is stored in the browser’s localStorage. Magento’s default key format is:

mage-cache-storage     // ~50KB–500KB+
mage-cache-storage-section-invalidation  // small

Enter fullscreen mode Exit fullscreen mode

The cart section alone can grow to 100KB+ if the shopper has a complex cart with configurable products, custom options, and tier pricing. Multiply by 20 sections and you’re pushing 1–2MB of localStorage per visitor.

This causes three problems:

  1. Mobile browsers aggressively evict localStorage. On iOS Safari, storage can be cleared on memory pressure, forcing a full re-fetch.
  2. Slow deserializationJSON.parse() on 1MB+ strings blocks the main thread for 10–50ms, contributing to poor Interaction to Next Paint (INP).
  3. Session storage quota — some browsers limit localStorage to 5MB. One heavy cart can approach the limit, breaking other features.

Performance Trap #3: Section Invalidation Abuse

The most common mistake: declaring section invalidation on every controller action.

<!-- BAD: Extension invalidates everything on every page -->
<action name="*">
    <section name="cart"/>
    <section name="customer"/>
    <section name="wishlist"/>
</action>

Enter fullscreen mode Exit fullscreen mode

Some third-party extensions use wildcard (*) matching or invalidate cart on non-cart actions (like product list page views via a tracking pixel). This forces the section/load/ call on every single page even when nothing changed.

Another abuse pattern: plugins on getSectionData() that run expensive queries for data that isn’t even displayed on the current page.

Optimization Strategies

1. Audit Your sections.xml Files

First, map out what you’re actually invalidating:

# Find all section definitions
grep -r "<action name=" app/code vendor/magento --include="sections.xml" | wc -l

# Find wildcard invalidation (highly suspicious)
grep -r '<action name="\*"' app/code vendor --include="sections.xml"

Enter fullscreen mode Exit fullscreen mode

For each wildcard or overly broad invalidation, ask: “Does this action actually change this section’s data?”

2. Eliminate Unused Sections from Initial Load

You can configure which sections load on the initial request via di.xml:

<!-- app/etc/di.xml or your module -->
<type name="Magento\Customer\CustomerData\SectionPoolInterface">
    <arguments>
        <argument name="sectionSourceMap" xsi:type="array">
            <!-- Only load what you actually display on every page -->
            <item name="cart" xsi:type="string">Magento\Checkout\CustomerData\Cart</item>
            <item name="customer" xsi:type="string">Magento\Customer\CustomerData\Customer</item>
            <item name="messages" xsi:type="string">Magento\Theme\CustomerData\Messages</item>
        </argument>
    </arguments>
</type>

Enter fullscreen mode Exit fullscreen mode

Sections like recently_viewed_product, recently_compared_product, and review rarely need to be in the initial section/load/ call. Load them lazily when the relevant widget initializes.

3. Disable Sections You Don’t Use

If you’re not using wishlist or product comparison, remove them entirely:

<!-- app/code/Vendor/Module/etc/frontend/di.xml -->
<type name="Magento\Customer\CustomerData\SectionPool">
    <plugin name="disable_unused_sections"
            type="Vendor\Module\Plugin\DisableUnusedSections"
            sortOrder="10"/>
</type>

Enter fullscreen mode Exit fullscreen mode

<?php
namespace Vendor\Module\Plugin;

class DisableUnusedSections
{
    private array $disabledSections = [
        'wishlist',
        'comparison',
        'review',
        'last-ordered-items'
    ];

    public function afterGetSectionNames(\Magento\Customer\CustomerData\SectionPool $subject, array $result): array
    {
        return array_diff($result, $this->disabledSections);
    }
}

Enter fullscreen mode Exit fullscreen mode

This removes those sections from both the section/load/ call and localStorage.

4. Switch to sessionStorage for Ephemeral Data

For sections that don’t need to persist across tabs (like messages), override the storage backend:

<!-- app/code/Vendor/Module/etc/frontend/di.xml -->
<type name="Magento\Customer\CustomerData\JsLayoutDataProviderPool">
    <arguments>
        <argument name="components" xsi:type="array">
            <!-- Custom storage handler -->
        </argument>
    </arguments>
</type>

Enter fullscreen mode Exit fullscreen mode

Or use a simpler approach: patch customer-data.js to use sessionStorage for sections that are tab-specific, reducing localStorage pressure.

5. Implement Server-Side Push (Advanced)

Instead of the browser polling on every page load, push updates only when data actually changes:

// In your observer, after cart modification
$sectionIdentifier = $this->sectionIdentifierFactory->create();
$sectionIdentifier->resetIdentifier(); // Forces JS to re-fetch on next action

Enter fullscreen mode Exit fullscreen mode

Better yet, for headless/API-first architectures, bypass customer-data entirely and use GraphQL queries for cart state, loading only what’s needed when the mini-cart opens.

6. Redis for Section Metadata

While section data itself is in the browser, the backend still queries the database. Ensure your customer/section/load/ endpoint uses:

  • Redis session storage (not DB sessions)
  • Quote caching via Magento_Quote cache tags
  • Varnish pass-through for section/load/ (do not cache this endpoint — it must be dynamic)

7. Measure Before and After

Use Blackfire or New Relic to trace customer/section/load/ calls:

  1. Open any cached product page
  2. Check the Network tab — find the section/load/ POST
  3. Profile it — look for QuoteRepository::get, TotalsCollector::collect, AddressRepository::getList
  4. Apply optimizations and re-profile

Expected results after optimization:

Metric Before After Section count 22 6 AJAX payload size 45KB 8KB section/load/ backend time 450ms 80ms localStorage size 1.2MB 180KB INP improvement — -40ms

Summary

Customer data sections are a powerful but dangerous feature. The default Magento 2 configuration is generous to a fault — it loads every section on every page, stores megabytes in localStorage, and assumes all extensions know how to invalidate responsibly.

The fix is surgical: audit your sections.xml, eliminate unused sections, disable features you don’t need, and ensure your backend session/cache layer is optimized for the customer/section/load/ endpoint.

The fastest AJAX request is the one you don’t have to make.

Found this helpful? Check out our Magento 2 Performance Optimization Guide 2026 for a full-storefront tuning strategy.

원문에서 계속 ↗

코멘트

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다