Urgent.News

What's breaking now, across thousands of outlets.

Tech

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.

Read the original at dev.to →

More in Tech

What a Kubernetes controller actually does when you break something

⚡ TL;DR Four things about controller mechanics are widely half-understood: what Reconcile receives, where its work comes from, what a periodic resync is, and what a predicate turns off.

  • Kubernetes controllers maintain desired and observed state consistency
  • Reconcile function executes process without receiving a diff
  • Watch, Informer cache, Work queue, and Predicates are four mechanisms

McKinley 1.0

Crackerjack new Mac app for creating and editing custom SF Symbols , from developer Amy Worrall: McKinley is an all-in-one studio for drawing and annotating SF Symbols.

Our regex found 199 records in a 1,723-record corpus and reported no errors

We maintain a corpus of 456 role-specific resume examples in TypeScript. Someone asked me what a good bullet point actually looks like, and rather than answer from taste I decided to measure the thing…

  • Regex algorithm identified 199 job descriptions in 1,723-record corpus
  • Twelve percent of data overlooked by regex script
  • Formatting issue corrected, expanding corpus to 1,723 description blocks

More from Monday 7 September →