Pages in one minute#
A page is the CMS record behind a website URL. It gives editors a place to choose a name, URL, language, navigation settings, layout, and an ordered set of blocks. Your application fetches the published page and decides how those blocks look in React.
Editor creates a page
-> adds or arranges blocks
-> saves a draft
-> reviews it in preview
-> publishes it
-> website fetches the published page by URL
-> PageRenderer renders the blocksFor example, a page called About us might be reached at /about and contain a hero, team list, and contact call to action. The editor can change copy or block order without changing the route code. A developer changes React components when the visual design needs to change.
What Contoprix delivers#
The JavaScript SDK returns a ContoprixPage object. These are the fields most applications use first:
| Field | Example | What it is for |
|---|---|---|
pageId | "8f..." | Stable ID. Preview requests use this ID. |
name | "About us" | Editor-facing page name. |
slug | "about-us" | The page's stored slug. |
languageCode | "en" | The language of the delivered content. |
pageType | "standard" | A page classification chosen in the CMS. |
blocks | [...] | Main blocks, including their order and data. |
breadcrumbs | [...] | Available when the page has breadcrumbs enabled. |
navigation | { hideHeader: false } | Page-level navigation preferences. |
layout | { header, footer } | Optional global header/footer blocks. |
regionLayout | { grid, regions } | Optional multi-region layout definition. |
A block has an ID, a kind, a component code, a sortOrder, and its data.
| Block kind | Main data | Typical use |
|---|---|---|
component | settings | A reusable visual component such as a hero. |
content-single | content | One selected content entry. |
content-list | contents | A list of selected content entries. |
form | form reference | A placement for a published form. |
For content blocks, values are inside entry.data. Do not expect entry.title or entry.body to exist at the top level.
type ArticleData = {
title?: string;
summary?: string;
};
const entries = block.contents ?? [];
for (const entry of entries) {
const article = entry.data as ArticleData;
console.log(article.title);
}Page URL, stored slug, and route path#
These terms are related but not always identical:
- Stored slug is the short value saved on the page record, such as
about-us. - Route path is the full public URL path, such as
/company/about-usfor a nested page. - Browser URL is the full address, such as
https://example.com/company/about-us.
When the frontend fetches a page, use the public route path. The SDK accepts a leading slash and safely encodes each path segment.
CMS page slug: about-us
Nested public path: /company/about-us
Frontend request path: /company/about-usThe home page is special: use client.pages.get() or fetch the route /. See Routing for a complete Next.js example.
How layout works#
A page can use a basic single-column layout or a published Page Layout with regions such as main, sidebar, or footer-callout.
When a region layout is present, each block can have a regionCode. PageRenderer creates a grid from the layout and renders each block in its matching region. Without a region layout, it renders the page's blocks in sortOrder.
Global header and footer pages can also be included in page.layout. PageRenderer renders them before and after the main regions. A page's navigation settings can hide either region.
"use client";
import { PageRenderer } from "@contoprix/react/client";
import type { ContoprixPage } from "@contoprix/types";
import components from "./components";
import { schemas } from "./schema";
export function ContoprixRenderer({ page }: { page: ContoprixPage }) {
return <PageRenderer page={page} components={components} schemas={schemas} />;
}PageRenderer sorts blocks, handles header/main/footer rendering, and isolates render failures with error boundaries. It still needs your component registry to know how a block code should look.
CMS pages versus dynamic content routes#
Use a CMS page when an editor needs to choose the layout and block order for one URL: a home page, About page, campaign page, or contact page.
Use a dynamic frontend route when many URLs share one layout and only the record data changes: /blog/[slug], /products/[slug], or /authors/[slug].
These patterns work well together. For example, /blog can be a CMS page with an article-list block, while /blog/[slug] is a dynamic route that renders one article entry.
The editorial lifecycle#
- An editor creates the page and configures its name, slug, page type, layout, SEO, navigation, and access settings.
- They add or edit blocks in page content. Saving creates a draft version.
- Preview reads the draft through the preview API.
- Publishing validates the draft, copies it to the published version, and makes it available through the delivery API.
- The frontend fetches published content only.
Important
A successful save does not make a change public. Public delivery requires a published page content version for the requested language.
A simple first page#
- Create a standard page named About us with slug
about-us. - Keep the default layout unless you already need regions.
- Add a component block with code
hero_banner. - Add a second component or content-list block.
- Add
hero_bannerto the React component registry. - Preview the page, then publish it.
- Visit
/about-usin your website.
If the page loads but a block is missing, first check whether the block's component code exactly matches a key in the frontend registry.
Next steps#
- Create a Page: create and configure a page in the CMS.
- Routing: map website URLs to delivery requests.
- Dynamic Pages: build repeating article, product, or profile routes.
- Publishing: understand drafts, versions, publishing, and cache refresh.
- Visual Builder Setup: connect delivered blocks to React components.