Skip to main content
NewNMC’s advertising guidelines for doctors are in force from 6 Oct 2026. See what to change, and get a free compliance auditNew NMC advertising rules for doctors: what to change
SEO

Diffing Raw HTML and Rendered DOM at Scale: A Medical Page QA Pipeline

Find the pages that only work after JavaScript runs. A repeatable method for comparing raw HTML with the rendered DOM across 2,000 medical pages, with diff rules, thresholds and failure modes.

Diffing Raw HTML and Rendered DOM at Scale: A Medical Page QA Pipeline

This post is for the person who owns technical SEO on a hospital or multi-clinic site and has a nagging suspicion that Google is seeing something different from what the CMS outputs. It assumes you can run a Node script, you have a crawl of the site, and your templates use some client-side JavaScript. You do not need to be a developer to follow the logic, but you will need one to run the pipeline.

The question it answers is narrow: for a sample of about 2,000 medical pages, which fields differ between the raw HTML the server sends and the DOM after a browser has run the scripts, and which templates depend on JavaScript for something Search needs? That includes the title, canonical, robots directives, headings, main content, internal links and structured data.

We describe a method, not a result. We do not publish findings from client crawls here. What you get is the sampling plan, the fields to extract, the diff rules, the thresholds to set for yourself and the failure modes that waste a week if you meet them unprepared.

Why the difference matters on medical sites

Google crawls a URL first and renders it later. Its own JavaScript SEO basics say that pages with a 200 status are queued for rendering, and that rendering may be skipped when a robots meta tag or header says not to index. The same page warns that if the raw HTML contains noindex, Google may skip rendering and JavaScript execution, so removing it with a script is unreliable.

Several things follow for healthcare sites.

  • A doctor page built as a client-side app can show an empty shell in raw HTML. Everything Search needs then depends on the render step.
  • A canonical set or changed by script can disagree with the one in the raw HTML. Google advises against using JavaScript to change the canonical to something else, and says to keep one tag whose value matches the original HTML.
  • JSON-LD injected by a tag manager exists only after rendering. Google allows this, but notes errors are easy to introduce.
  • A booking widget, "load more" button or tabbed accordion may hide the clinical text, or the internal links to treatment pages, until a click.

None of these is a ranking penalty. They are dependencies. Each dependency is a place where a deployment, a slow third-party script or a blocked resource can quietly remove content that the raw HTML never contained.

The technical SEO audit usually starts with a URL Inspection check on a handful of pages. That is the right first step and the wrong place to stop, because a template problem affects thousands of URLs. A scripted comparison turns "this page looks fine" into "this template is safe or it is not".

Step 1: Build a stratified sample, not a random one

Take your sitemap or crawl export and tag every URL with a template. On a hospital site the templates are usually: home, specialty hub, treatment page, condition page, doctor profile, location or branch page, blog article, tool or calculator, and enquiry or booking page. A group with programmatic pages will have a further template per locality. The programmatic location pages post covers how those pages go thin; here we only care which template each belongs to.

Then sample by template. For 2,000 URLs, a workable split is to give every template a floor of 50 URLs and share the remainder in proportion to template size, with an extra weight on templates that carry enquiry traffic. Include:

  • the 100 URLs with the most Search Console clicks, since they carry the risk;
  • a set of pages with the fewest impressions, because rendering problems often hide there;
  • every URL pattern that was changed in the last two releases.

Record the sample as a file with columns for URL, template, release tag and priority. You will rerun it, so keep it under version control with the scripts.

Step 2: Fetch each page twice

For the raw version, use a plain HTTP client. Send an ordinary desktop user agent, follow redirects, record the final URL, the status code and the response headers, and save the body. Do not pretend to be Googlebot; some firewalls block spoofed bot agents, and you learn nothing about real Googlebot access from a fake one. Check access separately in the URL Inspection tool on a sample.

For the rendered version, use a headless browser. Playwright is a common choice. Load the URL, wait until the network has settled and the main content selector exists, then read the serialised DOM. Set explicit rules:

  • Use a fixed viewport, a fixed locale and a clean browser profile for every page.
  • Dismiss or pre-set the cookie banner the same way every time, because banners change what tag managers fire.
  • Wait for a named content selector with a timeout, not only for network idle, because a page can be idle and still empty.
  • Do not scroll or click unless you are testing lazy loading on purpose, and then record that choice.
  • Run at low concurrency. Four parallel pages is plenty; a hospital server that serves patients should not feel your audit.

Store both bodies and the rendered DOM so a disputed diff can be inspected later.

Step 3: Extract the same fields from both

Write one extraction function and run it on both bodies. Using the same code for both removes a whole class of false differences. Extract:

FieldHow to read itWhy it matters
HTTP status and final URLResponse metadataRedirect chains and soft errors
titleFirst title element text, trimmedQuery matching and snippet
Meta descriptionmeta[name=description]Snippet source
CanonicalAll link[rel=canonical] hrefs, resolved to absoluteDuplicate handling
Robots directivesmeta[name=robots] plus X-Robots-Tag headerIndexing control
h1 and heading outlineText of all h1 to h3Page topic signals
Main content textText inside the main landmark, whitespace-normalisedWhat the page says
Word countWords in the main content textQuick shape check
Internal linksCount and set of a[href] targets in main and navDiscovery and context
JSON-LDParsed objects: @type, @id, key propertiesEntity data
HreflangAll alternate linksLanguage targeting
ImagesCount, count without altImage search, accessibility

