
On a Hyvä storefront, personalized ERP data belongs outside the cached page. Mirror pricing and inventory into Magento on a schedule, render a cacheable public shell, and hydrate customer-specific values through Hyvä’s section data after paint. Live ERP calls in the request path are what turn a fast frontend slow again.
That is the whole argument, and it is the part most integration projects get backwards. A Luma to Hyvä migration removes roughly a megabyte of JavaScript from the critical path. Six months later the same store is back to a three second load, and the theme is not the reason. The reason is a live price call on the product page, a stock check that blocks add to cart, a tag manager carrying nine tags, and a chat widget that ships 300 KB before anyone asks a question. This guide is about the layer that decides whether your frontend investment survives contact with your back office.
Two integration surfaces, two different rulebooks
Merchants talk about “integrations” as one thing. Your storefront sees two, and they fail differently.
| Surface | Examples | How it hurts performance | The governing rule |
|---|---|---|---|
| Server side data | ERP pricing, inventory, credit limits, order history, freight quotes, tax service | Adds latency to time to first byte, breaks full page cache, cascades when the upstream is slow | Keep it out of the request path. Mirror, queue, and hydrate |
| Client side scripts | Tag manager, chat, reviews, personalization, A/B testing, consent tools | Adds main thread work, degrades INP, causes layout shift | Budget it, defer it, and load on interaction |
Fixing one and ignoring the other produces a store that is fast in the lab and slow in the field. Field data is what Google scores and what your buyers feel.
Rule one: the ERP is not in the request path
Most distribution and manufacturing ERPs were built for order entry by staff, not for storefront traffic. A system that answers a pricing call in 400 milliseconds for twelve concurrent users will answer in four seconds for two hundred, and your product page inherits that number. The durable pattern is a fast local mirror that the ERP updates on a schedule, with writes queued back in controlled batches.
Decide per data type. This is the table we build with clients before any code is written:
| Data | Where it should live | Freshness that is actually needed | Fallback when the source is down |
|---|---|---|---|
| List and tier pricing | Magento, synced from ERP | Hourly, or on change events | Serve last known price, flag stale in admin |
| Customer or contract pricing | Magento shared catalog or price mirror | Nightly plus event-driven updates | Serve last synced price, block only if policy requires |
| Inventory quantity | Magento MSI, synced from ERP | 5 to 15 minutes for most catalogs | Show in stock or out of stock band, not exact counts |
| Credit limit and balance | ERP, cached per customer for minutes | Minutes at checkout, not per page view | Allow order, flag for manual credit review |
| Order and invoice history | ERP, fetched on the account page only | On demand, per view | Show an error card on that panel, not the whole page |
| Freight or LTL quotes | ERP or carrier, live call at checkout | Live, with a timeout | Fall back to table rates or “quoted after order” |
| Delivery dates | Derived locally from synced lead times | Daily | Show a range, not a promise |
Two decisions carry most of the value. First, exact stock counts are rarely worth their cost. Bands such as “in stock”, “low stock”, and “made to order” satisfy the buyer and remove per-request pressure. Second, credit checks belong at checkout, not on the catalog. Teams that put a credit call on every page view are paying for information the buyer does not use until the end.
The wider architecture behind this, including message queues, idempotency, and inventory reservations, is covered in our guide to Magento B2B ERP, CRM, and POS integration patterns. What follows is the storefront half of that story.
How personalized data reaches a cached Hyvä page
Full page cache exists so a page can be served without touching PHP. Anything customer specific has to arrive separately, and Hyvä’s approach is simpler than Luma’s in a way that matters for integration work.
In Luma, private content sections are subscribed to individually and invalidated piecemeal. In Hyvä, as the section data documentation sets out, you cannot subscribe to one section. All sections arrive combined in a single data object, loaded by Ajax and kept in local storage. It refreshes when the data is older than one hour or when the private_content_version cookie changes, and regular POST requests invalidate it for the next page load.
Practical consequences for anyone wiring ERP data into the frontend:
- Add your customer-specific values as a section, and they ride along with the same request that already carries cart and customer data. One request, not five.
- Consume it in Alpine by listening for the event, for example
@private-content-loaded.window="receiveCustomerData($event.detail.data)", then render from that state. - To force a refresh after an Ajax action, dispatch
reload-customer-section-data. If you need a hard refresh, clear themage-cache-sessidcookie first, and leaveprivate_content_versionalone. - The one hour expiry is a design constraint. If your ERP price changes must appear faster than that for a logged-in buyer mid-session, drive an explicit reload after the relevant action rather than shortening the window globally.
The complementary piece is deciding what stays public. Hyvä’s caching guidance and Adobe’s own page caching documentation both point the same direction: keep catalog, product, and CMS pages cacheable, and pull the personal parts out rather than marking whole pages uncacheable. Every “cacheable false” in a layout file is a decision to serve that page from PHP forever.
The pattern that keeps full page cache working for B2B
B2B is where this gets abandoned too early, usually with the reasoning that logged-in buyers see custom catalogs and custom prices, so caching is pointless. That conclusion costs real money, because it means every category page render hits origin.
The pattern that holds:
- Render a cacheable shell. Category and product pages render publicly, with price and availability regions present but empty, sized to their final dimensions.
- Hydrate after paint. One batched request returns prices and stock bands for every product on screen, keyed by customer and catalog. On a category page that is one call for the visible grid, not one per tile.
- Reserve the space. Set explicit dimensions on the price and stock regions. A price that appears late and pushes the grid down is a layout shift, and CLS is scored on exactly that. Hyvä’s Core Web Vitals guidance is blunt about reserving space for content inserted later.
- Cache the hydration response. Per customer group or per contract, for minutes. Most B2B buyers view many pages per session against pricing that does not change during it.
- Prefetch on intent. For configurators and variant-heavy products, fetch the likely next prices in the background so the buyer sees an instant change rather than a spinner.
Restricting prices to logged-in users does not change the architecture. It changes what the public shell says, which should be a clear prompt to sign in rather than an empty space that looks broken. How company accounts, tiered pricing, and shared catalogs render in this model is covered in our piece on Hyvä for B2B frontends.
When a live call is genuinely required
Some calls cannot be mirrored: a freight quote for a specific pallet configuration, a credit availability check before order placement, a tax calculation for an exempt customer. Those are legitimate. Treat each one as a dependency with a contract, not as a function call.
| Control | What to set | Why |
|---|---|---|
| Timeout | 2 to 3 seconds at checkout, 1 second on catalog | The buyer’s patience is the real budget |
| Retry | One retry, with backoff, only for idempotent reads | Retrying a write duplicates orders |
| Circuit breaker | Open after a threshold of failures, retry after a cool-off | Keeps one sick system from taking the store down |
| Fallback value | Defined per call, in writing, before build | “It errors” is not a fallback |
| Idempotency key | On every write to the ERP | Duplicate order submission is the most expensive bug in B2B |
| Logging | Request id, duration, outcome, per call | Otherwise you are debugging by anecdote |
Write the fallback into the acceptance criteria. The question “what does the buyer see when the ERP is unreachable” should have an answer approved by the merchant, not invented by a developer at 2am during a peak week.
The third-party script budget
The other half of the problem arrives through the tag manager, and it is usually invisible until a Core Web Vitals report turns amber. Hyvä’s own documentation names it: loading third-party scripts synchronously in the head is the single biggest INP problem on most Magento storefronts.
Give the client side a budget the same way you give the server side one:
| Script category | Typical weight | Loading rule |
|---|---|---|
| Tag manager container | 50 to 150 KB, plus every tag inside | Load after first paint, audit the tag list quarterly |
| Chat and support widget | 100 to 400 KB | Facade first, load the real widget on click |
| Reviews and ratings | 40 to 120 KB | Server render the summary, defer the full widget |
| Personalization and A/B testing | 30 to 200 KB | Load early only for the specific test, remove when the test ends |
| Heatmaps and session recording | 50 to 150 KB | Sample a percentage of traffic, never all of it |
| Consent management | 30 to 80 KB | Required early, so pick the lightest option that satisfies counsel |
Two habits matter more than any single tool choice. Audit the tag manager on a schedule, because containers accumulate tags that outlived their campaign. And require every new script to name its owner and its removal date, because scripts with no owner never get removed.
Acceptance criteria before an integration is “done”
Run these before sign-off. Each has a pass or fail answer.
- Category and product pages still return from full page cache for guests, verified by cache headers, not by feel.
- A logged-in buyer sees correct pricing after hydration, and the hydration call is batched, not per product.
- Layout shift measured on a category page stays under 0.1 with personalized data loading.
- Every live call has a timeout, a fallback, and a log line with duration.
- The ERP can be switched off in staging and the store still sells, with the agreed degraded behavior.
- Order writes are idempotent, proven by replaying the same submission twice.
- Field data, not lab data, is checked a week after launch for LCP, INP, and CLS.
That last one separates teams that fix Core Web Vitals from teams that fix Lighthouse. If your field numbers are the problem, the diagnosis path in our guide to Magento PageSpeed under 40 and what a Hyvä migration fixes applies directly.
What to render when the back office is down
Decide these in advance, per surface:
- Catalog page, pricing unavailable: show last synced price with no visible warning, or show “sign in for pricing” if that is already the pattern. Do not show a spinner that never resolves.
- Product page, stock unavailable: show the last known band. Never show “out of stock” as the failure default, because that is a sale you decided not to make.
- Cart, price mismatch: recalculate at checkout and tell the buyer clearly if a line changed. Silent corrections are worse than visible ones.
- Checkout, freight quote unavailable: fall back to table rates or accept the order with shipping quoted after, if the merchant approves that policy.
- Order submission, ERP unreachable: accept and queue the order in Magento. Never lose it at the browser.
Frequently asked questions
Does a Hyvä migration fix my ERP integration performance?
No. Hyvä replaces the frontend rendering layer. If your product page waits on a live ERP price call, the page still waits after the migration, and the wait is now the largest remaining number. The migration is what makes that integration cost visible, because everything else got faster.
Can I show real-time inventory on a Hyvä storefront?
Yes, with a definition of real time that your systems can honor. Synced quantities refreshed every few minutes, rendered as availability bands, satisfy nearly every buyer. Per request live counts on catalog pages are the pattern that reliably breaks under load. Reserve genuinely live checks for the add to cart or checkout step, where the stakes justify the call.
Where should customer-specific prices be rendered so caching still works?
Outside the cached HTML. Render the page publicly with sized placeholders, then hydrate through Hyvä’s combined section data or a single batched endpoint after paint. Adding your values to the existing section data payload avoids a second round trip, and Hyvä’s combined-object model means you are not managing per-section subscriptions.
How many third-party scripts is too many?
Judge by main thread time, not count. If scripts you did not write account for more than roughly a fifth of total blocking time on a mid-tier phone, you have a budget problem. In practice, chat widgets and tag manager sprawl are the two items that produce the largest single improvements when they are deferred or trimmed.
The short version
Speed is not a property of a theme, it is a property of a system. The frontend work sets your ceiling and the integration layer decides how much of that ceiling you keep. If you want that layer reviewed against your actual ERP and your actual tag stack, we do this work as a Hyvä development partner and as a Magento and Adobe Commerce team that has shipped B2B integrations for merchants with real catalogs and real order volume. Our technology partner network covers most of the payment, ERP connector, and personalization vendors you are likely to be running.
We also build on Shopify and Shopify Plus, Shopware, and BigCommerce, which matters here for one reason: the integration rules above are platform independent, and we will tell you honestly when your constraint is the platform rather than the plumbing. More about how our team works, or start at Bemeir. We build it, you sell it.





