Site SEO AI Auditby Internet Solutions

hreflang on JavaScript and Headless Sites: What Can Go Wrong

30 Ogos 20267 min bacaanSEO antarabangsa
hreflang on JavaScript and Headless Sites: What Can Go Wrong

Short answer: On JavaScript-heavy and headless sites, hreflang, canonical tags, the lang attribute and even translated content are often added in the browser after the page loads. Search engines may render JavaScript, but not always immediately, and some crawlers do not render it at all. Put hreflang, canonicals and lang in the initial server-rendered HTML, give every language its own URL, avoid switching languages on the client without changing the URL, and test both the raw and the rendered HTML.

Why JavaScript complicates international SEO

Traditional websites send a complete HTML document for each URL: head tags, content and links are all there when the crawler receives the page. Many modern sites work differently. A single-page application may send an almost empty HTML shell, and JavaScript then fetches data, renders the content and updates the head. Headless set-ups combine a content system with a separate front end, and how much HTML is prepared on the server depends on how the front end is configured.

For international sites, this matters because the key language signals all live in the head or in the URL: hreflang links, canonical tags, the lang attribute and, of course, the translated text. If those signals exist only after JavaScript runs, their visibility depends on whether and when a crawler renders the page.

Google can render JavaScript and generally processes rendered content, as described in its JavaScript SEO basics. But rendering can happen later than the initial crawl, and other search engines and many AI crawlers render little or no JavaScript. Relying on client-side rendering for language signals is therefore a risk you do not need to take.

Problem 1: hreflang injected by JavaScript

Some front-end frameworks manage head tags through a component that updates the document after the app starts. If hreflang is added this way and the server sends no hreflang in the initial HTML, crawlers that do not render JavaScript see no alternates at all, and Google sees them only after rendering.

A subtler version of this problem is a mismatch: the server sends one set of hreflang tags, and JavaScript replaces or adds others. Search engines may then see two different clusters for the same page, depending on whether they look at the raw or the rendered HTML.

The fix is to render head tags on the server. Most frameworks support server-side rendering or static generation, where the head, including hreflang and canonicals, is part of the HTML sent for each URL. Alternatively, move hreflang into XML sitemaps, which do not depend on page rendering at all.

Problem 2: language switching without URL changes

Single-page applications sometimes switch languages entirely on the client: the visitor clicks “Deutsch”, the app loads German strings and re-renders the page, and the URL stays the same, or changes only in a hash fragment such as #de.

For search engines, this means there is only one URL, and it contains whichever language the server or the app shows by default, usually English. The German version has no URL of its own, cannot be indexed separately and cannot be listed in hreflang. Hash fragments do not help, because search engines generally ignore everything after the # when identifying a page.

Every language version needs a real URL, such as /de/produkte/, that returns German content when requested directly, without any prior clicks, cookies or stored preferences.

Problem 3: the wrong lang attribute and content on first load

Many JavaScript apps render a default language on the server and then switch to the visitor’s language in the browser, based on a cookie, stored preference or browser setting. Crawlers usually have no cookies and send no language preference, so they receive the default. If the app also sets the lang attribute only on the client, the raw HTML for a German URL might say lang="en" and contain English text.

Check that the server renders the right language, content and lang attribute purely from the URL. Preferences and detection can suggest a different version to human visitors, but they should never change what a language URL returns.

Problem 4: links that crawlers cannot follow

Language switchers and internal links in JavaScript apps are sometimes implemented as buttons or elements with click handlers instead of real links. Crawlers discover pages by following a elements with href attributes; they do not click buttons.

Client-side routers also make it easy to create URLs that work when you navigate within the app but fail when requested directly. If /de/preise/ loads correctly after clicking through from the home page but returns a 404 or the English home page when opened in a new tab, crawlers will see the broken version. Test every language route by requesting it directly from the server, with no prior navigation.

Problem 5: rendering errors and timeouts

Even when a crawler renders JavaScript, rendering can fail: an API that returns an error for crawlers, a script blocked in robots.txt, a translation file that loads slowly or an app that waits for a consent click before showing content. When rendering fails, the crawler sees an empty or partial page, possibly without any language signals.

