Use the SDK for everyday website delivery#
@contoprix/client is the simplest way for a JavaScript or TypeScript application to read published Contoprix data. It keeps the base URL, authentication, language, timeout, and route encoding in one place.
Use it from server components, route handlers, backend services, or jobs. Keep credentials out of browser code.
Pick the package you need#
| Package | Use it for |
|---|---|
@contoprix/client | Framework-neutral delivery client for pages, content, media, navigation, search, sitemap, forms, preview, and schema tooling |
@contoprix/react | React rendering primitives, hooks, providers, and Visual Builder helpers |
@contoprix/next | Next.js server helpers, preview helpers, webhooks, and revalidation helpers |
@contoprix/graphql-client | Framework-neutral client for the GraphQL delivery endpoint |
@contoprix/cli | Model pull/push, generated types, components, diagnostics, and GraphQL code generation |
Install the core client first. Add the framework package only when you use it:
npm install @contoprix/client @contoprix/types
npm install @contoprix/react # React rendering helpers
npm install @contoprix/next # Next.js projectsConfigure the core client#
Add private environment variables. Do not use a NEXT_PUBLIC_ prefix for credentials.
CONTOPRIX_BASE_URL=https://cms.example.com
CONTOPRIX_DELIVERY_KEY=your-delivery-keyCreate a reusable server-side client:
import { ContoprixClient } from "@contoprix/client";
export const contoprix = new ContoprixClient({
baseUrl: process.env.CONTOPRIX_BASE_URL!,
auth: {
type: "deliveryKey",
deliveryKey: process.env.CONTOPRIX_DELIVERY_KEY!,
},
languageCode: "en",
timeout: 10_000,
});baseUrl is the API origin. For example, use https://cms.example.com, not https://cms.example.com/api.
Make the common requests#
import { contoprix } from "@/lib/contoprix";
export async function getHomepage() {
return contoprix.pages.get();
}
export async function getPage(path: string) {
return contoprix.pages.getBySlug(path);
}
export async function getLatestArticles() {
return contoprix.content.list({
contentType: "article",
take: 6,
skip: 0,
sort: "newest",
});
}Other useful calls:
const navigation = await contoprix.navigation.get();
const results = await contoprix.search.query("pricing", 10);
const sitemap = await contoprix.sitemap.get();
const article = await contoprix.content.getBySlug("article", "hello-contoprix");
const itemById = await contoprix.content.get("article", "entry-id");
const media = await contoprix.media.get("media-id");content.list() returns { items, pagination }. Each item has common information such as id, slug, and contentTypeCode; model-specific values are in item.data.
const articles = await getLatestArticles();
const cards = articles.items.map((entry) => ({
id: entry.id,
slug: entry.slug,
title: String(entry.data.title ?? entry.slug ?? "Untitled"),
}));Replace title with your real content-field code. The SDK cannot know every tenant's model at compile time until you generate types from the schema.
Use a different language for one request#
Set a default languageCode once, then override it per call:
const frenchAbout = await contoprix.pages.getBySlug("/about", {
languageCode: "fr",
});This is clearer and safer than creating several clients just to change the locale.
Next.js: use the server helper#
In a Next.js App Router application, @contoprix/next/server can read the same environment variables automatically:
import { getContoprixPage } from "@contoprix/next/server";
export default async function CmsPage({
params,
}: {
params: Promise<{ slug: string[] }>;
}) {
const { slug } = await params;
const page = await getContoprixPage({
slug: `/${slug.join("/")}`,
});
return <h1>{page.name}</h1>;
}The helper throws when the delivery request fails, including a not-found response. Handle that error in the route or an error boundary according to your application's error policy. For more control, import createContoprixClient from the same @contoprix/next/server entry point and call its page, content, or navigation APIs directly.
Use client credentials for trusted server-to-server work#
For a backend service, use a client ID and secret instead of a delivery key:
const contoprix = new ContoprixClient({
baseUrl: process.env.CONTOPRIX_BASE_URL!,
auth: {
type: "clientCredentials",
clientId: process.env.CONTOPRIX_CLIENT_ID!,
clientSecret: process.env.CONTOPRIX_CLIENT_SECRET!,
},
});The SDK exchanges the credentials for an SDK access token and reuses the token until shortly before it expires. Do not implement a separate token cache unless your environment has a special requirement.
When the Next.js helper reads environment variables, a complete CONTOPRIX_CLIENT_ID plus CONTOPRIX_CLIENT_SECRET pair takes precedence over CONTOPRIX_DELIVERY_KEY. Set only the credential style you intend to use.
Preview draft content carefully#
Preview calls are separate from published delivery and require preview:read:
const draftPage = await contoprix.preview.getPage("page-id", {
languageCode: "en",
});Preview credentials expose unpublished work. Use them only in a protected preview route and never ship them to ordinary visitors.
Handle errors intentionally#
Network and authorization failures should be handled close to the route or job that makes the request.
export async function loadAboutPage() {
try {
return await contoprix.pages.getBySlug("/about");
} catch (error) {
console.error("Could not load /about from Contoprix", error);
return null;
}
}Avoid silently treating every error as a 404. A missing page, an expired credential, and an unavailable CMS require different responses and different monitoring.
SDK checklist#
- Create one client per server-side integration boundary.
- Use the lowest scopes needed by that client.
- Set a reasonable timeout for your application.
- Pass ordinary page paths; let the SDK encode them.
- Read content model values from
entry.data. - Use generated model types after a schema change.
- Keep preview and privileged credentials separate from public delivery keys.
Next, learn the CLI workflow for generated types, or use Webhooks to refresh cached pages after publication.