Wix-managed headless projects can serve the same SEO tags that the Wix platform generates for a site's business solutions — titles, meta descriptions, canonical links, Open Graph and Twitter tags, and structured data — so that SEO settings a site owner edits in the Wix dashboard reach your custom frontend. This guide shows how to wire SEO support into dynamic pages for Wix business solutions such as Wix Stores, Wix Bookings, Wix Events, and Wix Blog.
Note: This guide assumes an Astro project created with the Wix CLI. The same two APIs (@wix/astro-pages and @wix/astro) apply to any Wix-managed headless frontend.
SEO support for a dynamic page has two independent parts. You need both for full coverage:
Page registration — a wixMetadata export on each dynamic route. The @wix/astro-pages integration reads these exports and exposes them at a /_wix/pages.json endpoint that enumerates every page in your project. Wix platform services use this to:
Tag rendering — at request time, fetch the Wix-resolved SEO tags for the specific item with loadSEOTagsServiceConfig() and render them into the page <head> with the <SEO.Tags> component. This is what puts the owner's dashboard SEO edits onto the live page.
wixMetadata registers the route with the platform; <SEO.Tags> renders the tags for a specific item. A page that exports wixMetadata but never mounts <SEO.Tags> is listed in the sitemap but ships generic markup; the reverse renders correct tags but stays invisible to the sitemap and SEO editor.
Projects created with the Wix CLI already include the @wix/astro and @wix/astro-pages dependencies, with the wix() and wixPages() integrations pre-configured in astro.config.mjs. You don't need to install or wire them yourself — the integration that reads your wixMetadata exports and serves /_wix/pages.json is ready out of the box:
The packages this guide adds are not predefined — install them yourself:
@wix/seo — the tag-fetching service and the <SEO.Tags> component.@wix/essentials — exports the WIX_APPS constant used below for app IDs and page metadata.WIX_APPS is a typed map of Wix app IDs and, for the solutions with dynamic pages, their page metadata. Prefer it over hardcoded strings — it gives you the appDefId, the pageIdentifier, and the slug token without copying literals into your code:
Source the appDefId, the pageIdentifier, and the slug-token value from the constant. The one thing you write by hand is the key inside identifiers — it must be the dynamic parameter of your route file (your code), not necessarily the key the SDK uses — see the note under Set up the SEO tags slot.
Note: The page-metadata accessor differs per vertical: WIX_APPS.checkoutAndOrders.productPageMetadata and .categoryPageMetadata (Stores), WIX_APPS.bookings.servicePageMetadata (Bookings), WIX_APPS.events.eventPageMetadata (Events), and WIX_APPS.blogs.postPageMetadata and .categoryPageMetadata (Blog).
Note: Dynamic pages must be server-rendered (output: "server"). The SDK calls used to fetch SEO tags depend on request context, so do not set prerender = true or use getStaticPaths() on these routes.
Expose a named seo-tags slot in the <head> of your shared layout. Dynamic pages fill this slot with Wix-generated tags; when it's empty, the layout falls back to its own default meta tags.
Each dynamic page imports the SEO helpers once in its frontmatter:
loadSEOTagsServiceConfig() takes three fields:
| Field | Description |
|---|---|
pageUrl | The canonical URL of the current page — use Astro.url.href. |
itemType | A seoTags.ItemType value identifying the business-solution page type. |
itemData | The dynamic identifier for the item, as { slug: "<value>" }. |
Important: The key inside wixMetadata.identifiers must match the name of your Astro route parameter. A route file named [handle].astro uses the key handle; [slug].astro uses slug. A mismatch breaks sitemap expansion.
The sections below show, per vertical, the wixMetadata export and the fetch-and-render snippet.
The Stores app registers two dynamic sub-pages: product pages and category pages. Both use the same Stores page-registration app ID (1380b703-ce81-ff05-f115-39571d94dfcd).
src/pages/product/[handle].astro
Register the route:
Fetch and render the SEO tags:
Tip: Run loadSEOTagsServiceConfig() in parallel with your data fetch via Promise.all to avoid an extra round trip.
src/pages/search/[collection].astro
Register the route:
Fetch and render the SEO tags:
The Bookings app registers a dynamic service page (app ID 13d21c63-b5ec-5912-8397-c3a5ddb27a97).
src/pages/bookings/[slug].astro
Register the route:
Fetch and render the SEO tags:
The Events app registers a dynamic event page (app ID 140603ad-af8d-84a5-2c80-a0f60cb47351).
src/pages/events/[slug].astro
Register the route:
Fetch and render the SEO tags:
The Blog app registers two dynamic sub-pages: post pages and category pages. Both use the same Blog app ID (14bcded7-0066-7c35-14d7-466cb3f09103).
src/pages/blog/[slug].astro
Register the route:
Fetch and render the SEO tags:
src/pages/blog-category/[slug].astro
Register the route:
Fetch and render the SEO tags:
The values that differ per vertical:
| Vertical | Route file | appDefId | pageIdentifier | identifiers | seoTags.ItemType |
|---|---|---|---|---|---|
| Stores — Product | product/[handle].astro | WIX_APPS.checkoutAndOrders.id | wix.stores.sub_pages.product | handle: "STORES.PRODUCT.SLUG" | STORES_PRODUCT |
| Stores — Category | search/[collection].astro | WIX_APPS.checkoutAndOrders.id | wix.stores.sub_pages.category | collection: "STORES.CATEGORY.SLUG" | STORES_CATEGORY |
| Bookings — Service | bookings/[slug].astro | WIX_APPS.bookings.id | wix.bookings.sub_pages.service_page | slug: "BOOKINGS.SERVICE.SLUG" | BOOKINGS_SERVICE |
| Events — Event | events/[slug].astro | WIX_APPS.events.id | wix.events.sub_pages.event | slug: "EVENTS.EVENT.SLUG" | EVENTS_PAGE |
| Blog — Post | blog/[slug].astro | WIX_APPS.blogs.id | wix.blog.sub_pages.post | slug: "BLOG.POST.SLUG" | BLOG_POST |
| Blog — Category | blog-category/[slug].astro | WIX_APPS.blogs.id | wix.blog.sub_pages.category | slug: "BLOG.CATEGORY.SLUG" | BLOG_CATEGORY |
Note: The identifiers column shows the key as it appears in each route file in this guide (handle, collection, slug). The key is always your own route's dynamic parameter; only the token value (STORES.PRODUCT.SLUG, etc.) is fixed by Wix.
Note: WIX_APPS.checkoutAndOrders.id (the page-registration ID, 1380b703-…) is not the same as the Stores catalog/install ID WIX_APPS.stores.id (215238eb-…) used for catalogReference.appId in cart operations. Both are correct; they identify different entities.
<SEO.Tags> covers the tags managed in the Wix dashboard. To add schema.org structured data (rich results), render a JSON-LD script from the item you already fetched:
Use the schema type that fits the page — Product for store products, Event for events, and so on.
wix build, then wix preview or wix release).<head> contains the Wix-generated <title>, <meta>, and <link rel="canonical"> tags rather than your layout's defaults./_wix/pages.json and confirm your dynamic routes are listed with their wixMetadata.Last updated: 25 June 2026