Home›Academy›JavaScript SEO›Dynamic content

JavaScript SEO · Lesson 03 · Content

Dynamic content

How content added after the initial HTML is rendered and indexed, and which patterns hide content from search engines and AI crawlers.

05 JavaScript SEO11 min Read timeIntermediate Level

03 / Content

Dynamic content is any content added or changed by JavaScript after the initial HTML loads: product details fetched from an API, reviews injected by a widget, text inside tabs, or items that load as the user scrolls. Search engines can index much of it, but only when it is present in the rendered page without user interaction.

This lesson covers API-driven content, lazy loading, user interactions, JavaScript that modifies SEO elements, structured data injection, and personalization, with checks for each.

1. Types of dynamic content

TypeExampleIndexing risk
API-rendered contentProduct description fetched after loadMedium. Depends on the API responding in time
Lazy-loaded contentImages or sections loaded when scrolled into viewLow to high. Depends on the loading method
Interaction-gated contentText revealed only after clicking a tab or buttonHigh if the content is not in the DOM until clicked
Third-party widgetsReviews, comments, related productsMedium. Often loaded in iframes or late scripts
Modified SEO elementsTitle, meta robots, canonical changed by JavaScriptHigh when raw and rendered values conflict
Personalized contentLocation, login, or A/B test variationsMedium. Googlebot sees one version

2. Content behind user interactions

The renderer loads the page but does not click, type, hover, or scroll like a user. The key question is whether content exists in the DOM before the interaction.

Tabs and accordions

RiskyTab content fetched on clickThe DOM contains only the first tab until a click happens.
SafeAll tab content in the DOM, hidden with CSSThe renderer and search engines can read every tab.

Content hidden with CSS is still indexable. Content that does not exist until a click is not.

3. Lazy loading

Lazy loading delays offscreen resources to improve performance. It is safe when done with native browser features or observers that trigger in the renderer.

MethodCrawler friendly?Notes
loading="lazy" on img and iframeYesNative, and the src remains in the HTML
IntersectionObserverUsuallyGoogle's renderer uses a tall viewport, so content often loads
Scroll event listenersRiskyThe renderer does not scroll like a user
Image URL in data-src onlyRiskyWithout a fallback, the image URL may never be seen

Never lazy load the main hero image or above the fold content. It delays Largest Contentful Paint and gains nothing. The Images lesson covers image attributes in more detail.

4. JavaScript that changes SEO elements

Scripts often update the title, meta description, canonical, or meta robots tag after load. Google generally uses the rendered values, but conflicts create risk.

Raw noindex removed by JavaScript

Google may skip rendering when the raw HTML says noindex, so the page stays out of the index.

Canonical changed after render

Two different canonical signals weaken consolidation.

Generic raw title

A placeholder such as Loading or the site name appears in snippets or AI answers.

Status code masking

A soft 404 page returns 200 with a not found message rendered by JavaScript.

Put critical signals in the raw HTML

Title, meta robots, canonical, hreflang, and status codes should be correct in the server response. JavaScript can enhance a page, but it should not be responsible for telling search engines whether to index it.

5. Soft 404s in single-page apps

Client-side apps often return HTTP 200 for every route, then render a not found message when data is missing. Search engines may treat these as soft 404s or, worse, index empty pages. Fix this by returning a real 404 from the server, or by redirecting to a URL that does, and by adding a noindex in the raw HTML for error views. See the Status codes lesson.

6. Injected structured data

JSON-LD added with JavaScript or a tag manager can be read by Google after rendering, but it depends on successful rendering and is invisible to crawlers that do not run scripts. Product, Article, and FAQ schema is safest in the server response. Validate injected markup against the rendered page, not the source. Related issues: schema missing and schema invalid. The article on schema markup for AI explains its role in AI visibility.

7. Personalization, geolocation, and A/B tests

Googlebot crawls mostly from US IP addresses, without cookies, and without a logged-in session. Content that depends on location, login state, or a test variant may differ from what users see. Keep the core content and links the same for every visitor, avoid redirecting based on IP, and make sure test variants do not change canonical tags or block indexing.

8. Auditing dynamic content in SiteAuditLint

  1. Pick a unique phraseChoose a sentence from content loaded by JavaScript, such as a product description or review.
  2. Search the raw HTMLCheck whether the phrase exists in the initial response.
  3. Search the rendered HTMLRun a rendered crawl and confirm the phrase appears.
  4. Compare SEO elementsFlag titles, canonicals, and meta robots that differ between versions.
  5. Check thin rendered pagesPages with very little text after rendering may be failing to load data.

SiteAuditLint's custom source search can check every crawled URL for a phrase, element, or pattern, which makes this comparison fast across a whole site. Pages that render empty often appear under thin content.

9. Practical exercise: Test three dynamic elements

Choose three pieces of dynamic content on your site, such as reviews, tab content, and a product description, and test each one in the raw and rendered HTML.

Dynamic content checklist

0 of 8 tasks completed

Key takeaways

  • Dynamic content is indexable when it exists in the rendered DOM without interaction.
  • Content fetched only on click or scroll is at risk.
  • Native lazy loading is crawler friendly. Scroll listeners are not.
  • Critical signals such as meta robots and canonical belong in the raw HTML.
  • Single-page apps need real 404 status codes to avoid soft 404s.
  • Server-rendered structured data is more reliable than injected schema.

Knowledge check

1. Tab content exists in the DOM but is hidden with CSS. Can it be indexed?
2. Which lazy loading method is most crawler friendly?
3. The raw HTML has noindex and JavaScript removes it. What is the risk?
4. A single-page app shows Page not found but returns HTTP 200. What is this?

Next, bring rendering, links, and dynamic content together in the Indexing lesson.