> ## Documentation Index
> Fetch the complete documentation index at: https://docs.frontic.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Page URLs

Shopping experiences live on URLs. Customers bookmark them, search engines index them, social posts link to them. Every one of those URLs needs to resolve to something renderable - and it should do so in a single request.

That's what a Page URL is: you hand Frontic a URL-key, and you get back everything needed to render the page - the page type, the data, and all the route metadata. No server-side routing logic, no second lookup, no stitching.

Manage your pages in the [API Builder](https://app.frontic.com/builder/pages) section of the admin app.

**api-builder/pages-overview**

Pages section showing one card per page type with its name, last-updated time, and connected block

![Pages section showing one card per page type with its name, last-updated time, and connected block](https://mintcdn.com/frontic/GsWLkrIAclxdqsw4/images/api-builder/pages-overview-light.png?fit=max\&auto=format\&n=GsWLkrIAclxdqsw4\&q=85\&s=6a1fcb63d6c6fd1472e7b0dffddcf63b)

Page URLs in the admin app

> [!NOTE]
>
> Page URLs don't hold their own data - they map a URL pattern to a [Detail Block](https://docs.frontic.com/api-builder/blocks.md), and that block's records become the page's content. Make sure the block you want to serve already exists and is connected to a Data Storage before creating a page.

## Create a page

From the [API Builder](https://app.frontic.com/builder/pages), click **New Page**.

**api-builder/page-create**

Create page form with fields for page name, block selection, and slug field configuration

![Create page form with fields for page name, block selection, and slug field configuration](https://mintcdn.com/frontic/hS7rYTW0C-o2HHTZ/images/api-builder/page-create-light.png?fit=max\&auto=format\&n=hS7rYTW0C-o2HHTZ\&q=85\&s=677286262ed204d93354d13dfc183a76)

Create a new Page URL - name, block, and slug field

Three pieces of information define a page:

* **Page name** - a human-readable name (e.g. `Product Detail`). Frontic derives the page type identifier and endpoint slug from this, so use normal capitalized words with spaces.
* **Block** - the [Detail Block](https://docs.frontic.com/api-builder/blocks.md) that shapes the response for this page type
* **Slug** - the block field used to generate the URL (e.g. `name`, `breadcrumbs`, `handle`)

> [!TIP]
>
> If no field on your block produces the URL shape you want, add a dedicated slug field and compute it with the [Value Composer](https://docs.frontic.com/data-integration/value-composer.md). Common patterns: `slugify` on a product name, `concat` a category path with a product name and color variant, or combine a brand prefix with a SKU - full control over URL shape without reshaping the underlying data.

### Localized URLs

If the slug field points at a translatable or scoped storage field, Frontic folds out one URL per locale and region from the same record. A single product can resolve at `/en/shop/equipment`, `/de/shop/ausstattung`, and a B2B-scoped `/pro/shop/equipment` at the same time - each served from the [domain](https://docs.frontic.com/project-settings/domains.md) that matches, each resolving to its own [Request Context](https://docs.frontic.com/api-builder/overview.md#request-context). Translate or scope the slug field on your Data Storage and the URL structure follows.

### Action on withdrawal

Pages change - blocks get removed, records get deactivated. In commerce, URLs that disappear cost you rankings, inbound links, and customer trust. Configure what happens when a page's underlying record is no longer available:

| Action | Description |
| - | - |
| 302 Redirect to home | Temporary redirect - the most common choice |
| 301 Redirect to home | Permanent redirect, removes the URL from search index |
| Delete URL | Removes the URL entirely (callers get a 404) |
| Keep URL with 404 | Keeps the URL but serves a 404 - useful for analytics |

Withdrawn URLs aren't lost - they're detached from the record but kept in the URL history. If a record with the same slug reappears later, Frontic automatically re-attaches the existing URL to it, preserving the original link. A record recreated with a different slug gets a fresh URL, and the old one stays withdrawn.

> [!TIP]
>
> To inspect individual generated URLs, verify canonical status, or remove stale entries, use the [URL Browser](https://docs.frontic.com/commerce-concepts/urls-seo.md#url-browser) in the admin app.

### Conflict resolution

URLs must be unique. When two records would generate the same slug (e.g. two products with the same name), pick a strategy:

| Strategy | Description |
| - | - |
| Append token | A secondary field (e.g. SKU) is appended to the slug to make it unique |
| Dismiss | The second page isn't created - the colliding record gets no URL |

### Sitemaps

You can augment your sitemaps with your Frontic page URLs. Enable sitemap visibility in your page settings to include that page in a generated sitemap:

**api-builder/pages-sitemap**

Page Settings showing the Visible in Sitemap toggle

![Page Settings showing the Visible in Sitemap toggle](https://mintcdn.com/frontic/1mx6IQXJDQLGJfJ5/images/api-builder/pages-sitemap-light.png?fit=max\&auto=format\&n=1mx6IQXJDQLGJfJ5\&q=85\&s=b488abc1e7aebe3a219cc2b95bde5a5d)

Page configuration - Enable sitemap visibility

Sitemaps can be fetched via [the Fetch API's sitemap endpoint](https://docs.frontic.com/reference/fetch-api/sitemap.md), or served from your app by the [Nuxt module](https://docs.frontic.com/reference/nuxt-module.md#sitemap).

## How URLs resolve

Frontic stores pages by their content-only slug, then projects them through your project's domain mappings to produce one fully-qualified URL per `(scope, region, locale)` combination that's configured to expose the content.

### URL anatomy

A resolvable URL splits into two parts: the **domain** the project mapped, and the **slug** the page record produced.

```
www.demo-shop.com/de   /shop/ausstattung
└──────────────────┘   └───────────────┘
       domain                slug
```

The **domain** is whatever string the project configured under [Domains](https://docs.frontic.com/project-settings/domains.md) - Frontic doesn't model a separate locale prefix layer. The same project can map any of these as a domain entry, and Frontic treats the whole thing as opaque on lookup:

* `www.demo-shop.com` - single domain, single locale
* `de.demo-shop.com` - locale on a subdomain
* `www.demo-shop.com/de` - locale on a path prefix, on the same domain

Each domain entry pins its own scope, region, and locale defaults. The slug is whatever path the page record's slug field produced - translated independently when the field is translatable.

The same product can resolve at all of:

* `www.demo-shop.com/shop/equipment` - public scope, en-US
* `www.demo-shop.com/de/shop/ausstattung` - public scope, de-DE (translated slug, locale carried by the path prefix in the configured domain)
* `b2b.demo-shop.com/shop/equipment` - b2b scope, en-US

Each is a separate URL with its own [Request Context](https://docs.frontic.com/api-builder/overview.md#request-context); the response shape is identical, but the data inside reflects the resolved scope / region / locale.

### Resolution chain

When a request hits Frontic with a URL like `www.demo-shop.com/de/shop/ausstattung`, the pipeline runs in this order:

1. **Domain match** - Frontic finds the longest configured project-domain entry that owns this URL (e.g. `www.demo-shop.com/de`, not `www.demo-shop.com`). The match returns the scope, region, and locale that domain entry is pinned to.
2. **Context resolution** - the `(scope, region, locale)` tuple becomes the [Request Context](https://docs.frontic.com/api-builder/overview.md#request-context). If the caller sent an `fs-context` header, that takes precedence; otherwise the domain's defaults apply.
3. **Page lookup** - Frontic strips the matched domain prefix and looks the remaining slug up in the project's URL history for the resolved scope. Hits return the page record; misses fall through to `route.code: 404` (or a redirect, depending on the page's withdrawal action).
4. **Block render** - the matched page's connected [Detail Block](https://docs.frontic.com/api-builder/blocks.md) renders the response, applying the resolved context to translatable / scoped fields.
5. **Route metadata** - Frontic attaches `route` to the response with the resolved code, the active context, alternate URLs for the same content in other regions/locales, and (when relevant) `redirect` or `context.suggested` entries.

The frontend doesn't need to know the chain - it's enough to pass the incoming URL to `client.page()`. The pipeline produces a deterministic answer, and your match-all route renders whatever comes back via `page.type` and `page.data`.

## Fetch a page

Your frontend hits a match-all route with only the incoming slug (e.g. `/fr/femme/chemises`). Pass that slug to Frontic and render the result.

> [tab] Client SDK
>
> ```ts theme={"theme":"css-variables"}
> const { slug } = useRoute().params;
> const page = await client.page(slug);
> ```

> [tab] Nuxt Module
>
> ```vue theme={"theme":"css-variables"}
> <script setup lang="ts">
> const { slug } = useRoute().params
> const { page } = useFronticPage(slug as string)
> </script>
>
> <template>
>   <component :is="page?.type" :data="page?.data" />
> </template>
> ```

See the [Client SDK reference](https://docs.frontic.com/reference/client-sdk.md#client-page) for the full API.

## Response

The response carries the page type, the block payload for this URL, and route metadata.

```json theme={"theme":"css-variables"}
{
  "type": "CategoryDetail",
  "block": "CategoryPage",
  "data": {
    "slug": "gloves-0194bcdaa2d57dc4bb4a9f33ed6b718c",
    "title": "Gloves"
  },
  "route": {
    "code": 200,
    "context": { "region": "de", "locale": "de-DE" },
    "alternates": [
      {
        "slug": "shop/equipment",
        "path": "/en/shop/equipment",
        "url": "www.demo-shop.com/en/shop/equipment",
        "href": "https://www.demo-shop.com/en/shop/equipment",
        "region": "en",
        "locale": "en-GB"
      }
    ]
  }
}
```

**type** `string`

The page type (e.g. `"CategoryDetail"`, `"ProductDetail"`). Use this to pick which component to render.

**block** `string`

The underlying Detail Block name. Useful if you map components to block names instead of page types.

**data** `object`

The block's content for this URL. Structure depends on the Detail Block configuration.

**route** `object`

Route metadata - response code, resolved context, alternates, suggestions, redirects. See [Route metadata](#route-metadata) below.

### Route metadata

The `route` property tells your frontend what HTTP code to return, what locale/region was resolved, where to redirect, and which alternate URLs exist for the same content.

**code** `number`

The HTTP status code your frontend should return: `200`, `301`, `302`, or `404`.

**context** `object`

The resolved region and locale the page was served for. Use this for analytics, canonical tags, or client-side state.

**alternates** `array`

Alternate routes for the same content in other regions/locales. Use for `hreflang` tags and language switchers. The current route is not included.

**redirect** `object`

When `code` is `301` or `302`, this holds the target URL to redirect to.

**context.suggested** `object`

When the caller's [context](https://docs.frontic.com/api-builder/overview.md#request-context) doesn't match the route Frontic resolved, this suggests a better-matching alternate. See [Context mismatches](#context-mismatches).

### Context mismatches

When a visitor with a `contextKey` tied to one region or locale lands on a URL from a different one - say, a user with `de-DE` context hitting `/en/shop/equipment` - Frontic serves the requested URL (never guesses silently) but adds `context.suggested` to the route, containing the matching alternate (slug, path, url, href, region, locale).

Your frontend decides what to do: prompt the user ("we noticed you're in German - switch?"), auto-redirect, adjust the canonical tag, or ignore the suggestion entirely and render the content as-is. Suggestions only appear on `200` responses - redirects and 404s don't include them.

### Error handling and redirects

The HTTP call itself returns `200 OK` whenever Frontic can satisfy the request - logical redirects and not-found cases for the URL live inside `route.code`. Your frontend reads that field, returns the matching HTTP status to the visitor, and (for `301` / `302`) uses `route.redirect.href` as the location. One code path handles every case.

## API Playground

> [!NOTE]
>
> Preview - the API Playground is in early access. It runs against your live backend today, but the UI and feature set are still settling before general availability. [Reach out](mailto:support@frontic.com) if you want to try it.

Open the playground with **Try it** in any page's detail header, or with **Open API Playground** on a URL in the [URL Browser](https://docs.frontic.com/commerce-concepts/urls-seo.md#url-browser), which fills that URL in for you. Use it to look up a rendered page against real data without writing code. Enter a URL, pick an API version, set the Request Context, and hit **Send** - the full page response appears side by side with your request.

**api-builder/playground-page**

API Playground dialog for the page endpoint showing a URL input on the left, release stage selector, domain and context configuration, and a JSON response with the resolved page type, data, and route metadata on the right

![API Playground dialog for the page endpoint showing a URL input on the left, release stage selector, domain and context configuration, and a JSON response with the resolved page type, data, and route metadata on the right](https://mintcdn.com/frontic/YiN8HmiGFMy2ycGP/images/api-builder/playground-page-light.png?fit=max\&auto=format\&n=YiN8HmiGFMy2ycGP\&q=85\&s=c48573a5e7d259f8c07dc766109196d3)

API Playground for the page endpoint - enter a URL, send, inspect the response

Use the playground to:

* **Resolve a URL** - paste the full URL (e.g. `www.demo-shop.com/de/products/red-sneaker`) and see which page type, block, and data Frontic resolves for it
* **Pick an API version** - run the request against the develop, preview or public version. Preview and public only appear once the project has them
* **Inspect the response** - status, response time, and payload size are shown alongside the body so you can spot performance issues. The response includes `type`, `block`, `data`, and the full `route` metadata
* **Copy code snippets** - auto-generated from your current configuration, ready to paste into your project

## Link to a page from a block

Block responses can embed a URL that points to a page. Add a [Route field](https://docs.frontic.com/api-builder/blocks.md#route) to a block, pick the target page and the field that carries the record key, and Frontic resolves the matching URL for every response - in the caller's locale and region, under the right domain. A product card rendered on `demo-shop.com/de` gets `/de/turnschuhe/air-max`, the same card on `demo-shop.com/en` gets `/en/sneaker/air-max`. No URL building on the frontend, no locale mapping tables.

## Related

> [card] [Detail Blocks](https://docs.frontic.com/api-builder/blocks.md)
>
> Shape the response for each page type.

> [card] [Menu Trees](https://docs.frontic.com/api-builder/trees.md)
>
> Build hierarchical navigation from Page URLs.

> [card] [URLs, Redirects & SEO](https://docs.frontic.com/commerce-concepts/urls-seo.md)
>
> How URLs are generated, how history is preserved, and how SEO metadata flows.

> [card] [Request Context](https://docs.frontic.com/api-builder/overview.md#request-context)
>
> How scope, region, and locale shape every page response.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.