Our site served every URL the same 3,780 bytes, and Google believed it
Checked with a Googlebot user agent one morning: every single URL on our site returned the same 3,780-byte shell. Same <title> , zero <h1> , zero body text. The homepage, a blog post and a product page were byte-identical before JavaScript ran. Search Console agreed with the crawler rather than with us. Of 741 URLs, 116 had earned a single impression in 28 days, and a landing page that had been…
Our site served identical 3,780-byte URLs for every page, and Google treated this as if it were correct. A single page, which had been live for five months, was still marked as unknown to Google.
Upon investigation, it became clear that Google did render JavaScript, but rendering was a separate process that did not always get the priority it needed. Of the 741 URLs, only 116 had received a single impression in 28 days, indicating that Google was not spending much budget on rendering these pages.
The issue was not just about rendering, but also that the 741 URLs were duplicates before rendering. By having a post-build script inject a real head into each HTML file, including title, description, canonical, robots, Open Graph, and Twitter tags, we ensured that the static markup matched the rendered markup. This prevented any risk of cloaking and made sure that any duplicate content signals were not passed to the crawler.
However, we learned a few hard lessons in the process. First, React Helmet async can delete tags you didn't mark. Our shell had static meta tags in index.html, but Helmet re-inserted its own tags on mount, leading to duplicate descriptions that crawled and indexed instead of the static ones. The fix was to mark the tags Helmet emitted with `data-rh="true"`.
Second, our script read the sitemap and relied on it for all URLs, failing to regenerate the sitemap when needed. This caused a silent omission of a specific route from the prerendered set, resulting in Google indexing the homepage's canonical tag instead of the individual pages.
Lastly, a dead ternary statement in the code resulted in a route falling through to a generic fallback body, which lacked important ranking terms. It's crucial to grep your codebase for `? null : null` to catch such issues early.
In the end, the key takeaway was to verify with a crawler user agent and ensure that static head, dynamic body, and source of truth are all aligned. The approach of serving a head-only page was not sufficient, as it excluded URLs without prerendered files and caused them to fall back to the homepage.
Written by urgent.news from Dev.to's reporting — not their text. Machine-written — may contain errors; check the original before relying on it.