
In this October 2026 teaching run, a deliberately broken website failed 11 SEO assertions before correction (Local fixture run report, 2026). Its pages could still look plausible in a browser. The hidden problems included indexing exclusions, conflicting canonicals, and an error page returning the wrong status. A release check makes those expectations visible before a change reaches users.
This tutorial builds automated SEO testing around a fictional local website and explicit route rules. You'll run the broken version, read its failures, then rerun the corrected version against identical expectations. The download includes source code and actual reports. Start with the JavaScript SEO guide if response HTML and rendered HTML are new concepts. Passing these checks confirms specific application behavior; it doesn't establish Google indexing or predict rankings.
Key takeaways
- The corrected local fixture passed all 37 assertions (Local fixture run report, 2026).
- Set expected status, indexing rules, canonical URL, and content for each route.
- Compare response HTML with the rendered DOM to catch JavaScript changes.
- Keep intentional exclusions and missing pages explicit; passing checks don't prove Google indexing.
- What should automated SEO testing verify?
- How do you run automated SEO testing with Playwright?
- Which response and rendered checks catch release mistakes?
- Read the failing and passing reports
- What else should you know before adding a release gate?
- Turn the fixture into a release check
- Documentation checked on 2 October 2026
What should automated SEO testing verify?
Compare each route with its intended status, indexing rules, canonical and essential content. Public guides, excluded previews and unavailable URLs need different policies. Define those expectations before writing assertions.
Write expectations independently of the output under inspection. If the checker copies the current canonical into its expected value, an incorrect URL will pass. Likewise, treating every successful response as correct would accept the missing guide's broken behavior. Your route list records the policy the application should implement.
| Route | Expected response | Indexing and content policy |
|---|---|---|
/guide/ | 200 | Public guide; canonical and content in response and DOM |
/header-guide/ | 200 | Public guide; no blocking response header |
/client-guide/ | 200 | Public guide; content arrives through JavaScript |
/removed-guide/ | 404 | Error content; no public-page canonical requirement |
/preview/ | 200 | Intentionally excluded preview |
Start with representative templates from your own website redesign checklist. Include a normal page, a JavaScript-dependent page, an intentional exclusion, and an unavailable URL. Is the error page supposed to remain discoverable? Decide that policy before writing assertions, then add more routes when they exercise different behavior.
How do you run automated SEO testing with Playwright?
Run the downloadable Node script after installing its pinned Playwright dependency and a browser. The October 2026 evidence records Playwright 1.62.1, Node 24.19.0, and Edge 154.0.4258.48 (Local fixture run report, 2026). The example starts its own localhost server, checks each route, writes reports, and closes the browser and server when it finishes.
Download the runnable SEO fixture ZIP and extract it into a new folder. Open a terminal there. Use Node compatible with the package's declared requirements, then install the dependency and Chromium. The README also explains how to select an existing Edge executable through an environment variable.
npm install
npx playwright install chromium
node check-seo.cjs broken
node check-seo.cjs fixed
Run the checking commands separately. The broken command intentionally returns a failure, so joining both with && would prevent the corrected command from running. Each command saves a JSON report and response/rendered HTML under reports/. A browser installation error is a setup problem; resolve it before interpreting the checks.
The checker imports the standalone library with require('playwright'). Playwright documents that this library requires explicit browser setup and cleanup (Playwright, Library, 2026). This download owns those steps and its reporting. You can read the complete flow without learning the test runner's configuration or introducing a separate application framework.
Review routes.cjs before editing the fixture. This entry requires guide content after rendering while permitting an initial loading shell:
{
path: '/client-guide/',
status: 200,
indexable: true,
canonicalPath: '/client-guide/',
rawContent: false,
content: 'Wheel inspection checklist'
}
The file contains the complete route array; the excerpt above explains its client-rendered entry. When adapting a React SPA audit, choose content that identifies the route itself. A shared navigation label or footer sentence would pass even when the main page failed to load.
Which response and rendered checks catch release mistakes?
Inspect responses and rendered documents separately. The client guide begins with acceptable metadata, then JavaScript introduces incorrect values and leaves its content unfinished. A response-only check would miss that regression.
Check the response status before following redirects
Request each local URL with automatic redirects disabled. Playwright's API reference specifies maxRedirects: 0 for this behavior (Playwright, APIRequestContext, 2026). Otherwise, a redirect could hide behind the destination's successful response. An intentional redirect needs its own expected status and destination checks; this fixture's public guides expect direct responses.
const response = await api.get(url, {
maxRedirects: 0,
failOnStatusCode: false
});
Keep error responses available for assertions rather than throwing immediately. Compare their actual status with the route policy. Google documents that content returned with a 404 status isn't used for indexing (Google Crawling Infrastructure, HTTP status codes, 2026). A heading saying “not found” doesn't replace that response. See the redesign release checklist for migration context.
Inspect meta directives and HTTP headers
Read both robots and googlebot meta values, plus applicable X-Robots-Tag response headers. Google's documentation describes these indexing controls and treats none as equivalent to noindex, nofollow (Google Search Central, Robots meta tags, 2026). The fixture respects generic and Googlebot-scoped headers. It doesn't interpret every specialized crawler rule.
Never treat a rendered removal of initial noindex as sufficient proof of a fix. Google may skip rendering when it encounters that directive in the original HTML (Google Search Central, JavaScript SEO basics, 2026). Fix the response at its source. Conversely, the client fixture demonstrates why adding noindex during JavaScript execution also needs a check.
Require the intended canonical and useful content
Count canonical link elements before comparing their values. The broken guide contains two, including a wrong relative URL, in the October 2026 report (Local fixture run report, 2026). The checker requires a single absolute HTTP(S) value in the document head, matching the route's expected canonical. Finding one correct tag among conflicting tags isn't sufficient.
Google recommends absolute canonical URLs, while acknowledging support for relative URLs (Google Search Central, Canonical guidance, 2026). Requiring absolute values here is a release policy. Production duplicates may intentionally point elsewhere, so store their target explicitly. This example checks HTML canonicals; add HTTP Link-header checks if your application uses that method.
For server-rendered guides, require meaningful main content in the response and browser DOM. For the client guide, permit the response shell but require the expected rendered text. The script waits for an explicit application readiness marker. What event means your content is complete? Use that event rather than guessing a fixed sleep.
The content assertion checks a main landmark, its heading, and an identifying phrase. Those checks won't evaluate article quality or every visible element. Use the response-versus-rendered SEO workflow to extend the investigation when a route needs deeper analysis. Store the snapshots so reviewers can see what changed.
Read the failing and passing reports
Read failed assertions as evidence of a policy mismatch, then identify the responsible template or header setting. The October 2026 broken run passed 26 assertions and failed 11; the corrected run passed all 37 (Local fixture run report, 2026). Repeated response and rendered failures can describe the same underlying defect, so don't count them as separate bugs.
These excerpts come from the actual localhost runs. The full logs and snapshots ship in the ZIP, while the downloadable run evidence records runtime versions and individual results. The reports use changing local ports for canonical comparisons. That variation is expected because each run starts a fresh server.
MODE broken; 5 fictional localhost routes
FAIL /guide/ response meta permits indexing: ["noindex, follow"]
FAIL /client-guide/ rendered main content: Loading guideCheck spokes and wheel alignment.
FAIL /removed-guide/ response status: expected 404, got 200
SUMMARY 26/37 passed; 11 failed; exit 1
MODE fixed; 5 fictional localhost routes
PASS /removed-guide/ response status: expected 404, got 404
PASS /preview/ response intentionally noindex: expected a robots exclusion
SUMMARY 37/37 passed; 0 failed; exit 0
The corrected fixture removes the public guide's exclusion and conflicting canonical, clears the blocking header, and fixes the client mutation. It also returns the intended missing-page status. Expectations remain identical between modes. Changing the expected status to accept the broken output would make the report green while preserving the error.
In this fixture run, the preview exclusion already passed before correction. That observation shows why a release gate needs route intent. Preserve intentional exclusions during a SPA release review, and investigate failures against their declared policy. A broad “remove all noindex” fix would damage this example's preview behavior.
What else should you know before adding a release gate?
A successful release check validates declared application behavior. It cannot establish crawler access, Google indexing or canonical selection. Keep those boundaries visible when adapting the suite.
Does a passing Playwright report prove Google will index a page?
No. The browser validates the listed local conditions. Use the JavaScript SEO investigation for separate crawl and indexing evidence.
Should an expected 404 make the release fail?
Only when it violates the route’s policy. The deliberately removed guide expects 404; an active public guide expects a successful response.
Can you run the download against a production URL?
The command accepts only broken or fixed localhost modes. Adapt it deliberately to your application preview; it does not accept a remote target.
What should you do when the browser or readiness wait fails?
Resolve the setup failure or missing readiness marker. Install Chromium or select an executable override, then reproduce the problem. Keep timeouts actionable rather than concealing them with retries.
Turn the fixture into a release check
Replace the fictional server with your application preview and retain independently defined route expectations. Until the checker requests your actual build, its success belongs to the demonstration.
Begin with representative templates, then add policies for redirects, duplicate pages, and intentional exclusions. Keep response HTML, headers, rendered snapshots, and exit codes with the build record. If a check fails, fix the responsible output and rerun the same expectations. Change a policy only when the intended behavior changes.
Download the fixture, reproduce the failure, and inspect the corrected report before adapting it. For the broader release review, follow the website redesign SEO checklist. Combine repeatable application checks with later crawl and indexing observations so each decision rests on the evidence that actually supports it.
Documentation checked on 2 October 2026
Primary documents retrieved and checked on 2 October 2026:
- Playwright: Library
- Playwright: APIRequestContext
- Google Search Central: Robots meta tags specifications
- Google Search Central: JavaScript SEO basics
- Google Search Central: Canonical guidance
For a factual correction, contact me with the affected section and a sanitized example.
Start with the downloadable fixture, then write route expectations for your next release.
Get in touch