Page SEO
Weaverse Studio lets merchants edit per-page SEO metadata (title, description, canonical, robots, Open Graph, Twitter card, JSON-LD) on every Weaverse page. To render those tags on the storefront, your theme needs to forwardweaverseData to a single helper — getWeaverseSeoMeta — from a meta export.
This guide explains where to wire the helper, how it interacts with code-defined SEO, and how to clean up any legacy override layer. It is written so you can apply it to any Hydrogen theme without prior knowledge of the file layout.
What changes on the storefront? The routes you opt in exportmetathat returns the SEO tags configured in Studio. Precedence is per route, not global: routes whose SEO is already derived from Shopify data (products, collections, Shopify pages) keep their code-defined SEO, and — in Pilot — so does the real homepage (INDEX). Pages without SEO configured in Studio fall through silently (no overrides).
Prerequisites
@weaverse/hydrogen>= 5.14.0 (the version that introducedgetWeaverseSeoMeta).- A Hydrogen route that loads a Weaverse page via
context.weaverse.loadPage(...).
TL;DR
In a route that should take its SEO from Studio (aCUSTOM page route, for example), export meta like this:
getWeaverseSeoMeta reads the SEO record embedded in the loaded page and returns the meta-tag array that React Router’s meta export expects. If the page has no SEO configured, it returns a minimal robots: index,follow descriptor — safe to call unconditionally.
The rest of this guide covers three real-world patterns and the cleanup steps you typically need.
Where to wire it
You decide per route whether Studio-edited SEO should apply. The routes that benefit most are the ones rendering WeaverseCUSTOM pages: the catch-all that serves custom pages, and the home/index route when it also serves root-level custom handles. Template routes (product, collection, Shopify page) are an optional supplement — they normally keep their Shopify-derived SEO.
The recipes below are independent of each other; the route file determines which one applies.
Catch-all route — CUSTOM pages
Most themes have a catch-all route that resolves any unmatched URL into a Weaverse CUSTOM page. Typical filenames:routes/catch-all.tsx, routes/($locale).$.tsx, routes/$.tsx. If your catch-all currently has no meta export, add one.
Before
Home / index route — INDEX (and root-level CUSTOM)
Many themes serve both the real homepage (type: "INDEX") and root-level CUSTOM handles from the same index route. Pilot’s app/routes/home.tsx splits the two: the real homepage keeps its code-defined SEO (seoPayload.home({ shop }), which reflects the shop name), while root-level CUSTOM handles served by the same route get their SEO from Weaverse.
Loader — compute seo only for INDEX, leave it null for CUSTOM, and return both weaverseData and seo:
Want merchants to edit homepage SEO from Studio too? That is a deliberate theme decision, not the default. Invert the branch — prefergetWeaverseSeoMeta(data?.weaverseData)when the merchant has filled in a title or description in Studio, and fall back toseoPayload.home({ shop })otherwise — so the homepage never ships with empty meta tags. Note the tradeoff: whichever way you choose, tell your merchants, because a field they edit in Studio for a route that keeps code-defined SEO will silently have no effect on the storefront.
Template routes — optional supplement (product, collection, blog, page)
Routes for Shopify resources (product, collection, blog, article, Shopify pages) typically build their SEO from the Shopify payload viaseoPayload.product(...), seoPayload.collection(...), etc. Leave those as-is. For templates, Shopify-driven SEO already covers the resource-specific fields (including structured JSON-LD with price, availability, ratings, etc.) that Weaverse Studio does not surface today.
If you want Weaverse SEO to supplement template routes: AddgetWeaverseSeoMetato the template’smetaexport and append it after the Shopify tags, not replace them. Avoid concatenating arrays naively — duplicate<meta name="description">tags can confuse crawlers. The safest pattern is to let Shopify SEO win and only pull in Weaverse tags that are absent from the Shopify payload (e.g. a customrobotsoverride or extra OG fields).
Step-by-step: applying this to a theme
- Bump the SDK to
@weaverse/hydrogen@^5.14.0and reinstall. - Locate every route that calls
context.weaverse.loadPage(...)—grep -rln "weaverse.loadPage" app/routes. - For each, decide which recipe applies (catch-all, home/index, or — optionally — template) and apply it. Routes that already build SEO from Shopify data stay as they are.
- Remove legacy overrides (see next section), if any.
- Run
typecheckandbuild. Fix anyerrorComponentregression caused by the SDK bump (see SDK 5.14 side effect). - Smoke test: open a Weaverse page in Studio, set a Title and Description, save, view source on the storefront URL. The tags should appear.
Removing a legacy override layer
Some themes shipped a hardcoded SEO override config to brand custom pages before Studio could edit SEO. Typical signatures:- A file like
app/.server/seo-overrides.ts,app/utils/seo-overrides.ts, or similar, with a hardcodedRecord<string, { title, description }>. - A helper like
seoPayload.customPage({ url })that maps the URL to one of those overrides. - A route that does
seoPayload.customPage({ url: request.url })and returns it in the loader.
- Delete the override file (e.g.
seo-overrides.ts). - Remove
customPagefrom your SEO payload module — both the function and its export. - Update routes that called
seoPayload.customPage({ url: request.url })— replace with themetaexport pattern above. The loader no longer needsrequestfor SEO purposes.
Why remove it? Studio-edited SEO is per-page and merchant-controlled. A static override would silently shadow whatever the merchant configures in Studio.
SDK 5-14 error component prop type
@weaverse/hydrogen 5.14 narrowed WeaverseHydrogenRoot’s errorComponent prop to React.FC<{ error: unknown }>. If your theme passes a custom error component typed as { error?: { message; stack? } }, TypeScript will now complain. The fix is to accept unknown and narrow at runtime:
.stack or other fields off the error.
Verification checklist
-
@weaverse/hydrogenis at^5.14.0(or newer) inpackage.jsonand the installednode_modulesversion matches. - Every route you opted in exports a
metafunction returninggetWeaverseSeoMeta(data?.weaverseData)(or branches per the home/index recipe). - Any legacy
seo-overrides.ts/customPagehelper is deleted. -
typecheckpasses (or only flags pre-existing, unrelated errors). -
buildsucceeds. - Setting a Title/Description in Studio is reflected in the storefront’s
<head>for that page.