Technical SEO
Google indexing checklist for Astro sites on Cloudflare Pages
A clean Astro build only proves that files were generated. Indexing needs a different kind of evidence: public URLs, valid metadata, submitted sitemaps, and Search Console saying the page is in Google.
The annoying part of Google indexing is that a successful deploy does not buy you a place in the index.
You can make the site easy to crawl. You can publish a sitemap, keep robots.txt open, and give Google clean canonical URLs.
After that, you still have to check what Google actually did. “The sitemap exists” and “the URL is indexed” are separate
facts.
We hit this while reviewing the Sunstone Apps sites, which are built with Astro and deployed on Cloudflare Pages. The local build passed. The public files were reachable. The metadata looked reasonable in source. None of that answered the only question that mattered: which URLs had Google accepted?
The useful work was not adding more SEO code. It was walking the chain from generated files to Search Console evidence.
Start with production output
For an Astro static site, start with the production build. Source code can look right while the generated HTML tells a different story.
The minimum artifacts to verify are:
robots.txtexists and does not block important pages.sitemap-index.xmlorsitemap.xmlis generated and reachable.- Canonical URLs point to the production domain.
hreflangpoints to the expected language variants.- Important pages do not render
noindex. - OpenGraph and JSON-LD are present when the site expects them.
In this project, BaseLayout and the shared SEO helpers generate canonical links, hreflang, OpenGraph, Twitter cards, and
JSON-LD. That shared layer is worth having because the institutional site and the app landing pages should not each invent
their own SEO rules.
But shared code is not proof. Sitemap generation, static assets, route output, and deploy configuration all happen outside the React or Astro component you are staring at. The generated site is what Google sees.
Check the public web, not only the build
After the build, check the deployed URLs from the public internet:
curl -L -sS -o /dev/null -w 'status=%{http_code} content_type=%{content_type}\n' \
https://example.com/sitemap-index.xml
That one boring request catches problems source inspection misses:
- DNS records missing for a subdomain.
- Cloudflare Pages not serving the latest build.
robots.txtpointing to the wrong sitemap.- A sitemap that exists locally but is missing from the deployed site.
In our check, sunstoneapps.com and daily-sudoku.sunstoneapps.com served their sitemaps with HTTP 200. The
word-search.sunstoneapps.com subdomain did not resolve publicly, so Google could not crawl it. Its local build also
rendered noindex because the product was still in prelaunch.
That was fine for a product not ready for search traffic. The same state would be a launch bug for a public product. This is why the checklist has to know intent, not just return green or red.
Verify the domain in Search Console
For a domain with subdomains, use a domain property in Google Search Console unless you have a reason not to. It is cleaner than maintaining separate URL-prefix properties for every site.
A domain property for sunstoneapps.com covers:
https://sunstoneapps.com/https://daily-sudoku.sunstoneapps.com/- future subdomains under the same verified domain
Search Console requires DNS verification for domain properties. Cloudflare’s Domain Connect flow can add the TXT record automatically:
google-site-verification=...
The practical rule is simple: keep that DNS TXT record. It is not launch debris. Removing it can break ownership verification later, usually at the least convenient time.
Submit the sitemap, then read the table carefully
Submitting the sitemap is only the receipt. The Search Console table still needs interpretation.
For Astro’s sitemap integration, Search Console may show both:
sitemap-index.xmlsitemap-0.xml
The index can be processed while showing 0 pages found, because the actual page URLs live in the child sitemap. The child
sitemap is the one that should show the page count.
In our case:
https://sunstoneapps.com/sitemap-0.xmlwas processed with 20 pages found.https://daily-sudoku.sunstoneapps.com/sitemap-0.xmlwas processed with 8 pages found.- The two
sitemap-index.xmlfiles were processed, but showed 0 pages directly.
That is not a failure. It means the index file was read, while the page count belongs to the child sitemap.
One confusing state showed up during the review: Search Console first said it could not fetch the Sudoku sitemap even though the same URL returned HTTP 200 publicly. After a refresh, Google processed it.
That is the kind of result worth slowing down for. If the public URL fails, fix the site. If the public URL works and Search Console has one stale read, refresh and recheck before changing code.
Inspect important URLs
The strongest quick proof is URL Inspection. It looks at one URL, which is exactly why it is useful.
For each important page, Search Console can answer:
- Is the URL known to Google?
- Is the page indexed?
- Was it served over HTTPS?
- Is the canonical acceptable?
- Can you request indexing?
For the Sunstone sites, the important URLs were:
https://sunstoneapps.com/https://sunstoneapps.com/pt-BR/https://daily-sudoku.sunstoneapps.com/https://daily-sudoku.sunstoneapps.com/pt-BR/
All four were already in Google and marked as indexed. That mattered more than a generic site: search. site: is useful
for a quick sniff test, but it can lag, omit URLs, and create false panic.
When Search Console says discovered but not indexed
Discovered - currently not indexed is not the same as a broken page. It often means Google knows the URL from a sitemap or
another signal, but has not crawled it yet. Treat the Last crawl field as the clue. If it says N/A, you may be looking at
a queue problem, not a rendering problem.
In a later review, sunstoneapps.com had indexed home pages but several blog and legal URLs still sat in that state. The
generated HTML was fine: public requests returned HTTP 200, robots.txt allowed crawling, canonical URLs pointed to the
final URL, hreflang alternates were present, and there was no noindex. The missing piece was not another meta tag. It was
stronger discovery.
The practical fix was to add useful internal links from pages Google already trusted. The institutional home page now renders the four latest blog posts in each locale. The Daily Sudoku landing page links directly to its data deletion page in the header and footer. Those links help readers, and they give crawlers a path that does not depend only on the sitemap.
The follow-up in Search Console stayed selective:
- test the live URL first;
- request indexing only when the live test says the page is indexable;
- prioritize hubs and legal pages over every single post;
- do not keep resubmitting the same URL, because it does not move the page forward in the queue.
That restraint matters. If the live test fails, fix the site. If the live test passes and the page is merely waiting, improve internal discovery and give Google time to recrawl.
The checklist I would reuse
Before calling a small static site indexable, I would check this chain:
- Production build succeeds.
robots.txtis public and points to the correct sitemap.- Direct sitemap files return HTTP 200.
- Canonical and
hreflanglinks match production URLs. - Important pages do not have
noindex. - Domain property is verified in Search Console.
- Direct child sitemaps are submitted and processed.
- Search Console finds page counts in the child sitemaps.
- Main pages pass URL Inspection.
- Prelaunch subdomains intentionally stay DNS-blocked,
noindex, or both.
That last item is easy to miss. A product that is not ready should not leak into search. A product that is ready should not ship with prelaunch brakes still on.
Validate the generated site, not only the source code
Astro makes components easy to reason about. Google does not index components. It indexes the output Cloudflare Pages serves:
HTML, sitemap, robots, canonical links, hreflang alternates, OpenGraph tags, and JSON-LD.
A component can look correct while the final page still has a wrong canonical URL, a missing localized alternate, draft content in the sitemap, or a stale OG image. Build output is the source of truth for search engines.
What to check after every content change
For a small static site, the post-change checklist can stay short:
- run the production build;
- confirm the route exists in the expected locale;
- inspect canonical and hreflang links;
- confirm the page appears or does not appear in the sitemap as intended;
- verify
og:type, title, description, and image; - check JSON-LD type for the page category.
Those checks matter more on bilingual sites. A missing Portuguese pair or a wrong default-locale route can split signals across URLs without breaking the page in a way a developer notices.
Cloudflare Pages is fast, but cache is still real
Cloudflare Pages deploys static output quickly, but old assets and social previews can linger outside your repo and outside Cloudflare. OG image filenames, generated paths, and metadata consistency matter because search and social surfaces may keep using an older preview after the page changed.
Treat the build as a deployable artifact, not a side effect of code. If the artifact contains the right HTML and assets, deployment becomes much less mysterious.
Content freshness needs structure
Publishing more pages is not automatically better. A small site benefits from a clear content structure: bilingual pairs, stable slugs, consistent dates, and internal links between related posts. Readers need that structure. Crawlers do too.
For technical blogs, freshness should come from work that actually happened. A post written after solving a release, indexing, billing, or React Native problem is usually stronger than a generic keyword article because it carries the ugly details: the wrong assumption, the failed check, the external system that lagged, the thing that looked broken but was not.
A simple rule helps: if a page is meant to be indexed, it deserves a production build check before the work is closed.
For bilingual sites, also check that both language versions landed in the same change. Publishing only one locale leaves the index with uneven signals and makes later translation work harder to track.
Conclusion
Indexing is a chain, not a switch:
DNS resolves -> page serves -> robots allows -> metadata is valid -> sitemap is processed -> URL is indexed
Each step needs different evidence. Astro proves the files can be generated. Cloudflare proves they can be served. Search Console is where you confirm whether Google accepted them.
The useful habit is not “submit sitemap and hope.” It is checking the chain until the important URLs say the thing you actually need: the page is indexed.