Skip to main content

Rendering Weaverse Pages

This guide covers everything you need to know about rendering different page types in Weaverse, from basic concepts to advanced implementation patterns.

Core Concepts

Weaverse page rendering revolves around two key elements:
  1. loadPage() function: Loads page data based on type and handle
  2. WeaverseContent component: Renders the loaded page content

The loadPage() Function

The loadPage() function is called in your route loaders to fetch page data:

The WeaverseContent Component

The WeaverseContent component renders the loaded page data. It automatically gets the weaverseData from your loader through the <WeaverseHydrogenRoot> wrapper:
How it works: The <WeaverseHydrogenRoot> component (typically in your root layout) automatically extracts weaverseData from the current route’s loader data and provides it to all child <WeaverseContent> components through React context. This eliminates the need to manually pass the data prop.

Supported Page Types

Weaverse supports the following page types:

E-commerce Pages

  • PRODUCT - Individual product pages
  • COLLECTION - Collection/category listing pages

Content Pages

  • PAGE - Shopify Page resources (the pages you manage in Shopify admin), loaded with the page’s handle
  • BLOG - Blog listing pages
  • ARTICLE - Individual blog post pages

Special Pages

  • INDEX - Homepage
  • CUSTOM - Weaverse custom pages created in Weaverse Studio; resolved from the request URL, so no handle is passed
PAGE and CUSTOM are easy to confuse. Use CUSTOM for pages you built in Weaverse Studio — Pilot serves these from app/routes/catch-all.tsx and resolves the handle from the request URL. Use PAGE with a handle only for Shopify Page resources, the way Pilot’s app/routes/pages/regular-page.tsx serves /pages/:pageHandle.
Pilot uses React Router 7’s manual route registry in app/routes.ts. Creating a file under app/routes/ does not create a route — the module has to be registered with route()/index() before any URL reaches it. Route module code imports LoaderFunctionArgs, MetaFunction, and useLoaderData from react-router, and loaders return plain objects rather than json().

Working with Locales

Localization is request context, not a decision repeated in every page loader. Resolve the active market once from an exact configured allowlist, then use that entry to create both the Shopify Storefront and Weaverse contexts. Normal storefront loaders can then load the active localized page without parsing the URL or hardcoding a fallback:
Do not accept any leading segment merely because it has a locale shape, and do not fall back unconditionally to en-us. A configured prefix selects its exact market; an unsupported exact xx-yy prefix returns 404; an ordinary slug remains routable.
Locale switches must preserve valid paths and queries and perform a document navigation so the next request rebuilds Shopify and Weaverse data. Links, redirects, cart actions, checkout, and React Router .data requests must retain the same active market. Use an explicit locale only for an intentional cross-locale admin or background operation, not as a second storefront routing system.

Advanced Localization Guide

Implement the exact routing, context, continuity, SEO, and translation contract.

Markets and Localization

Define the canonical market table and configure localized content.

Routes Without Weaverse Integration

Some routes in your Hydrogen theme may not use Weaverse’s page system at all. These typically include functional pages that rely heavily on Shopify’s built-in components and APIs:
  • Search pages - Use Shopify’s search API directly
  • Cart pages - Use Shopify’s cart components and forms
  • Account pages - Use Shopify’s customer account API
  • Policy pages - Often render Shopify’s policy content directly

Custom Page Approach

Use the page type that matches the resource being rendered:

Shopify Page Resources: PAGE Type with Handle

Use PAGE only for a Shopify Page resource, normally under /pages/:pageHandle:

Weaverse Custom Pages: CUSTOM Type

For a root-level custom page created in Studio, let Weaverse resolve the page from the current request URL:
This approach allows you to create visually customizable pages using Weaverse’s editor while maintaining functional pages that use Shopify’s native components.

Real-World Example: Pilot Template Pattern

Pilot registers application and custom-page routes under an optional first segment, but that route parameter is not the market authority:
Before React Router handles the request, the server rejects an exact locale-shaped prefix that is not in the canonical market table:
This boundary makes the optional route safe:
  1. A configured prefix selects its exact Shopify and Weaverse market context.
  2. An invented prefix such as /en-xx returns 404 before any route can serve default-market content there.
  3. Ordinary root-level handles such as /about-us or /hi-india continue to the Weaverse custom-page path.
  4. The catch-all loads custom pages with loadPage({type: "CUSTOM"}); it does not reinterpret arbitrary text as a locale.
Keep this request boundary and the canonical market table together. A regex alone can identify locale-shaped text, but only the allowlist can authorize a market route.

Basic Implementation

Here’s the standard pattern for implementing Weaverse page rendering in a React Router v7 route:

1. Route Loader

2. Route Component

Page Type Examples

Product Page

Collection Page

Custom Page

Blog Page

Homepage

Custom Pages

Custom pages are built in Weaverse Studio and are rendered with the CUSTOM type. Weaverse resolves which custom page to serve from the request URL, so you do not pass a handle.

Root-Level Custom Pages Need No New Route

Pilot’s catch-all already covers every unmatched URL, so a custom page published at /about is served without touching app/routes.ts:
Add a dedicated route only when you want a different URL shape (for example nesting campaigns under /promo/...) — and load it with type: "CUSTOM" too. Remember to register it in app/routes.ts:

Shopify Pages (PAGE + handle)

PAGE is for Shopify Page resources, not for Weaverse custom pages. Pilot serves these at /pages/:pageHandle:

Error Handling

404 Error Handling

Always check if the page data exists and handle 404 cases:

Fallback Rendering

Provide fallback content when Weaverse data is unavailable:

Error Boundaries

Use error boundaries for graceful error handling:

Performance Best Practices

Parallel Data Loading

Always load Weaverse data in parallel with other API calls:

Caching

Use proper cache headers for Weaverse pages:

Preloading

Consider preloading critical page data:

Troubleshooting

Common Issues

1. Page Type Mismatch

Problem: Wrong page type specified in loadPage()
Solution: Use the correct supported page type
Problem: Using unsupported page types
Solution: Many functional pages don’t need Weaverse integration - use native Shopify components instead
Alternative: If you intentionally want a functional route to render a Weaverse custom page instead, create that page in Studio at the same URL and load it as CUSTOM from the route.

2. Missing Handle Parameter

Problem: Handle not provided or undefined
Solution: Always validate handle exists

3. Component Not Rendering

Problem: Weaverse components not registered properly Solution: Ensure components are registered in ~/weaverse/components.ts (or ~/app/weaverse/components.ts in Pilot template):
Important: Always use namespace imports (* as ComponentName) and restart your dev server after registration.

4. TypeScript Errors

Problem: Type errors with WeaverseContent Solution: Ensure proper type imports:

Next Steps

For more advanced use cases, see the Migration Guide and Custom Routing documentation.