Customer Data (Private Content)
Describe front-end usage of customer data: client-side private content, customerData API, sections.xml, and invalidation to keep FPC enabled.
Customer Data (Private Content)
The Problem With Sessions in Templates
Rendering session-dependent content in *.phtml prevents Full Page Cache (FPC) and Varnish from caching the page HTML.
<!-- Avoid this pattern in templates -->
<div class="greeting">
Welcome <?= $block->getSession()->getUsername(); ?>!
</div>
Instead, move user-specific pieces to the client side using the Customer Data framework.
Approach: Private Content on the Client
- Local storage: User-specific data is persisted in the browser (localStorage) and hydrated via AJAX.
- Placeholders: Server returns fully cached HTML with placeholders; JS fills them after load.
- customerData JS module: Provides API to read, subscribe, and reload sections.
Using the customerData Module
define(['Magento_Customer/js/customer-data'], function (customerData) {
'use strict';
// Read a section (Knockout observable)
var cart = customerData.get('cart');
// Get current value
var cartData = cart();
// React to changes
cart.subscribe(function (newCart) {
// update UI with newCart
});
// Force reload of one or more sections
customerData.reload(['cart', 'customer'], true);
});
- get(name) returns a KO observable; call it as a function to read, or subscribe to updates.
- reload(sections, forceNew) triggers AJAX to
/customer/section/loadto refresh data.
Canonical Example
See Magento/Checkout/view/frontend/web/js/view/minicart.js for a canonical usage of customer data (minicart content and count).
Sections & Invalidation
The sections mechanism ensures that client-side data stays fresh when backend state changes.
- Configuration: Each module declares sections and invalidating actions in
etc/sections.xml. - Frontend loader: When data is missing/expired, Magento sends AJAX to fetch sections' JSON.
- Backend provider: Aggregates data for each section and returns JSON for the frontend.
- XHR Listener: JS listens for POST/PUT requests; matching actions invalidate affected sections.
sections.xml Example
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Customer:etc/sections.xsd">
<section name="cart">
<action name="checkout_cart_add"/>
<action name="checkout_cart_updatePost"/>
<action name="checkout_cart_delete"/>
</section>
<section name="customer">
<action name="customer_account_loginpost"/>
<action name="customer_account_logoutsuccess"/>
</section>
</config>
When these actions occur (typically via POST), Magento invalidates the specified sections; the next page view or XHR triggers reload.
Rendering Private Content in HTML
Use data-mage-init or x-magento-init to bootstrap a small module that reads from customerData and updates the DOM.
<div class="greeting" data-role="greeting"></div>
<script type="text/x-magento-init">
{
"[data-role=greeting]": {
"Vendor_Module/js/greeting": {}
}
}
</script>
define(['Magento_Customer/js/customer-data'], function (customerData) {
'use strict';
return function (element) {
var customer = customerData.get('customer');
var name = (customer() && customer().fullname) || 'Guest';
element.textContent = 'Welcome ' + name + '!';
customer.subscribe(function (data) {
element.textContent = 'Welcome ' + ((data && data.fullname) || 'Guest') + '!';
});
};
});
Key Endpoints & Storage
- Load endpoint:
/customer/section/load(returns JSON for requested sections) - Storage: Section data is persisted in localStorage and synced with Knockout observables.
- Expiry: Magento uses TTL to expire sections; expired/missing sections are reloaded automatically.
Best Practices
- Avoid session-dependent templates: Prefer client rendering via customerData.
- Use sections.xml: Declare invalidation for every backend action that affects private content.
- Minimize payload: Keep section JSON small; render on the client efficiently.
- Subscribe instead of polling: Use observables to react to updates.
- Force reload when needed:
customerData.reload(['section'], true)after custom AJAX updates.
Further Reading
Exam Tips
- Goal: Keep FPC on; render personalized bits via JS from localStorage.
- API:
customerData.get('section')(observable),.subscribe(),.reload(). - Invalidation:
etc/sections.xmlmaps backend actions to sections; POST/PUT XHR triggers invalidation. - Endpoint:
/customer/section/loadprovides sections JSON. - Example: Minicart, welcome message, messages area.