Opening the page…

Sulayman Bowles

Raw HTML and rendered DOM are separate evidence.

Separate what the server delivered from what the browser built.

· · Updated

Monochrome generative point study “Twin Drift,” a mathematical form rendered in black and white.
Twin Drift · @yuruyurau ↗

A server response and a rendered page can disagree in either direction. JavaScript may add content absent from the HTML or remove content the server delivered. Parsing, scripts, network activity, and mutations create the DOM. It and the raw response therefore answer different questions; neither alone explains the transformation.

Capture both artifacts with request metadata, browser identity, navigation timings, dependent-request outcomes, console errors, stop conditions, and completeness. That record lets a reviewer distinguish a page defect from a blocked resource, consent branch, timeout, authentication boundary, or failed instrument.

In this article

Which version of a JavaScript page should an SEO audit trust?

Capture both the HTTP response and the rendered DOM, because they answer different questions and either can contain information the other lacks. Preserve the browser environment, requests, timing, errors, and completion rule with the rendered snapshot. When content differs, first distinguish an application defect from blocked resources, consent, authentication, timeout, or capture failure. A screenshot or empty source response alone cannot establish what a particular crawler successfully retrieved and processed.

Sources: Google JavaScript SEO guidance · Chrome DevTools Protocol · RFC 9110 HTTP semantics

Questions and sources · 3 questions

Scope and assumptions

A controlled browser run describes the tested environment at a recorded time. It does not reproduce every search crawler, user device, cache state, geography, consent choice, or personalization path, and a successful local render does not prove indexing.

Evidence states
SOURCE + DOM
Completeness
EXPLICIT
Diff grain
FIELD
Primary artifact
RENDER ENVELOPE

Save what the server returned

Store the direct request target, headers, redirect chain, status, response headers, body hash, size, and timings together. Keep requested and final URLs distinct. A 200 application shell and a 200 response containing the article share a status, not a content outcome.

For a source-to-DOM comparison, also retain the main-document response from the browser navigation itself. An independent HTTP fetch may receive another experiment variant, cookie branch, cache version or geographic response. If its bytes differ from the browser’s response, first report a delivery difference; do not attribute the whole delta to JavaScript. A direct-request capture remains useful as its own named scenario.

Keep response bytes alongside extracted fields. A later parser may need to distinguish an absent title, canonical, link, or structured record from an extraction miss. Record content encoding and character decoding too: replacement characters from a bad decode can resemble source defects.

Redirects, cache headers, content type, robots directives, and transport failures precede client execution. A screenshot cannot reconstruct a missing redirect hop or establish which markup the origin returned.

Minimum source-capture envelope
LayerRequired fieldsWhy it matters
Requestrequested URL, method, selected headers, timestampDefines the attempted observation
Redirectshop URL, status, location, elapsed timePreserves routing and canonicalization evidence
Responsefinal URL, status, headers, content typeDefines transport outcome
Bodyartifact reference, hash, bytes, decoded charsetMakes extraction reviewable
Failureerror class, phase, retry stateSeparates no response from an empty response

Record the browser conditions

DOM output depends on engine and version, viewport, locale, time zone, cookies, storage, user agent, JavaScript policy, service workers, interception, authentication, and consent. Without those inputs, disagreeing runs cannot be compared. “Desktop render” is not enough.

Isolate contexts unless the test deliberately models a continuing session. Cookies can personalize a public route, service workers can return stale origin content, and shared storage can suppress a modal or select another application branch. Save the scenario and state seed with the capture.

Observe navigation, redirects, failed subresources, console output, and page exceptions. Do not inject repairs into the observation; test an intervention separately. Even a reasonable privacy choice, such as blocking analytics, changes the network policy and belongs in the record.

Collect HTTP response statuses as well as failed-request events. In Playwright, a 404 or 503 response completes as an HTTP response and does not emit requestfailed merely because its status is bad. A logger listening only for requestfailed can therefore report no failed requests while the article API returns an error. Playwright request events.

  • Pin browser family and exact version for comparable reruns.
  • Record viewport, locale, time zone, reduced-motion setting, and color preference.
  • Start from a named cookie and storage state.
  • Store failed requests and page exceptions with timestamps.
  • Mark every interception, mock, or blocked resource as an intervention.

Define when this page is complete

Network idle is not a content test. Telemetry, chat, streams, and polling may never stop; a quiet network may still leave an empty page. Fixed sleeps can be too short under load or waste time after completion. Define observable conditions for the page type instead.

A product test might require a main heading, price, image state, canonical, product record, and no fatal application error. An article might require its title, body threshold, publication metadata, and internal navigation. Bound the test with a wall-clock deadline and label complete, partial, timed out, blocked, or failed outcomes.

Carry that label into extraction. Fields observed in a partial DOM remain evidence, but missing conditions stay uncertain. Dropping completeness can turn unfinished navigation into a false orphan-page finding or content-absence claim.

Render-completeness states
StateMeaningAllowed interpretation
completeAll required page-type conditions observedField comparison is supported for this scenario
partialSome required conditions observed before stopPresent fields are evidence; missing fields remain uncertain
timed_outDeadline reached before the contract resolvedNo normal-health conclusion
blockedChallenge, authentication, or explicit denial prevented accessCoverage gap with visible boundary
failedBrowser, navigation, or instrumentation errorTool failure until reproduced otherwise

