Use Your Own Front End
Write and publish in Pendium, then render the pages and posts on a site you build and deploy yourself, from one export endpoint.
Pendium can be the place your content is written and published while your own code renders it. Your site reads everything the brand has published from one endpoint, GET /api/v1/site/export, and serves it with your templates, on your domain, from your repo.
Pick how your content reaches the web
| Option | Who renders it | Use it when |
|---|---|---|
| A site built for you | Pendium, on a folder on your site or a subdomain | You're on Pro and want pages and posts live without building or running a site. |
| CMS mirror | WordPress, Webflow, or Ghost | You already run a blog there and want posts copied into it. Pages aren't copied. |
| Your own front end (this page) | Your code | You want full control of the markup, design, and hosting, for posts and pages alike. |
With your own front end, Pendium doesn't serve anything to your visitors. Your site fetches the export, renders it, and answers every request itself.
Where content and code change
You write, edit, publish, and schedule in Pendium, and the slug, categories, writer, and address of every page and post are set there too. The export reports all of it. Your templates, styling, and hosting live in your repo and deploy through your own pipeline, so a template change never touches Pendium.
A publish in Pendium changes what the export returns. Your site shows it the next time it reads the export: at build time for a static site, or per request (or per cache window) for a server-rendered one.
Pendium doesn't notify your site when content changes. A static site picks up new content by rebuilding, and the export's ETag makes a scheduled check cheap: an unchanged brand answers 304 Not Modified, so you only rebuild when something was published or edited. The quickstart below sets this up.
What your site needs to serve
To keep the addresses Pendium has already handed out working, serve:
- every page at its
path, and every listing page (indexes) at itspath; - when
site.postsEnabledistrue, every post, category, and author at itspath. With posts off, Pendium serves none of them, even though a post'spathis still set; - a
301from eachaliases[].fromto itsto, so old slugs and the/blogaddress still land.
Paths are relative to the site root. Build full URLs (canonical tags, sitemap, feed) from site.canonicalOrigin plus path, or from your own origin when canonicalOrigin is null. Don't build them from the url fields: they point at the brand's live site, and they're null when the brand has no live site Pendium serves or builds for it (including a built site whose address isn't live yet, such as a newly verified domain that isn't serving the site). A post's url is also null when the site doesn't serve that post: its path is null, or posts are off. Paths lists the rules the export already applied, so your router doesn't have to re-derive them.
Page content arrives as typed sections (hero, prose, faq, and so on), not HTML, so your components decide the markup. Post bodies are Markdown. Links between the brand's own pages and posts already point at their site-relative path, so they work on your host as they are (Links in content). Site Export documents every field.
Analytics
Pendium can count visits to a site you render yourself, so the brand's Site Analytics keeps working. There are two parts: a tag for people, and a server-side report for AI crawlers.
Page views
Add the brand's tag to every public page, in the page's <head>:
Copy it from the brand's Site Analytics page, under Running your own front end?, or build it from site.analytics.siteKey in the export. When site.analytics is null, analytics is off for the brand: leave the tag out.
- Use a classic script tag. With
type="module"the tag can't find its owndata-siteand does nothing. - It counts one view per page, including pages your router changes without a full load. An anchor link or a change to the query string isn't a new view.
- It stores nothing on the visitor's device: no cookie, no local storage. A visitor counts once per day.
- Leave it off preview and staging builds, or their visits count too.
Views count when the page is on a host the brand is served on: its verified custom domain, its verified subpath host, or the website on its company profile (with or without www).
AI crawlers
AI crawlers don't run JavaScript, so the tag never sees them. Report them from your server with POST /api/analytics/hit, signed with the brand's signing secret from the same Site Analytics card. The secret can only report visits for its own brand. Keep it on your server.
Quickstart: Astro
This builds a static Astro site that reads the export at build time. It renders posts and their redirects; add page and listing templates the same way once this works. The same shape fits Next.js, Eleventy, or any generator that can fetch JSON during a build.
1. Get an API key and the brand ID
Create a key from API Keys under your avatar in Pendium (see Authentication). Keep it on the build server: a preview that runs code you don't fully trust can read drafts with a reviewer's preview token alone, with no key. Find the brand's syntheticId with /api/visibility/account.
Put both in your build environment, never in client code. The key can read every brand your account can open.
2. Load the export once per build
The first response carries up to 100 posts. Follow postsNextCursor until it's null to collect the rest.
3. Render posts at their paths
Install a Markdown renderer and an HTML sanitizer for the post bodies:
Post bodies are Markdown, and Markdown can carry raw HTML that marked passes through untouched. Sanitize the output before it goes into the page, so a stray <script> or onclick in a post can't run for your visitors.
Serve posts only when site.postsEnabled is true. A post whose path is null isn't reachable on the site (a page owns that address, for example), so skip it too.
4. Carry over the redirects
Astro config files can await, so load the export there and turn aliases into redirects.
With a host adapter (Netlify, Vercel, Cloudflare), Astro writes these as real 301s in the host's config. A plain static build without an adapter gets a meta-refresh page at each old address instead, so check what your host supports.
5. Rebuild when content changes
Most hosts give you a deploy hook: a URL that starts a build when you POST to it. The hook only starts the build, and the build can still fail after the hook answers. So let the deployed site record which version of the export it was built from, and compare against that.
Publish the build's ETag as a file on the site:
Then run a check on a schedule (a CI cron, for example) that reads that file from your live site and calls the hook only when the export has changed since:
The file changes only when a build deploys, so a failed build leaves the old ETag live and the next check starts another build. A check that runs while a build is still going can start a second one; many hosts queue or cancel the duplicate. The ETag covers the whole brand, including posts past the first 100, so one export request per check is enough. Every request counts toward your rate limit, 304s included, so every few minutes is plenty.
Previewing drafts
A static build shows published content only. To let a reviewer see unpublished pages and posts, render a preview route on demand (server-side) that requests perspective=drafts with the reviewer's preview token in the X-Pendium-Preview-Token header. Drafts need that token as well as your API key, so your public build can't show them by accident. Drafts covers the token and how long it lasts.
Related
- Site Export: the endpoint, every field, and its errors.
- Authentication: creating and passing an API key.
- Rate limiting: how many export requests you can make.
- Integrations & CMS Sync: mirroring posts into WordPress, Webflow, or Ghost instead.