Technical SEO

Client-Injected SEO Tags Are Absent From the HTML

A React SPA that sets its meta tags with a client-side head manager delivers HTML with no title, no description, and no Open Graph tags. The tags appear only after JavaScript runs. Anything that reads the response without executing scripts sees an untitled page.

· The RECNOS Engineering Team

The tags are real, just late

A client-side head manager is not broken. It sets the document title, the description, and the Open Graph tags correctly, and a browser running the application sees all of them.

The problem is what arrives over the wire. The server returns a minimal HTML shell with a root element and a script tag. Every meta tag is injected by React after the bundle executes.

What does not execute JavaScript

Several classes of consumer read the raw response and stop there. For all of them, the page has no title and no description — a link shared to a messaging app previews as a bare URL rather than a card.

  • Social unfurlers, which generate link previews from the initial HTML
  • Crawlers that fetch the response without rendering it
  • Any client without JavaScript enabled
  • Tools that inspect a URL's metadata, including most link checkers

Rendering crawlers mostly cope, and that is the trap

Major search engines do execute JavaScript, so the tags are eventually seen. This is why the problem goes unnoticed: a site check in a browser-based tool shows everything working.

The costs are less visible than a missing title but real. JavaScript rendering is deferred, sometimes to a second pass, so indexing is slower and less predictable. Anything that fails during rendering — a blocked script, a runtime error, a timeout — leaves the page indexed without its metadata.

The fix is to move the tags server-side

The reliable fix is to emit the tags in the server response rather than injecting them. In a React SPA that means rendering the head on the server or prerendering the routes, so the title and description are in the HTML the server returns.

The project had both patterns in the same repository: an authenticated application using client-side injection, and a public site on a server-rendering framework emitting its metadata per route. The public surface — the one that needs to be crawled — was the one that had it right.

How to check it yourself

Fetch the page and look at the response without running scripts. If the title and description are not there, neither are they there for anything that does not execute JavaScript.

curl -s https://example.com/page | grep -i '<title>\|og:title'

The project this came from