Self-Hosting: Headless CMS Quickstart
You picked Self-hosted when you created your site (or you're about to). This guide is for the developer who's building and shipping the frontend.
In self-hosted mode, Vivreal is a headless CMS:
- Your content team gets Vivreal's portal UI to organize collections, schemas, media, and publish dates
- Your development team gets an API key and a site ID to pull that content into any frontend
- Vivreal does not ship, prescribe, or host a rendering layer — the frontend is 100% yours
You're free to use any framework (Next.js, Remix, Astro, SvelteKit, Nuxt, Solid, plain HTML, a mobile app) on any hosting platform (Vercel, Netlify, AWS, Cloudflare, your own infra).
What You Get
After creating a self-hosted site in the portal, you have:
| Value | Where to find it | What it's for |
|---|---|---|
| API key | Group Settings → API Keys | Authenticates Client API calls. Scoped to your group. Keep it server-side. |
| Site ID | Sites page → your site → Settings | Scopes queries to this site's content. Use it as a query parameter in Client API calls. |
| Seeded collections | Content tab in the portal | Vivreal created schemas and starter page configs based on the template you picked. Your frontend reads from these collections. |
Keep your API key server-side
Treat the Vivreal API key like any other secret. Never ship it to the browser. Put it in an environment variable on your hosting platform and only use it from server-side code (API routes, server components, server actions, edge functions, or a backend proxy).
Your First Fetch
Here's the minimum needed to pull content from Vivreal into any backend or server component.
const API_KEY = process.env.VIVREAL_API_KEY;
const SITE_ID = process.env.VIVREAL_SITE_ID;
const COLLECTION_ID = "your-collection-id"; // from the portal
const res = await fetch(
`https://client.vivreal.io/tenant/collectionObjects?collectionId=${COLLECTION_ID}&siteId=${SITE_ID}`,
{
headers: {
Authorization: API_KEY,
},
}
);
if (!res.ok) {
throw new Error(`Vivreal API returned ${res.status}`);
}
const { data } = await res.json();
// data is an array of collection objects ready to render
That's it. You now have your content as JSON. How you render it, cache it, revalidate it, theme it, and deploy it is up to you.
What Self-Hosted Is NOT
To set expectations — self-hosted mode does not include:
- A starter template repo or codebase — Vivreal's hosted-mode templates (Ecommerce Store, Showcase) are an implementation detail of hosted mode. Self-hosted is deliberately scaffold-free.
- A rendering SDK — there's no
@vivreal/rendererfor self-hosted. Use whatever your team already uses. - Deployment automation — Vivreal doesn't wire your hosting. You pick Vercel, Netlify, AWS, wherever.
- Asset delivery past the CMS — media URLs come back in Client API responses, but CDN caching, image optimization on your pages, etc. is on your side.
- Site-level theming or config beyond what's in collections — if you want per-site design tokens, encode them in a collection and fetch them like any other content.
Recommended Patterns
Scope every query by site ID
If your group has multiple sites pointing at overlapping collections, siteId keeps each site's queries clean. Always include it.
Cache aggressively, revalidate on writes
Vivreal content updates within seconds server-side, but you don't need to re-fetch on every request. Use your framework's caching primitives (ISR in Next.js, cache() in Remix, etc.) and invalidate on webhook events (see below).
Subscribe to webhooks for cache invalidation
Vivreal emits webhook events (content.created, content.updated, content.deleted, integration.*) when your content changes. Wire a webhook endpoint on your site that purges or rebuilds the relevant cache entries.
See Webhooks Overview for the full event list, signature verification, and retry policy.
Never hard-code collection field names
Field names are schema-driven and can change in the portal. Always iterate over the data object rather than destructuring hard-coded field names, or keep a single mapping layer that's easy to update when the schema changes.
Common Questions
Do I need to rebuild my site when content changes? No — content updates are served live from the Client API. The only time you rebuild is when your frontend code changes. For incremental page generation (e.g., Next.js ISR), trigger revalidation from a webhook handler.
Can I have both hosted and self-hosted sites in the same group? Yes. Create one site in each mode — they share the same group, the same collections, and the same API key. Each site has its own site ID, so you can scope queries independently.
Can I use the Client API without creating a site first?
No — the API key is group-scoped, but every Client API query requires a siteId. Create at least one site (any mode) to get a site ID.
What if I want to move to hosted later? You can create a new hosted site in the same group, pointing at the same collections, and run both side-by-side or migrate your domain from one to the other. Your content stays intact.
Next Steps
- API Reference: Endpoints — full Client API endpoint list
- API Reference: Authentication — API key details, scoping, and rotation
- Webhooks Overview — set up cache invalidation and event handling
- Setup Modes — recap of when to use self-hosted vs. other modes
Source of truth
- Self-hosted mode is resolved in
VR_Secure_API/src/createSites/services/createSiteCollectionData.js— triggers schema seeding but skips the Step Functions deploy pipeline - Client API authentication:
VR_Client_AuthLambda authorizer validates the API key at API Gateway - Client API routes:
VR_Client_API/src/api/index.js(8 endpoints under/tenant/) - Webhooks are emitted by
VR_CMS_API/src/shared/emitWebhookEvent.jsand delivered byVR_Secure_API/src/webhookDelivery/services/deliver.js