launch-seo
A site can be fully built and deployed and still be invisible to search and bare when shared — none of that happens automatically. This is the checklist for making it discoverable, run once when a site first goes public (and again whenever new top-level pages are added).
When to use
- A docs/marketing/product site just deployed to a real domain for the first time.
- Someone asks to "submit to Google Search Console", "check our SEO", "add a sitemap", or notices link shares (Slack/Twitter/LinkedIn) render with no title/description/image.
- Stage between
open-source-repo-prep(repo is public-ready) andlaunch-video-generation/social-launch-post(announcing it) in theship-a-productpipeline — the site should be discoverable and shareable before you point an announcement at it.
Don't assume your host gives you a real robots.txt
Some edge platforms (Cloudflare zones are the common case) silently inject their own generic default robots.txt — often a legal/AI-crawler content-signals notice with zero real crawl directives and no Sitemap: line — for any zone that doesn't serve its own. It returns 200 and looks plausible at a glance, which is exactly why it's easy to miss: check the content, not just the status code, before assuming your robots.txt is real.
curl -s https://your-domain.com/robots.txt
If it's not something you wrote, you don't have one yet.
1. sitemap.xml
A flat <urlset> listing every real page with an absolute canonical URL — don't invent extensionless-vs-.html ambiguity, list whatever URL form your site actually serves with a 200 (verify with curl -s -o /dev/null -w "%{http_code}\n" <url> for both forms if your static host does automatic extension-stripping/redirecting — Cloudflare Workers Static Assets' default html_handling strips .html and 307s the suffixed form, for example; always list and link to the form that resolves directly, not the one that redirects).
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<url>
<loc>https://your-domain.com/</loc>
<changefreq>weekly</changefreq>
<priority>1.0</priority>
</url>
<url>
<loc>https://your-domain.com/docs/quickstart</loc>
<changefreq>monthly</changefreq>
<priority>0.8</priority>
</url>
<!-- one <url> per real page -->
</urlset>
2. A real robots.txt with a Sitemap: line
User-agent: *
Allow: /
Sitemap: https://your-domain.com/sitemap.xml
If staging and production share the same static-asset bundle (a common setup: one Worker/build serving both a preview subdomain and the real domain from the same site//dist/ directory), a single static robots.txt file can't differ per hostname — you'd either index the staging preview as duplicate content, or block the real domain by accident. Handle it in code instead of as a static file: intercept the request at the edge (a Worker fetch handler, a middleware, whatever your platform's request-hook is) and branch on request.url's hostname — permissive + Sitemap: line for the real domain, blanket Disallow: / for every preview/staging hostname.
3. Canonical, Open Graph, and Twitter Card meta — every page
Without these, link shares in Slack/Twitter/LinkedIn/iMessage render with no title, no description, no image — just a bare URL. Add to every page's <head>, using that page's real absolute canonical URL:
<link rel="canonical" href="https://your-domain.com/docs/quickstart">
<link rel="icon" type="image/svg+xml" href="/assets/favicon.svg">
<meta property="og:type" content="website">
<meta property="og:site_name" content="Your Product">
<meta property="og:title" content="Same as <title>">
<meta property="og:description" content="Same as meta description">
<meta property="og:url" content="https://your-domain.com/docs/quickstart">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="Same as <title>">
<meta name="twitter:description" content="Same as meta description">
twitter:card content="summary" (no image) is fine and honest if you don't have a dedicated 1200×630 OG banner asset yet — don't reference an og:image you don't actually have; a missing declared image is worse than none (broken-image icon in the unfurl). A proper banner is a high-fidelity-ui-image-gen/app-screenshots-shaped follow-up, not a blocker for shipping the rest of this.
4. Favicon
If there isn't one, a minimal hand-written SVG monogram is enough to stop favicon.ico: 404 and get a real browser-tab icon — doesn't need a design tool:
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
<rect width="32" height="32" rx="7" fill="#yourAccentColor"/>
<text x="16" y="22" font-family="ui-sans-serif, system-ui, sans-serif" font-size="15" font-weight="700" fill="#fff" text-anchor="middle">AB</text>
</svg>
Reference it with <link rel="icon" type="image/svg+xml" href="/assets/favicon.svg"> — SVG favicons are widely supported; ship one instead of blocking on a real .ico/.png set.
5. Verify before submitting
After deploying, actually fetch every new file — don't assume the deploy worked:
curl -s https://your-domain.com/robots.txt # your real one, has Sitemap:
curl -s -o /dev/null -w "%{http_code}\n" https://your-domain.com/sitemap.xml # 200
curl -s https://your-domain.com/sitemap.xml | head # valid XML, real URLs
curl -s https://your-domain.com/ | grep 'og:title' # meta present
Edge caches can lag a few seconds right after a fresh deploy — a 404/missing-meta result immediately post-deploy isn't necessarily broken, recheck once before debugging.
6. Submit to search engines — Google, Bing, and Yandex
Don't stop at Google. Bing Webmaster Tools feeds Bing, DuckDuckGo, Yahoo, and Ecosia from one submission, and Yandex Webmaster covers Yandex's own index. All three are free, and all three verify ownership the same three ways (DNS record, HTML meta tag, or uploaded file — DNS is the usual path if you already control DNS).
- Google Search Console — https://search.google.com/search-console
- Add the property using the root domain URL (
https://your-domain.com/), not a specific page. - Verify ownership.
- Sitemaps → submit
https://your-domain.com/sitemap.xml.
- Add the property using the root domain URL (
- Bing Webmaster Tools — https://www.bing.com/webmasters
- Fastest path: "Import from Google Search Console" — it pulls in the verified property and its sitemaps in one step. Otherwise: add the site manually, verify, Sitemaps → submit the same
sitemap.xmlURL.
- Fastest path: "Import from Google Search Console" — it pulls in the verified property and its sitemaps in one step. Otherwise: add the site manually, verify, Sitemaps → submit the same
- Yandex Webmaster — https://webmaster.yandex.com
- Add site → verify ownership → Indexing → Sitemap files → submit the same
sitemap.xmlURL.
- Add site → verify ownership → Indexing → Sitemap files → submit the same
Optional accelerator: IndexNow — Bing and Yandex (not Google) support instant URL pinging instead of waiting for a recrawl: host a random key at https://your-domain.com/{key}.txt, then GET https://api.indexnow.org/indexnow?url=<page-url>&key=<key> whenever a page ships or changes. Worth wiring up for a frequently-published site (blog/docs/changelog); overkill for a mostly-static marketing page.
Crawl/index status is not instant in any of them — allow days, not minutes, before checking indexing results. A site:your-domain.com query in each engine is the quick "am I indexed yet" check.
7. Beyond classic SEO — run geo-aeo next
This skill makes a site findable by search crawlers and shareable as a link. It does not make the site quotable by AI answer engines (ChatGPT, Claude, Perplexity, Google AI Overviews) or usable by agents. That's a separate layer — llms.txt/llms-full.txt, per-page markdown mirrors, schema.org JSON-LD, a WebMCP manifest, answer-first content, and programmatic entity pages. Run the geo-aeo skill right after this one.
Checklist
-
robots.txtcontent actually checked (not just status code) — confirmed it's yours, not a host-injected default. -
sitemap.xmllists every real page at the URL form that returns200directly (no redirect hop). -
robots.txthas aSitemap:line pointing at it. - Staging/preview hostnames get
Disallow: /if they share a bundle with production. - Every page: canonical link, favicon, OG + Twitter Card meta (title/description matching the page's own, no fabricated
og:image). - Verified live post-deploy with
curl, not just "the PR merged". - Sitemap submitted to all three consoles — Google Search Console, Bing Webmaster Tools (GSC import shortcut), Yandex Webmaster — property verified in each.
See also
../open-source-repo-prep/SKILL.md— repo-level public-readiness; this skill is the deployed-site-level counterpart.../social-launch-post/SKILL.md— the OG/Twitter meta here is what makes that skill's cross-posted links render with a real preview instead of a bare URL.../launch-analytics/SKILL.md— the measurement counterpart: GA4 + Microsoft Clarity. Together with the search-engine submissions above (§6), these are the things every domain project needs.../ship-a-product/SKILL.md— orchestrator; this is the discoverability stage, done once the site is live and before announcing it.