The 7-Layer Website Launch Checklist We Built After Breaking 3 Client Sites
June 2026
We didn't sit down one afternoon and write a checklist. We earned it. One broken deploy at a time.
Three client sites went live with problems we should have caught. A build that failed because a database row didn't exist. A site that rendered fine but pointed every canonical tag at the wrong domain. An AI crawler block we didn't even know was turned on.
Each incident added a layer. Now we have seven. Here's every one of them and the production failure that created it.
Layer 1: DNS and Domain Pointing
This one seems obvious. Point the domain at the server. But "obvious" has a way of hiding the second and third thing you forget.
When we launched tentmakerswc.com, the A record was correct. The domain resolved. Traffic arrived. But we hadn't checked whether GSC domain verification was complete. Turns out, we'd added the GSC domain property but never finished DNS verification. Combined with no sitemap submission, the site had zero search visibility for the first week.
What to check:
- A/CNAME record points to the right origin
- www redirects to non-www (or vice versa) via 301
- GSC domain property DNS verification is done, not just started
- SSL certificate is active and covers the bare domain + www
One more thing. GSC will flag www.site.com and http://site.com as "Page with redirect." Those are healthy 301s. Do not click Validate Fix. It burns your daily indexing quota and sends failure notification emails. Dismiss them permanently.
Layer 2: Cloudflare Tunnel and Edge Config
If you're running through Cloudflare, the tunnel has to be alive and routing to the right internal service. We use Cloudflare tunnels to connect our deployment pods to the public internet.
The failure mode here is silent. The tunnel shows "healthy" in the Cloudflare dashboard, but it's pointing at the wrong internal port or an old container. You get a 502 or a stale page and no error in your application logs because the request never reaches your app.
What to check:
- Tunnel status is "healthy" in Cloudflare Zero Trust
- Public hostname maps to the correct internal service and port
- Cloudflare SSL mode is set to Full (Strict), not Flexible
- Cache is purged after the first successful deploy
Layer 3: CI/CD Environment Variables
GitHub Actions needs the right env vars to build the site. Missing one doesn't always throw a clear error.
When we deployed tentmakerswc.com, every config was correct. DNS, tunnel, snapshot file, everything. The GitHub Actions build failed at pnpm fetch-config with: "Failed to fetch config (404): {error: site_not_found}".
The env vars were fine. The problem was somewhere else (Layer 5). But we've also seen builds fail silently because a NEXT_PUBLIC_ variable was missing and the app compiled with undefined baked into the client bundle. No build error. Just broken runtime behavior.
What to check:
- All
NEXT_PUBLIC_*vars are set in the GitHub Actions workflow - API keys and service URLs are populated for the production environment
- The build command matches the target environment (production, not preview)
- Build logs show the config fetch succeeding, not just the build completing
Layer 4: Config Snapshot File
Our sites pull their configuration from a central gateway at build time and store it as site-config.snapshot.json. This file contains the site name, theme colors, SEO metadata, service descriptions, and schema markup data.
If the snapshot is stale or missing, the site either builds with old content or fails outright. We've had sites go live with a previous client's phone number in the footer because the snapshot wasn't refreshed before deploy.
What to check:
site-config.snapshot.jsonexists and is current- Business name, phone, address, and hours are correct
- SEO fields (title, description, canonical URL) reference the production domain
- The snapshot was generated after the last config change, not last week
Layer 5: Gateway Tenant Database Row
This is the one that got us on tentmakerswc.com. Everything was configured. DNS, tunnel, env vars, snapshot. The build failed with a 404 at config fetch.
Root cause: the sites-gateway Postgres database had no row matching tentmakerswc.com. The gateway is the source of truth. If your domain doesn't have a row in the tenant table, the config API returns 404 and your build dies.
This layer is easy to forget because it lives outside the application code. It's a database entry in a separate service. You can review every file in the repo and never find the problem.
What to check:
- The gateway database has a row for the production domain
- The
domaincolumn matches exactly (no trailing slash, no protocol prefix) - The
config_jsonblob has the correct business data - The config API returns 200 when you hit it with the production domain
Layer 6: Next.js Robots.ts, Metadata, and Canonical URLs
After tentmakerswc.com went live and passed all five layers above, we checked the rendered HTML. The site returned HTTP 200. It looked right. But buried in the source were 4 references to the old preview domain: preview3.redeemedanalytics.com.
Two were in canonical tags. Two were in og:url meta tags. Found at byte positions 3634, 4018, 129488, and 129963. Every search engine that crawled the page was told the real URL was on our preview subdomain, not the client's actual domain.
The fix required three changes: update canonical_url in the gateway config JSON, update metadataBase in layout.tsx, and grep the entire app/ directory for old domain references. All three. Missing any one of them leaves a stale reference.
We also found that 4 client sites had Disallow: /_next/ in their robots.ts files. This blocked Googlebot from fetching JavaScript, CSS, and fonts needed to render the page. We found it through the Cloudflare AI Crawl Control Violations tab. Googlebot doesn't show up there, but the pattern was the same blocking rule affecting all crawlers.
What to check:
robots.tsdoes not block/_next/(Googlebot needs those assets)sitemap.tsgenerates URLs with the production domain- Canonical tags in rendered HTML point to the production domain
- og:url meta tags match the production domain
- Grep the full
app/directory for any old domain strings metadataBaseinlayout.tsxuses the production URL
Layer 7: Cloudflare AI Crawl Control
This was the sneakiest one. After launching tentmakerswc.com, we discovered that Cloudflare's managed robots.txt was silently blocking 9+ AI crawlers. Our app's own robots.ts was clean. The blocks were coming from Cloudflare's AI Crawl Control feature, which has its own toggle in the dashboard.
If you've ever wondered why your site doesn't appear in AI-generated answers from ChatGPT, Perplexity, or Claude, this might be why. Cloudflare can block those crawlers at the edge before your application even sees the request.
What to check:
- Cloudflare AI Crawl Control is set to your intended policy (not the default)
- Check the Violations tab for blocked crawlers you didn't intend to block
- Your app-level
robots.tsand Cloudflare's edge-level blocking are not contradicting each other - Test with a direct fetch from an AI crawler user-agent string
Bonus: The Compliance Layer
This isn't a deployment layer. It's a legal one. But we check it at launch because fixing it later means the site was non-compliant from day one.
- Privacy policy page exists and is linked from the footer
- Terms of service page exists and is linked from the footer
- Forms have consent checkboxes (not pre-checked)
- Business physical address is visible (CAN-SPAM requirement)
- If an AI chatbot is on the site, there's a disclosure that it's AI
robots.tsandsitemap.tsare both present and functional- JSON-LD schema markup is on at least the homepage and service pages
- No specific data retention periods are stated unless the system enforces them
- A governing law clause exists in the terms
Post-Launch Verification
The site is live. The checklist is done. Now verify it actually worked.
- Submit the sitemap to GSC. Don't wait for Googlebot to discover it.
- Verify GSC domain property DNS. Check it's verified, not pending.
- Request indexing for the homepage and top 3 service pages.
- Check the Cloudflare AI Crawl Control Violations tab. Look for crawlers being blocked that shouldn't be.
- Run a Lighthouse audit on the live URL, not localhost.
- View page source and search for any old domain references.
- Test the contact form on the live domain with a real submission.
FAQ
Why did the build fail with "site_not_found" when everything else was configured correctly?
The sites-gateway Postgres database had no row for the production domain. The config API returned 404. DNS, Cloudflare, env vars, and the snapshot file were all correct, but the gateway is the source of truth. No database row means no config, and no config means a failed build.
How do I know if Cloudflare is blocking AI crawlers on my site?
Go to the Cloudflare dashboard for your domain. Navigate to Security, then Bot Management, then AI Crawl Control. Check the Violations tab. If you see crawlers listed there that you want to allow (like GPTBot, ClaudeBot, or PerplexityBot), your site is being blocked at the edge regardless of what your robots.ts says.
Should I block /_next/ in robots.ts?
No. The /_next/ path contains JavaScript, CSS, and font files that Googlebot needs to render your page. Blocking it means Google sees a blank or broken page. We found this on 4 client sites and it was hurting their rendering in search results.
What's the difference between GSC flagging "Page with redirect" and an actual redirect problem?
GSC flags www.site.com and http://site.com as "Page with redirect" when they 301 to your canonical URL. This is correct behavior, not an error. Do not click Validate Fix. It wastes your daily indexing quota and generates failure notification emails. Dismiss these permanently.
We build and launch websites for service businesses on Next.js and Cloudflare. If you want to talk through your launch process or need a second set of eyes on a deployment, reach out. You can also learn more about our web development and SEO work.