Skip to main content

Pre-rendering for Ecommerce

Pre-rendering for ecommerce - product and category SEO

Pre-rendering for ecommerce: how to make product, category, and selected facet URLs indexable without serving stale price, stock, or schema markup to crawlers.

Updated

Before vs after

Before vs after - typical ecommerce results

Median ranges from JavaScript-heavy ecommerce deployments with roughly 10k-100k SKUs. Results depend on URL governance, purge discipline, and how much thin facet inventory stays indexable.

Metric
Before pre-rendering
After pre-rendering
Rich result eligibilityIntermittent (hydration race)Stable on first crawl
Product page indexing60-70% indexed90-97% indexed
Stale-price incidents in crawler HTMLRecurring during promotionsRare after purge automation
Category CWV (LCP)3.8s1.4s
Organic product-page sessionsBaseline+180% at 6 months

Product schema has to land in the first HTML

Product structured data is not a decorative extra on ecommerce pages. `Offer`, `AggregateRating`, `Review`, availability, and price currency determine whether Google can trust the page for product-rich results. If JSON-LD appears only after hydration, the first crawl often sees a shell, then the page spends days or weeks waiting for a second render pass.

Pre-rendering changes that sequence. The crawler gets the finished DOM on request one, including the visible price, stock message, review summary, and JSON-LD. That does not guarantee rich results, but it removes the most common technical blocker: missing product data in the initial HTML. If the team is still deciding between an application rewrite and a crawler layer, compare the trade-offs in dynamic rendering vs SSR.

One quotable rule matters here: if a shopper can see the price and rating after page load, Googlebot should be able to see the same values in the first HTML response. Anything weaker leaves rich-result eligibility to queue timing rather than site quality.

Category, product, and facet URLs should never share one policy

The biggest ecommerce mistake is treating product pages, category pages, brand pages, and facet combinations as one crawl class. They do not carry the same business value, duplicate risk, or update frequency. A product page with a 4.7 rating and live inventory is a revenue page. A category page is a discovery hub. A `/shoes?color=black&size=11&sort=price-asc` URL may be useful for users but still a weak indexation target.

In practice, category pages deserve stable snapshots because they consolidate internal links and broad demand. Product pages deserve the shortest freshness window because they hold offer data. Most facet combinations deserve either no snapshot at all or a canonical relationship back to the parent category. Teams with large SKU counts should read this page alongside large sites (100k+ pages) before deciding what actually earns a render slot.

The catch is simple: if every URL template gets equal render priority, the catalogue usually protects the least important pages first.

Faceted navigation is where crawl budget goes to die

Every filter combination can generate a new URL. Five facets with ten values each create 100,000 states before pagination, sorting, or locale are added. Most of those URLs do not deserve independent indexation. They split crawl demand, bloat sitemaps, and make the render queue chase low-intent combinations while core products wait.

Pre-rendering works best when paired with an explicit canonical model. Snapshot only the facet states that map to real search demand, such as a high-volume brand-plus-category combination or a stable sale landing page. Route thin combinations back to canonical category URLs with consistent `rel=canonical`, noindex, or parameter handling rules. On catalogue-heavy stores this starts to resemble the marketplaces pattern much sooner than teams expect.

What most guides skip is that render waste and crawl-budget waste are usually the same problem wearing different names. If the queue is full of low-value filtered URLs, the crawler is learning the wrong site map.

Price and stock freshness determine TTL

Ecommerce freshness is measured in hours, sometimes minutes. A flat TTL of 24 hours is too long for fast-moving inventory, flash sales, or merchant-center-sensitive pricing. The result is predictable: crawlers index yesterday's price, users land on today's price, and trust starts to erode even if the app itself is technically correct.

A workable default is template-based. Product pages often need 15-60 minute TTL plus event-driven purges when price, stock, variant availability, shipping promise, or review count changes materially. Category pages can usually live at 2-6 hours because they summarize inventory rather than define a single offer. Evergreen brand or buying-guide pages can stretch to 24 hours or longer. The policy belongs in pre-render cache headers, not in a single global cache fallback.

Another quotable rule: on ecommerce sites, stale HTML is not a cosmetic bug. It is a ranking, trust, and conversion bug because price and availability are part of the document's meaning.

What to pre-render first when the catalogue is too large

Start with the pages that are already closest to winning. That usually means revenue-driving product templates, top categories, high-impression products from Search Console, and categories with link equity or strong conversion rates. Do not begin with the deepest long-tail filter combinations just because they exist in the URL graph.

