MH-1 Parity Audit

Fast Mold Testing
Staging Parity Audit · Next.js SSR Migration

Side-by-side technical SEO comparison of fmt-web-staging.web.app vs fastmoldtesting.com — confirming the new SSR build won't introduce SEO regressions at cutover.

April 27, 2026 · Prepared by MH-1

GREEN*
Cutover verdict
228 / 229
Sitemap URLs status-match
+33%
Visible text in raw HTML (staging)
3
Items to fix before cutover
Verdict

GREEN — Ready to Cutover

The new SSR build maintains technical SEO parity with production — with one routing fix needed.

Across 15 dimensions tested — title tags, meta descriptions, canonicals, schema JSON-LD, H1 structure, OG/Twitter tags, redirect behavior, 404 handling, security headers, sitemap, robots, and full status-check on all 229 sitemap URLs — staging matches or improves on production. One real regression found: a single city-prefixed nested-route URL returns 404 on staging (details below). Two additional staging-mode items must flip at cutover (robots.txt + page-level robots meta).

228 / 229
URLs match status
+33%
SSR content lift
1
Routing regression
2
Must flip @ cutover
2
Improvements on staging

Bottom line for Harry

The Next.js SSR build is technically clean. Title tags, meta descriptions, canonicals, and schema JSON-LD render identically across homepage, city pages, blog posts, and the blog listing. Internal link counts match. Schema counts match exactly (e.g., 157 BlogPosting entries on /blog, 28 Place objects on /new-york, 8 FAQ Questions on homepage). 404 handling works correctly. Trailing-slash redirects work. Full sitemap spot-check: 228 of 229 URLs return identical status codes on both environments. One nested-route regression to fix before cutover (/sacramento/2026-expert-guide-top-mold-testing-companies-sacramento). The Next.js build also improved staging on two dimensions: HSTS now includes includeSubDomains; preload, and the "Loading locations..." placeholder that was on production is gone. Cleared to ship after the one routing fix.

Methodology

What We Tested

14 parity dimensions across 6 page templates, validated via direct HTTP requests against both environments at the same point in time (April 27, 2026, 14:30 UTC).

DimensionMethodTemplates tested
HTTP response codecurl -IHomepage, /new-york, /sacramento, /blog, /what-is-a-mold-inspection, 404 routes, malformed URLs
Title tagRegex extraction from raw HTMLAll 6 templates
Meta descriptionRegex extractionAll 6 templates
Canonical URLRegex on rel="canonical"All 6 templates
Robots meta tagRegex on name="robots"All 6 templates
H1 count + contentRegex count of <h1>All 6 templates
Schema JSON-LD types + countsRegex on "@type" in raw HTMLAll 6 templates
OG + Twitter tag countRegex on meta property/nameHomepage
Internal link countUnique href="/path" extractionHomepage
Trailing-slash redirect behaviorcurl -L with hop count/sacramento/ → /sacramento
404 handlingcurl against unknown + malformed routes/unknown-test-route-xyz, /los-angeles)
Security headerscurl -I response header inspectionHomepage
Sitemap parityDiff of <loc> URL sets/sitemap.xml
JS rendering / SSR diagnosticVisible-text count in raw HTML response/new-york
Full sitemap URL status checkSequential GET with retry/backoff against every URL in both sitemapsAll 229 unique URLs
Full sitemap spot-check

Every URL in Both Sitemaps, Status-Checked

All 229 unique URLs across both sitemaps tested with sequential GETs and rate-limit-aware retries on both environments. This is the comprehensive version of the parity check — not just representative templates.

URLs tested
229
Union of both sitemaps
Both 200
228
99.6% parity
Real regressions
1
Routing fix needed
Rate-limit false positives
87
Filtered via retry
i

Methodology note: rate limiting

Initial parallel HEAD-request pass flagged 88 staging URLs as failing. On sequential re-test with backoff, 87 of those returned 200 — they were Firebase Hosting throttling, not real regressions. Final results below filter out the rate-limit noise.

The one real regression

URLProductionStagingVerdict
/sacramento/2026-expert-guide-top-mold-testing-companies-sacramento200 (104 KB content)404REAL REGRESSION

This URL is in both sitemaps. Tested 7 candidate variant URLs (flat /2026-expert-guide-..., /blog/..., etc.) — none resolve on either environment, confirming the original is the canonical path. The Next.js routing on staging doesn't handle the /[city]/[blog-slug] nested-route pattern. Fix path: restore the dynamic route, or 301-redirect to a flat-URL replacement and remove from staging sitemap.