Normalise before comparing. Lowercase nothing, but collapse whitespace, strip tracking parameters from URLs and sort JSON-LD keys. For main content, hash the normalised text and also keep the text, so a reviewer can see the actual difference.

Want this applied to your practice? Get a free seo audit.

Book my free audit

Step 4: Write diff rules with severities

Do not alert on "different". Raw and rendered pages differ in small ways on every site. Write rules that say what kind of difference is harmful, and give each a severity.

RuleSeverityReading
Raw has noindex, rendered does notCriticalGoogle may skip rendering; the page may stay out of the index
Raw canonical missing, rendered presentHighRelies on the render step for duplicate control
Raw and rendered canonicals differCriticalConflicting signals
Raw title empty or generic, rendered title specificHighTitle exists only after render
Raw main text very short, rendered longHighContent depends on JavaScript
Raw internal links far fewer than renderedMediumDiscovery depends on render
JSON-LD only in renderedMediumAllowed, but fragile; check it is stable
JSON-LD types differ between the twoHighTwo sources disagree
Rendered H1 differs from raw H1MediumCheck for placeholder text in raw

"Very short" and "far fewer" need numbers, and they are yours to choose. A starting point is to flag a page when the raw main text has fewer than a quarter of the words found in the rendered version, then adjust after reading twenty flagged pages. State the threshold in the report so it can be argued with.

Step 5: Score templates, not pages

The output you want is a table with one row per template: URLs sampled, URLs flagged, flagged by rule, and a verdict of server-rendered, partly dependent or fully dependent. A page-level report with 2,000 rows is useless to a developer. A template-level one says which component to fix.

Hypothetical example, clearly invented: on a 200-bed hospital's site in Pune, the doctor-profile template might show a raw title and canonical but an empty main content area, with the biography, qualifications and clinic timings arriving through an API call. All 80 sampled profiles would then be flagged High for content dependency. The fix is to render that block on the server or at build time, not to inspect 80 pages one by one.

When a template is dependent, ask three questions before asking for a rebuild.

  1. Does Search Console show these URLs indexed and getting impressions? If yes, the render step is working at present, and the risk is about fragility.
  2. Does the dependency involve the clinical copy, or only a widget? Widgets matter less.
  3. Is another system, such as a CDN cache or a consent script, the cause? Fix that instead.

Google has also documented dynamic rendering as a workaround and describes it as a workaround rather than a recommended long-term solution. Treat server-side or build-time rendering of the important content as the target.

Failure modes in the pipeline itself

Expect these, and check for them before trusting any diff.

  • Bot protection. Your headless browser may receive a challenge page. Compare the rendered title against a known block page and exclude those URLs.
  • Geo or language redirects. A request from outside India may be redirected to a different language version. Run the audit from the market you care about.
  • Timing. A slow API makes content arrive after your wait. Re-run flagged pages with a longer timeout before reporting them.
  • A/B tests and personalisation. A variant can change the heading in one fetch and not the next. Fetch flagged pages twice.
  • Cache variants. The CDN may serve an older raw version than the origin. Record the Age and cache headers.
  • Blocked resources. If robots.txt blocks a script, your browser loads it anyway and Google may not. Check blocked resources separately in the URL Inspection report.

Where to start this week

Pick the three templates that matter most to appointments: usually doctor, treatment and location pages. Sample 50 URLs from each. Run the raw and rendered fetch and extract only title, canonical, robots, main text and JSON-LD. Read every flagged page by hand. If one template shows a pattern, take the evidence to the developer who owns it, with the raw body and the rendered DOM side by side.

Then confirm the result in the Search Console URL Inspection tool and the Rich Results Test on a few URLs, because they show what Google fetched. Keep the sample file, the extraction script and the thresholds in the repository, and rerun them after each release. Pair it with a review of your schema markup so structured data is checked in the same pass. The technical SEO glossary entry is a short briefing for the marketing lead who needs to read the report.

Filed underrendered HTML vs raw HTML SEOheadless browser SEO auditJavaScript rendering SEO healthcareraw HTML vs rendered DOMcompare rendered and source HTMLPlaywright SEO audit

About the author

Co-Founder & CTO · Gurugram, India

Arush builds the systems the rest of the company runs on — the patient-acquisition pipelines, the AI chatbots, the analytics that tie a single click to a booked appointment. If a campaign reports a number, it's because something his team built is tracking it.

Free guide · 17 pages

The Patient Acquisition Blueprint

A 90-day plan from first search to booked appointment.

The Pioneers Brief — one essay, three benchmarks, one teardown, every Thursday. Subscribe free →

Free seo audit

Your next chapter starts with a conversation.

Three quick questions. We come prepared with a plan for your specialty and city.

  • A 30-minute call with a healthcare specialist
  • Your top three growth opportunities, in writing
  • Honest advice — even if that means not hiring us
  • No obligation and no hard sell
You’ll speak with a senior strategist
Consultations are hosted by Arush Thapar’s team.
Step 1 of 3Takes 30 seconds

What do you want to improve first?

Details stay privateNo obligationReply within 1 working day

Client portfolio · Healthcare websites

Work relevant to diffing raw html and rendered dom at scale a medical page qa.

Explore client work →