A practical rollout sequence for a 50k-SKU store is: top 5,000 products first, then the top 100 category pages, then a short allowlist of search-driven facet pages, then everything else only after freshness and purge behavior are stable. If the catalogue is already above six figures, pair the rollout with JavaScript rendering cost and ostr.io vs Prerender.io so the SEO plan and the cost model stay aligned.

This page is for teams with a meaningful public catalogue and JavaScript-heavy templates. It is the wrong fit for stores that already serve complete server HTML, or for tiny catalogues where a framework-level SSR fix is cheaper than adding another operational layer.

What not to pre-render on ecommerce sites

Do not send internal search results, account pages, cart states, checkout, wishlists, postcode-specific delivery views, or one-off sort orders into the crawler cache. Those paths are user-state driven, operationally noisy, or poor long-term SEO assets. Indexable surface area should shrink as site complexity rises, not expand.

Variant URLs also need discipline. If color or size changes the product meaning enough to earn separate demand, give that variant a stable canonical URL and snapshot it intentionally. If the variant only swaps a picker state, keep one canonical product page and let the client handle the rest. The same principle applies to store-location selectors and session-specific pricing.

When teams ignore these boundaries, pre-rendering gets blamed for problems caused by weak URL governance. The service is not the issue. The real issue is letting every state masquerade as a page.

What changes operationally after launch

The SEO upside is only half of the project. Operationally, the team now owns a route policy, purge triggers, and a freshness budget by template type. Merchants care about stock and price accuracy. SEO cares about first-HTML completeness. Engineering cares about queue load, event fanout, and monitoring. Those concerns meet in one place: the render policy.

The clean setup has three inputs. Search Console and logs decide which templates deserve crawl priority. Commerce events decide when to purge. A routing layer decides which user agents receive the cached snapshot. If one of those three stays vague, stores either overspend on rendering or under-deliver on freshness. That is also why body-level links to technology and cache headers matter more here than generic platform advice.

Integration

Product page - render on demand with an event-driven cache

Trigger a cache invalidation whenever stock or price changes. The next crawler hit gets the fresh snapshot.

server/inventory-hooks.ts
typescript
import { purgeOstrio } from "@/lib/ostrio";
export async function onProductUpdated(productId: string) {
const urls = [
`https://yourdomain.com/p/${productId}`,
`https://yourdomain.com/p/${productId}/reviews`,
];
await purgeOstrio({ urls });
}
export async function onStockChanged(productId: string) {
// Only purge if stock crosses the 0 threshold (in stock ↔ out of stock)
await purgeOstrio({ urls: [`https://yourdomain.com/p/${productId}`] });
}
FAQ

Ecommerce pre-rendering — engineer questions

Usually yes, but treat that as a side effect rather than the main KPI. The crawler-facing HTML is cached and complete, so LCP and TBT often improve on SEO-critical templates. The business win is faster indexation and more reliable product markup, not just a prettier score.

Trigger a purge when stock crosses the key threshold that changes the page meaning, usually in-stock to out-of-stock or back again. Purging on every unit decrement creates queue noise. The goal is to refresh the snapshot when availability messaging, structured data, or buy-box eligibility actually changes.

Not for SEO alone. Pre-rendering can give crawlers the same finished HTML that SSR would provide, while leaving shopper traffic on the existing app. Keep SSR if you need request-time personalization, user-specific pricing, or framework-level reasons. For crawler visibility, pre-rendering is usually enough.

Pre-rendering preserves hreflang from the rendered DOM, but each locale still needs its own stable URL, canonical, and cache key. Do not assume one English snapshot can stand in for all locales. Snapshot each locale path separately and purge locale-specific pages when regional price or stock changes.

No. Most facet combinations are weak SEO assets and expensive render targets. Pre-render only the combinations with proven demand or clear merchandising value, then canonicalize or de-prioritize the rest.

Use event-driven purges tied to promotion start and end, price changes, and stock changes on priority products. A short TTL helps, but promotions are where TTL-only strategies usually fail. The safer pattern is short TTL plus explicit invalidation.

It is the wrong fit when the indexable catalogue is small, the site already serves complete server HTML, or the important content changes per user or postcode on every request. In those cases, SSR, static generation, or tighter URL pruning may be the cleaner answer.

Editorial trust

Written by ostr.io engineering team · Engineering Team. We build and run pre-rendering infrastructure for more than 200 engineering teams, which is where the numbers and code samples on this page come from.

Last updated . Editorial scope and review policy: About prerender.info.

Free tier includes 1,000 pages. Works on any framework.

Get pre-rendering for your site