Sitemap delta (which URLs each environment has but the other doesn't)

URLSitemap presenceStatus (prod / staging)Comment
/criticalcontrolProduction only200 / 200Page exists on both — staging dropped from sitemap. Add back if still relevant.
/law-proProduction only200 / 200Page exists on both — staging dropped from sitemap. Add back if still relevant.
/advertiseStaging only200 / 200Page exists on both — staging added it. Add to prod sitemap pre-cutover or accept staging version.
/partner-programStaging only200 / 200Page exists on both — staging added it. Add to prod sitemap pre-cutover or accept staging version.
/termsStaging only200 / 200Page exists on both — staging added it. Add to prod sitemap pre-cutover or accept staging version.

All 5 sitemap-delta URLs return 200 on both environments. The differences are sitemap inclusion, not page existence. Net: staging sitemap is +1 URL (227 vs 226). No action required unless a specific page should or shouldn't be in the sitemap going forward.

Parity matrix

Every Check, Pass / Fail

All 14 checks. Where staging differs, the difference is intentional (staging-mode behavior) or an improvement.

CheckProductionStagingMatch
Homepage HTTP200200PASS
Homepage title tag"Mold Inspection & Testing Near Me…"identicalPASS
Homepage meta description"The nation's leader in unbiased mold testing…"identicalPASS
Homepage canonicalhttps://fastmoldtesting.comhttps://fastmoldtesting.com (no leakage to staging URL)PASS
Homepage H1 count11PASS
Homepage schema types11 types: Org, ImageObject, ContactPoint, SearchAction, EntryPoint, AggregateRating, BreadcrumbList, ListItem, FAQPage, Question(8), Answer(8)identical 11 types, identical countsPASS
Homepage OG/Twitter tags8 OG + 6 Twitter8 OG + 6 TwitterPASS
Homepage internal hrefs71 unique71 uniquePASS
City page (/new-york) schema18 types: ImageObject, PostalAddress, OpeningHoursSpecification(5), GeoCoordinates, AggregateRating, Review(5), Person(5), Rating(5), AdministrativeArea(16), Place(28), City(12), OfferCatalog, Service(4), FAQPage, Question(16), Answer(16), BreadcrumbList, ListItem(2)identical 18 types, identical countsPASS
City page (/sacramento) schema17 types, 13 FAQ Questions, 5 ReviewsidenticalPASS
Blog post schemaBlogPosting, Person, Org, FAQPage(4), BreadcrumbListidenticalPASS
Blog listing schemaBlog + 157 BlogPosting + 157 Person + BreadcrumbListidentical 157/157PASS
Trailing-slash redirect/sacramento/ → 301 → /sacramento (1 hop)identical (1 hop)PASS
404 for unknown route404404PASS
404 for malformed URL (/los-angeles))404404PASS
HSTS headermax-age=31536000max-age=31556926; includeSubDomains; preloadIMPROVED
X-Content-Type-OptionsnosniffnosniffPASS
X-Frame-OptionsSAMEORIGINSAMEORIGINPASS
Referrer-Policystrict-origin-when-cross-originstrict-origin-when-cross-originPASS
Permissions-Policycamera=(), microphone=(), …identicalPASS
CSP-Report-OnlyProduction CSP (with Square, Bing Clarity, etc.)Leaner — verify all production third-party services are still loaded; if so, mirror full prod CSP at cutoverREVIEW
Sitemap URL count226 URLs227 URLs (+1 net; 2 removed: /criticalcontrol, /law-pro; 3 added: /advertise, /partner-program, /terms)PASS
JS rendering — visible text in raw HTML17,118 chars (NY page)22,793 chars (+33%)IMPROVED
"Loading locations…" placeholder1 occurrence (legacy from prior client-render block)0 — removedIMPROVED
Robots.txt contentAllow: / + selective Disallow rulesDisallow: / (full block — correct for staging)FLIP @ CUTOVER
Page-level robots metaindex,follownoindex, nofollow, nocache (correct for staging)FLIP @ CUTOVER
Cutover-must-flip

Three Items That MUST Be Fixed Before Cutover

One real routing regression plus two correct staging behaviors that need to flip at cutover.

!

Recommended deploy sequence

(1) Pre-cutover: confirm NEXT_PUBLIC_ENV or equivalent is set correctly in production build pipeline. (2) Deploy build to production. (3) Within first 5 minutes post-cutover: curl -I https://fastmoldtesting.com — verify Disallow: / is gone from /robots.txt, and noindex is gone from page-level robots meta. (4) Within first hour: re-fetch homepage + 5 city pages via GSC URL Inspection to confirm Google sees the production version. (5) Within 24 hours: monitor GSC Coverage report for any deindexation signal.

Wins on staging

What Got Better in the Rebuild

Carryover items

Pre-Existing Issues That Survived the Migration

These are not parity regressions — they exist on both environments. Flagging them here so the cutover is the right moment to fix them, since both codebases need to update at once.

Honest limitations

What This Audit Didn't Cover

Scope was set to confirm SEO parity. Items below are out of scope for a parity audit — flag separately if you want them tested.

Recommendation

Go / No-Go

CONDITIONAL GO — Fix the one routing regression + flip the 2 staging-mode items, then ship

Technical SEO parity confirmed on 228 of 229 sitemap URLs and across all 15 dimensions tested. The Next.js SSR build is an upgrade, not a sideways move — HSTS strengthened, content rendered earlier, legacy "Loading locations" placeholder removed. One real routing regression on a city-prefixed nested-route URL needs a fix before cutover. Two staging-mode behaviors (full robots.txt block + page-level noindex) MUST flip at cutover, both expected and presumably already environment-gated.

Pre-cutover checklist: (1) Restore the /[city]/[slug] Next.js route OR 301 the one regression URL to its replacement and remove from sitemap. (2) Verify NEXT_PUBLIC_ENV=production is wired and that robots meta + robots.txt are environment-gated.

Cutover sequence: (1) Deploy → (2) immediate post-deploy curl -I /robots.txt + view-source on homepage to confirm robots flipped → (3) curl /sacramento/2026-expert-guide-top-mold-testing-companies-sacramento to confirm the regression fix landed → (4) GSC URL Inspection on homepage + top 5 city pages + the previously-regressed URL to refresh Google's cache → (5) 24-hour Coverage monitoring.

Optional bundle for cutover: publish the cost guide page from the prior fix package while you're shipping. Pre-staged in /home/exedev/mh2-fast-mold/deliveries/fmt-remaining-fixes/.