Make sure translation files, API endpoints and scripts needed for rendering are not blocked by robots.txt, respond quickly and do not depend on cookies or consent to return content.

Rate limits and bot protection deserve special attention. Some sites protect their APIs from automated traffic, and in doing so they also block the requests a search engine’s renderer makes while building the page. The visible symptom is often nothing at all in a browser, because human visitors are allowed through, while crawlers receive error responses from the API and render an empty template. Check your API and firewall logs for blocked requests from search engine crawlers, and verify crawler identity properly rather than blocking all automated traffic.

How to test what crawlers see

Testing a JavaScript site means comparing two versions of each page:

  1. Raw HTML: request a language URL with a command-line tool or view the page source (not the inspector). Check that hreflang, canonical, lang and main content are present and correct.
  2. Rendered HTML: use URL inspection in Search Console and look at the rendered HTML and screenshot. Check that nothing changed for the worse, such as a different language or missing hreflang.
  3. Without cookies and language headers: request each language URL in a clean session and with no Accept-Language header, as crawlers do.
  4. At scale: crawl the site and compare results for templates, since JavaScript issues usually affect whole page types.

Keep a short test list of URLs for each template and language, for example a home page, a category, a product or article and a contact page per language. Run the same raw-versus-rendered comparison on that list after every front-end release. Framework upgrades and changes to head management are the most common moments for server-rendered hreflang to disappear without anyone noticing.

A safe architecture for multilingual JavaScript sites

Element Safe approach Risky approach
Language URLs Path per language, such as /de/ Same URL, language in state or hash
Rendering Server-side rendering or static generation Client-only rendering of content
hreflang and canonical In server HTML or in sitemaps Injected by JavaScript after load
lang attribute Set on the server from the URL Changed in the browser
Links and switcher Anchor elements with href Buttons with click handlers
Language detection Banner suggestion only Automatic switch or redirect

Checking your site

Site SEO AI Audit crawls a site the way a search engine does and checks whether content needs JavaScript to be read, as part of its AI visibility checks, alongside hreflang return links, broken language versions, x-default and lang attributes in its Languages area. On JavaScript sites, that combination quickly shows whether language signals exist in the HTML crawlers receive. The first audit is free.

Related reading

The bottom line

On JavaScript and headless sites, the question is not whether hreflang exists, but whether it exists in the HTML crawlers receive first. Give every language its own URL, render content, hreflang, canonical and lang on the server or put hreflang in sitemaps, use real links, never switch languages without changing the URL, and test raw and rendered HTML side by side.

FAQ

Does Google read hreflang added by JavaScript?

Google can process rendered HTML, so it may see JavaScript-added hreflang, but only after rendering, which can be delayed. Other search engines and many AI crawlers may not see it at all, so server-rendered hreflang is safer.

Can I use hash URLs like #de for languages?

No. Search engines generally ignore the part after the hash when identifying a page, so all languages would share one URL. Use paths such as /de/ instead.

Is hreflang in a sitemap better for single-page apps?

It is often easier, because sitemaps do not depend on page rendering. The pages still need their own URLs and server-rendered content in the right language.

How do I see what Googlebot rendered?

Use the URL inspection tool in Search Console, which shows the rendered HTML and a screenshot of the page as Google saw it.

Should my app detect the visitor’s language automatically?

Detection can power a suggestion banner, but it should not change the content or language of a URL. Each language URL should always return the same language.

#hreflang#International SEO#JavaScript SEO#Multilingual SEO
Semak laman web anda sendiri — percuma.Setiap isu SEO di laman anda — dan cara tepat membaikinya.
Mula percuma

Lagi dari blog

Semua artikel →
Internet Solutions

Lagi daripada pasukan kami

Dibina oleh Internet Solutions. Cuba produk kami yang lain — setiap satu menjimatkan masa anda dengan cara berbeza.

internet-solutions.net ↗
Site SEO AI Audit
Gambaran Keseluruhan Privasi

Laman web ini menggunakan kuki supaya kami dapat memberikan pengalaman pengguna yang terbaik. Maklumat kuki disimpan dalam pelayar anda dan menjalankan fungsi seperti mengenali anda apabila anda kembali ke laman web kami serta membantu pasukan kami memahami bahagian laman web yang paling menarik dan berguna bagi anda.