Compare meaning before markup

String diffs are crowded by generated IDs, attribute order, hydration markers, timestamps, and framework wrappers. First compare source and DOM fields relevant to the claim: headings, visible text, links, canonical, robots directives, language alternates, structured records, forms, media, and named components.

Classify each field as added, removed, changed, or unchanged and point to both captures. Resolve links while retaining original hrefs and anchors. Compare parsed structured records by stable identity, not JSON key order. Report exact and normalized text so normalization cannot conceal a meaningful delta.

For example, suppose the browser receives an article heading in its main response, then a hydration error replaces the body with a loading shell. The source capture, response hash, page exception and final DOM identify a client-side loss. If the heading instead appears only in a separate HTTP fetch, that same conclusion is premature. Pairing the observations determines which repair the evidence supports.

Use serialized DOM to investigate the component behind a field change. Starting with the operational difference keeps the report focused on what delivery or discovery changed, rather than every framework mutation.

Source observationServer response

Status, headers, body, redirects

Browser conditions

Scripts · network · state · stop condition

Rendered observationDOM capture

Fields, links, content, completeness

Field-level comparisonRetain both observations and explain the conditions between them.
A difference is an observation. The capture conditions determine which explanation it can support.
Render envelope

The completeness result and artifact references travel with every extracted field.

{
  "run_id": "render-2026-07-19-001",
  "requested_url": "https://example.com/article",
  "source_artifact": "sha256:source-hash",
  "dom_artifact": "sha256:dom-hash",
  "browser": { "name": "chromium", "version": "pinned" },
  "scenario": "anonymous-desktop",
  "completion": { "state": "partial", "missing": ["article-body"] },
  "failed_requests": 2,
  "field_diff_ref": "artifact://field-diff.json"
}

Find which stage failed

Source absent, DOM present: was client delivery intentional, and did the completion test pass? Source present, DOM absent: inspect component logic, hydration, consent, and runtime errors. Both present but reported missing: reproduce extraction on saved captures before changing the site.

Browser capability and crawler accessibility are separate. Google documents crawling, rendering, and indexing for JavaScript pages; local Chromium is not a Googlebot result. It can establish dependence on client execution in the tested scenario, not failure across every downstream system.

After repair, repeat the request headers, browser version, scenario, completion contract, and extractor. Verify the expected delta without new failure states. An environment change creates a new comparison; it cannot silently close the old finding.

Source-to-DOM triage matrix
SourceDOMFirst questionClaim boundary
presentpresentDid extraction or normalization fail?Delivery is visible in both saved states
absentpresentDid required client execution complete reliably?Content depends on tested render path
presentabsentWhat mutation removed or replaced it?Client execution changed delivered content
absentabsentWas the page complete and was the right route captured?Missing only if both observations are valid
unknownpartialWhich completion condition failed?Coverage gap, not confirmed absence

Rerun the same rendering test

Keep source, DOM, and the conditions that joined them. After a repair, repeat the same capture and completion contract. A successful local render demonstrates that tested path; it does not establish indexing or every downstream crawler’s behavior.

Reading notes ·

Questions, with evidence

A browser capture describes the recorded environment. It does not reproduce every crawler or establish indexing.

Why can View Source and the browser show different titles or content? — link to this answer

View Source describes the response body; the rendered DOM describes the document after the browser parses it and scripts run. Save both observations with URL, time, and environment. Compare title, canonical, headings, content, and links by meaning. A JavaScript change can fix or introduce a discrepancy, so neither observation should silently replace the other.

Evidence: Google’s JavaScript SEO basics · WHATWG DOM standard

Read the supporting analysis
Compare visible and machine-readable claims too

Is waiting for network idle enough to prove an article rendered? — link to this answer

No. A completion condition should refer to the page you need: the expected article, heading, body, and relevant links. Background requests may never settle, while a quiet network can leave a loading shell or failed component. Record the wait condition and check the resulting document, with explicit limits for missing or unavailable observations.

Evidence: Google’s JavaScript rendering guidance · Chrome DevTools Protocol

Read the supporting analysis
Include rendered evidence in the route check

Does a 200 response mean Google indexed the page? — link to this answer

No. A successful response establishes transport behavior for the request, not indexing. Inspect whether it contains the expected document or a shell, error, or alternate page; then inspect rendering and indexing directives. Google’s crawl, canonical selection, and index state are separate observations. Avoid diagnosing a ranking loss from an HTTP status alone.

Evidence: Google’s HTTP-status guidance · Google’s JavaScript SEO basics

Read the supporting analysis
Separate the preferred URL from Google’s selection

Sources

  1. Google Search: JavaScript SEO basics

    Verified Jul 19, 2026

  2. Google Crawling Infrastructure: HTTP status codes

    Verified Jul 19, 2026

  3. WHATWG DOM Standard

    Verified Jul 19, 2026

  4. Chrome DevTools Protocol

    Verified Jul 19, 2026

  5. RFC 9110: HTTP Semantics

    Verified Jul 19, 2026

  6. Playwright Page: requestfailed and response events

    Verified Oct 16, 2026

    Current event semantics checked for this revision; no browser experiment is reported.

Read next