How client-side rendering works

Under client-side rendering the server returns minimal HTML — in practice an empty <div id="root"></div> and a link to the JS bundle. The browser downloads the bundle, executes it, and only then does the application build the DOM, request data through the API and draw the interface.

The typical flow for an e-commerce single page application:
1. The browser receives HTML (roughly 1–5 KB) plus a link to the JS bundle
2. It downloads and parses the bundle (200–500 KB and up)
3. The application initialises and requests data — catalogue, recommendations, profile
4. The API responses arrive and the page renders

The visitor sees content only at step 4, which creates a noticeable delay on the first load, measured as first contentful paint.

CSR in e-commerce: strengths and limits

Aspect CSR SSR
First load Slower (waits for JS) Faster (HTML is ready)
Navigation between pages Fast, no reload Needs a new server request
SEO Problematic without extra work Natively compatible
Personalization Delayed until JS initialises Available immediately in the HTML
Core Web Vitals (LCP, CLS) At risk from async loading Better by default

Personalization and recommendations in a CSR architecture

Recommendation widgets under CSR load after the application initialises — they are not in the original HTML. That means:

  • Layout shift: the “similar products” block appears 500–1,500 ms after the rest of the content and pushes the page around. The fix is to reserve the space in advance with a skeleton placeholder.
  • Delayed personalization: for a few seconds the visitor sees a page with no personal content. On a slow connection that is obvious.
  • Initialisation order: make sure the platform’s SDK initialises at the right point in the component lifecycle rather than blocking the main thread.

Tip: for SEO-important pages such as categories and product cards, consider a hybrid — Next.js or Nuxt with server-side rendering for the first load and client-side rendering for subsequent navigation. It combines the strengths of both.

Common mistakes

Shipping everything in one bundle. Split it into chunks through code splitting — the category page should not be waiting for the basket’s code.

Letting external scripts block rendering. Analytics and personalization tags without async or defer hold up the first paint. Every external script should be asynchronous.

No skeleton states. Empty blocks that fill in a second later create layout shift and read badly to the visitor. Put a placeholder animation where the widget will be.