Introduction
Open the page in a browser and the product name and description are right there — yet it barely shows up in search results. When SEO stalls on a headless EC site, a large share of the cause is this: the HTML the server returns first doesn't contain the actual content.
The gap is hard to spot during development, and it tends to appear most on sites that have worked hardest on loading speed and eliminating visual flicker.
This article explains how, on an EC site selling motorcycle gear, I used server-side rendering (SSR — assembling the HTML on the server before returning it) to supply the information that wasn't reaching crawlers (the programs search engines use to read pages). The screen looks exactly the same afterwards; only how the page reaches search engines changes.
Why the Initial HTML Ends Up Empty
Prioritizing Smooth Rendering Removes Content
Text and images jumping around the instant a page opens is one of the more disliked experiences on the web. The standard way to avoid it is to show a gray skeleton — just the outline — while loading, and only draw the real thing once the screen width and device have been determined.
The problem is when that "wait until we know" condition also applies to server-side rendering. Then the HTML the server returns contains nothing but the skeleton. Screen width is something only the browser knows, so on the server the answer is permanently "not yet determined." The smoother the rendering, the less information ends up in the initial HTML.
Empty HTML Gets Saved to the Cache
The impact grows when this is combined with ISR (a mechanism that caches generated HTML and reuses it for a set period). The empty HTML gets stored in the cache, and every crawler that arrives afterwards receives the same empty page.
Human users see everything fine once JavaScript runs, so nothing looks wrong on screen. Crawlers, on the other hand, may look at the empty HTML and move on without waiting for JavaScript. That's where "visible on screen, nonexistent to search engines" comes from.
The server returns a skeleton. Crawlers may never read the content
Headings, descriptions, and links are present from the start and reliably read
Put simply, the whole difference is whether the first HTML to arrive has anything in it.
Choosing What to Deliver to Crawlers
The Product Heading and Description
The non-negotiables are the h1 (the single most important heading on a page) and the product description. The h1 tells crawlers what the page is about, so it's always output on the server. The description is the same body text users see, included in the HTML — trimmed to roughly the first 2,000 characters when it runs long.
Skip this and, however polished the design is, search engines may decide they can't tell what the page is. It's an unglamorous detail, and the first one to get right.
Internal Links to Related Products
The other priority was internal links to related products and items used alongside them. Internal links are the routes crawlers use to move through a site, and they also signal how pages relate to each other. Server-rendering the related-products block makes it easier for crawlers to travel between product pages.
The product name, the link to its page, and the brand name. Putting just those three in the initial HTML increases both the content on each page and the number of paths through the site.
The server receives a request for a product page
Product details and related products are fetched together on the server
Generate HTML containing the heading, description, and internal links
Crawlers and users alike receive HTML with real content in it
Take those four steps and content-bearing HTML arrives without waiting on anything in the browser.
Including Content in the HTML Without Showing It
Some information you want crawlers to have but don't want on screen. That's what the sr-only technique is for. It was originally a way to place supplementary text for screen readers used by people with visual impairments; CSS shrinks the display area to almost nothing, while the HTML itself is perfectly normal. Crawlers and screen readers both receive it as usual.
Output these from the skeleton stage onward and a crawler that reads the page before the screen-width check finishes still gets HTML with content. Once the check completes, the visible elements take over.
Never Hide Text That Differs from the Screen
Hiding text that differs from what's displayed is treated as cloaking — showing search engines one thing and people another. So there's exactly one operating rule: any text output through sr-only must match what appears on screen. How the description is trimmed, how related products are ordered — all of it lines up with the visible version.
Keeping Exactly One h1 per Page
Avoiding Duplicates with Category-Specific Pages
The fiddly part of the implementation was handling the h1. As a rule, a page has one h1. But headless builds often give categories their own hero image and layout, and some of those come with an h1 of their own. Add an SEO h1 mechanically and certain pages end up with two.
So I made it conditional: pages with a visible main heading keep theirs, and only pages without one get a hidden heading to fill the gap.
Either way, the page always ends up with exactly one h1.
Separating the Display Label from the Search Title
Breadcrumb names (the navigation showing Home > Category > Product) follow the same principle. A title written for search results tends to be long and packed with search terms, and using it as a navigation label makes the screen harder to read.
So the display label and the search title are stored separately, and breadcrumbs, structured data, and the link back to the category from a product page all use the display label. The point is to avoid three different names for the same place.
Category Page SSR Made the Biggest Difference
Putting the First 24 Items in the HTML
Even more effective than product pages was SSR on category listing pages. Category pages are where browsing starts, and they're the route crawlers take toward individual product pages. If they return empty HTML, the product pages beyond them become harder to discover.
What gets output is the category heading, the lead paragraph describing the category, and for the first 24 items: product name, an excerpt of the description, and a link to the product page. That count of 24 matches the number of products shown when the page first opens.
Using the Same Values Visible and Hidden
The description excerpt uses the same 120-character trim as the visible cards. It's a small detail, but being strict about using identical values for the visible and hidden versions makes later reviews much easier to reason about.
"All we're doing is putting on-screen content into the HTML earlier." Hold to that one line and there's no room to suspect cloaking. The goal is to stay in a position where you can honestly say no separate content was prepared for search engines.
Conclusion
Most cases of crawlers not receiving content on a headless EC site trace back to implementation choices made for a smoother display leaving the initial HTML empty. The fix is to server-render the heading, product description, and internal links, and to use sr-only for anything you don't want on screen — while making sure the text you output always matches what's displayed.
The strength of this approach is that it improves how the page reaches search engines without changing the look at all. Next comes structured data, which adds meaning to the information you've delivered, and sitemaps, which tell search engines where the entry points are.
SEO Design for Headless EC — SSR Visibility, Structured Data, Sitemaps
The big picture of SEO measures for headless EC.
Implementing JSON-LD Structured Data (Products & Breadcrumbs)
How to add meaning to the content you output and turn it into rich results.
Generating and Caching Dynamic Sitemaps and robots.txt
Sitemap generation that follows products as they change, plus URL normalization.