Why a React Native web app is invisible to a crawler
A React Native app that exports to the web starts as one empty page. A
crawler and a link preview read three things from that page, and all three
are missing. This section of the docs lists the blockers, then gives you a
checklist in the order that fixes them, with the function in
@rootnative/seo that does each step.
The three blockers
1. One empty page
A single-page export writes one index.html with an empty <div> and a
script. Every route renders on the client. A crawler that does not run the
script sees the same empty page for every URL, and a crawler that does run it
sees a page with no title, no description, and no share card.
The fix is a static export. Expo Router writes one HTML file per route when
web.output is static, and PageHead writes the head of each page into
that file at export time.
2. No links
A Pressable that calls router.push renders a <div> with a click handler.
A Button that calls Linking.openURL renders a <button>. A crawler does
not click. It follows <a href> elements, and it finds none, so it never
reaches the second page.
The fix is Link from Expo Router for every navigation. It renders an
<a href> on the web and a pressable on native. Put a component such as
Button inside <Link asChild>.
3. A 404 for a deep link
A host that serves one index.html returns a 404 for /movies/1 unless a
rewrite rule sends every path to that file. A static export removes the
problem for the routes it knows, because /movies/1.html exists. A dynamic
route still needs generateStaticParams, or a host rewrite, or both.
No package can fix this one. The docs say so, and the limits page explains what to check on the live host.
What the package does and does not do
@rootnative/seo holds the parts that do not depend on your data:
- One
PageMetashape for the head of a page, andtoHeadTagsto turn it into tag records any renderer can write. PageHeadfor Expo Router,SeoProviderfor the site, andHeadingfor the outline.- JSON-LD builders for the common schema.org types. An empty field is left out.
shellTagsfor the HTML shell, therootnative-seocommand that writes the sitemap androbots.txtfrom the export, andwriteManifestfor the deploy step.
The app keeps the mapping from its data to the meta. The package knows schema.org, not your API. It does not prerender, it does not configure the host, and it does not ship an image component.
Next: the checklist.