Server-side rendering on Adobe Commerce: making product data visible to Google and AI
How Adobe Commerce renders PDPs server- vs client-side, why that hides enriched product data from crawlers and AI agents, and how to check and fix it.

Enriching a product with complete attributes, specs, and use-cases only pays off if that data actually lands in the HTML a crawler or AI agent receives. On Adobe Commerce, whether that happens depends entirely on which storefront architecture is serving the page — Luma, PWA Studio, or the newer Edge Delivery Services storefront all handle this differently. This guide covers how to check what's really being served, and how to make sure enriched product data is server-rendered rather than trapped behind a client-side render step.
Three storefront architectures, three rendering behaviors
Adobe Commerce doesn't have one rendering model — the storefront you've deployed determines whether product data ships in the initial HTML response.
Luma (default theme). Luma is a server-rendered PHP theme: layout XML and .phtml templates assemble the page on the server, so most of the DOM — including price, name, and description — is present in the raw HTML response before any JavaScript runs. Luma uses RequireJS and Knockout.js for interactive widgets (image gallery, swatches, add-to-cart), but the core product content is not gated behind that JavaScript. The catch: Luma's out-of-the-box structured data is thin. It emits partial schema.org microdata via hardcoded meta tags in a handful of templates, not a complete JSON-LD Product object — so even though the content is server-rendered, the machine-readable markup usually needs a custom module or extension to be complete.
PWA Studio (headless storefront). PWA Studio's UPWARD server returns a server-rendered HTML shell — the app frame, not the product content — and then a React bundle fetches product data over GraphQL and renders it client-side. Adobe's own PWA Studio documentation is direct about the SEO tradeoff this creates: "When a search engine crawler processes a page, it indexes the initial HTML response from the server," and while "some crawlers, such as Googlebot, have the ability to execute JavaScript to simulate client-side rendering," that isn't guaranteed or immediate for every crawler or AI fetcher. Adobe's guidance is to use UPWARD's server-side rendering for the pages where indexing matters most — home, category, and product detail pages — rather than relying on the client-rendered default.
Edge Delivery Services storefront (Adobe Commerce Optimizer / newer composable storefronts). This is Adobe's current push for PDP rendering done right by default: product pages are folder-mapped virtual pages built from a single template, and the metadata that matters for indexing — title, description, Open Graph tags, and JSON-LD product schema — is rendered server-side into static HTML, ahead of the client-side JavaScript that handles interactivity. A serverless function watches Catalog Service for product changes and calls the Edge Delivery preview API to regenerate that static HTML, so enriched attributes propagate into the served page without a full rebuild.
The practical takeaway: know which of these three you're running (it's common to have Luma on legacy sites, PWA Studio on a 2019–2023 headless build, or EDS on a newer Commerce Optimizer rollout), because the fix is different for each.
Why client-only rendering is a problem for crawlers and AI agents
Google's own JavaScript SEO documentation describes a two-wave process: Googlebot indexes whatever is in the initial HTML immediately, then queues the page for a second pass where JavaScript is executed and rendered — and that second wave can lag by "seconds to days or even weeks" depending on rendering queue load. Two consequences matter for a PDP:
- Freshness lag. If price, availability, or a new attribute only exists after client-side rendering, a re-crawl of an already-indexed page may not pick up the change for days.
- AI agents often don't render at all. Many AI shopping and answer-engine crawlers fetch raw HTML and do not execute JavaScript the way Googlebot's renderer does. If your enriched specs, identifiers, and use-case copy only exist after a GraphQL fetch resolves in the browser, those agents see an empty shell — not the product.
Google's guidance is explicit that "critical meta tags like title, meta description, canonical, hreflang, and Open Graph tags must be in the server-rendered HTML rather than injected by JavaScript" — and the same logic applies to the product's core facts and its JSON-LD.
Making sure product data is in the server-rendered HTML
Regardless of storefront, the target is the same: the raw HTML response (before any JS executes) should contain the product name, price, availability, key specs/attributes, and a complete JSON-LD Product block.
- On Luma: confirm your theme or an installed module outputs full JSON-LD, not just partial microdata. A minimal, complete block added via layout XML (referencing a block that reads the product's attributes, including
sku,gtin/mpnif populated,offers.availability, andaggregateRatingwhere reviews exist) looks like:
<referenceContainer name="content">
<block class="Vendor\StructuredData\Block\ProductSchema"
name="product.jsonld"
template="Vendor_StructuredData::product/jsonld.phtml" />
</referenceContainer>
<script type="application/ld+json">
{
"@context": "https://schema.org/",
"@type": "Product",
"name": "Example Product Name",
"sku": "EX-1001",
"gtin13": "0012345678905",
"description": "Full enriched description text, not a truncated snippet.",
"offers": {
"@type": "Offer",
"priceCurrency": "USD",
"price": "129.00",
"availability": "https://schema.org/InStock"
}
}
</script>
- On PWA Studio: move PDP rendering onto UPWARD's server-side path (FileResolver or TemplateResolver) rather than letting product content resolve purely on the client after the shell loads. At minimum, ensure the product's title, meta description, canonical URL, Open Graph tags, and JSON-LD are injected into the server response — not appended by the React bundle after a GraphQL round trip.
- On Edge Delivery Services: this is largely handled by the platform's template + preview-API model, but confirm your enrichment pipeline's attribute updates are actually reaching Catalog Service in a way that triggers the re-render — an attribute sitting in a PIM or metafield that never syncs to Catalog Service won't make it into the regenerated static HTML.
How to validate
Don't trust the rendered browser tab — check what the server actually sends before JavaScript runs.
# Fetch the raw server response, no JS execution
curl -s -A "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)" \
https://www.example.com/catalog/product/view/id/1234 | less
Search that output for the product name, price, and a JSON-LD script block (a script tag with type="application/ld+json"). If they're missing but visible in the browser, the data is client-rendered only.
- View-source vs. rendered DOM: open the PDP, use "View Page Source" (Ctrl/Cmd+U) for the raw HTML, then compare it against the browser's Inspector "Elements" tab (the rendered DOM, post-JavaScript). If the price or description appears in Elements but not in View Source, it's arriving via client-side JavaScript.
- Google's Rich Results Test: run the PDP URL through Google Rich Results Test — it renders the page the way Googlebot does and reports whether it found a valid
Productstructured data block, which flags both missing JSON-LD and JSON-LD that only appears after client rendering completes. - Disable JavaScript: in Chrome DevTools, use Cmd/Ctrl+Shift+P → "Disable JavaScript," then reload the PDP. Whatever content survives is what most non-Googlebot crawlers and AI agents will see.
Verified as of July 2026 against Adobe's PWA Studio content-rendering documentation, the Adobe Commerce Edge Delivery Services announcement, and Google Search Central's JavaScript SEO guidance; Adobe Commerce Optimizer and Edge Delivery Services are under active development, so confirm current behavior against your specific storefront version before shipping.
None of this matters, though, if there's nothing rich to put in that server-rendered HTML in the first place. Anglera continuously enriches product attributes, specs, use-cases, and identifiers behind the scenes — it plugs into whatever PIM or commerce platform already holds your data — so the JSON-LD block and server-rendered fields above have complete, current facts to draw from rather than a handful of manually maintained fields.
