Skip to Content
Strapi Page Builder 1.2 is now available 🎉

Manual Installation

Requirements: Strapi 5.31 or later, Node.js 20 to 24, and for Next.js, version 15.5 or 16.4 and later (Next.js 16.0 to 16.3 with Turbopack, the Next.js 16 default, is not supported: use 16.4 or later, or run with --webpack). Upgrading from 1.1? Read the upgrade guide first.

Sign up

If you don’t already have one, visit the Strapi Page Builder sign-up page to sign up for a free development account and get your API key; it will be needed in the next steps.

Strapi

Install the Strapi Page Builder plugin for strapi

From the terminal within your Strapi project, run

npm install @wecre8websites/strapi-page-builder

Once installed rebuild and run your environment with

npm run build && npm run develop

Configure Content-Types

  1. Create or update a content-type in the Content-Type Builder . For this example, the content-type should be configured with a few simple fields like title and content and, most important, a Relation field connected to Template from page-builder.
  2. Create a new content entry in the Content Manager  filling out the fields however you like but leaving the template field blank for now.
  3. Enter your Strapi Page Builder API key and the web app editor url in the Strapi Page Builder settings . Note, if on a free plan, only localhost and 127.0.0.1 domains can be used.
  4. Set the default content type to to the one configured above and select the new content entry made above. This is the content that will load when Strapi Page Builder first starts. It’s recommended you set this to your index page content.

React

Install the Strapi Page Builder React library

From the terminal within your React project, run

npm install @wecre8websites/strapi-page-builder-react

Configure an environment variable called PAGE_BUILDER_API_KEY or similar and assign to it your Strapi Page Builder API key.

IMPORTANT: API keys must be handled securely as though they were passwords. You should never commit your API key to GitHub or any where else that it may become compromised. Keep it server-side only (no NEXT_PUBLIC_ prefix).

Create a basic Strapi Page Builder config

Create a new file called config.ts in a folder called blocks in your src directory and the following code:

src/blocks/config.tsx
"use client"; import { Config } from "@wecre8websites/strapi-page-builder-react"; interface Blocks { TextComponent: { text: string }, } export const config: Config<Blocks, {}, "basic" | "other"> = { components: { TextComponent: { fields: { text: { type: "text" }, }, defaultProps: { text: "Visually editable text", }, render: (data) => <div style={{ padding:"6rem" }}>{ data.text }</div> }, }, root: {} }

Create an editor route

If using Next.js, create a new folder called editor in your app directory and add the following code. Adapt as necessary if using a different framework.

app/editor/page.tsx
import { Editor } from "@wecre8websites/strapi-page-builder-react"; import "@wecre8websites/strapi-page-builder-react/editor.css" import { notFound } from "next/navigation"; import { config } from "../../blocks/config"; export default async function EditorPage({ searchParams, }: { searchParams: Promise<{ _pagebuilderToken?: string }>; }) { const { _pagebuilderToken } = await searchParams; if (!_pagebuilderToken) return notFound(); return ( <Editor config={config} apiKey={process.env.PAGE_BUILDER_API_KEY as string} strapi={{ url: process.env.NEXT_PUBLIC_API_URL as string, authToken: process.env.STRAPI_ADMIN_TOKEN as string, imageUrl: process.env.NEXT_PUBLIC_IMAGE_URL as string, }} /> ); }

This is a Next.js Server Component, and that matters. When it is imported in a Server Component, Editor keeps apiKey and strapi.authToken on the server and validates the editor token there, so neither secret is ever sent to a visitor’s browser. Do not import Editor into a file marked "use client" or pass these values through your own client component: that sends them to the browser. See the Security guide.

Your config contains functions, so the file that defines it starts with "use client". That lets a Server Component hand it to the editor.

If your editor route does anything privileged of its own, such as enabling draft mode or loading private data, do it only after confirming the token. The _pagebuilderToken check above only tells you the parameter is present:

app/editor/page.tsx
import { validateEditorToken } from "@wecre8websites/strapi-page-builder-react/rsc"; import { draftMode } from "next/headers"; const check = await validateEditorToken(process.env.PAGE_BUILDER_API_KEY, _pagebuilderToken, process.env.SITE_ORIGIN); // e.g. "https://www.example.com" if (!check.ok) return notFound(); (await draftMode()).enable();

Allow the editor to be framed

The editor runs in an iframe inside the Strapi admin, so two headers must agree.

Strapi (config/middlewares.ts): add your site to frame-src in the strapi::security config, otherwise the admin refuses to load the editor.

config/middlewares.ts
{ name: "strapi::security", config: { contentSecurityPolicy: { useDefaults: true, directives: { "frame-src": ["'self'", "https://www.example.com"], }, }, }, },

Your site: restrict the editor route so only your Strapi admin can frame it, and pin the same origin on the editor.

app/editor/page.tsx
<Editor allowedParentOrigin="https://cms.example.com" /* ...other props */ />
next.config.ts
headers: async () => [{ source: "/editor", headers: [{ key: "Content-Security-Policy", value: "frame-ancestors https://cms.example.com" }], }],

allowedParentOrigin is optional but recommended in production. When set, the editor only sends messages to, and accepts messages from, that origin; without it the editor still ignores any window other than its direct parent, and only a parent that holds a valid token can drive it. The Strapi plugin always pins its messages to the editor URL’s origin.

Add the render component

Render can be used in a Server Component with your server-side strapi settings, including authToken. Page Builder keeps the token on the server and only allows the browser to look up documents that the page’s own template already references. Never copy the token into a client component yourself.

This example uses Next.js and assumes the Content-Type created in Strapi is called Homepage and is a Single type. Adapt as necessary for your configuration.

app/page.tsx
import { Render } from "@wecre8websites/strapi-page-builder-react"; import { notFound } from "next/navigation"; import { config } from "../../blocks/config"; export const revalidate = 60; const getHomepage = async (locale?: string) => { const queryUrl = new URL("http://localhost:1337/api/homepage"); if (locale) queryUrl.searchParams.append("locale", locale); queryUrl.searchParams.append("populate", "*"); const res = await fetch(queryUrl.toString(), { headers: { Authorization: `Bearer ${process.env.STRAPI_ADMIN_TOKEN}`, }, }); const { data } = await res.json(); const { template, ...content } = data; return { template, ...content }; }; export default async function Page({ params, }: { params: Promise<{ locale: string; slug: string[] }>; }) { const { locale } = await params; const { content, template } = await getHomepage(locale); if (!template.json || !content) return notFound(); return ( <Render config={config} data={{ templateJson: template.json, content }} /> ); }

Start editing

With both Strapi and Next.js running, open Strapi Page Builder  from the Strapi side-bar and start editing your content, visually.


Strapi Page Builder

You can now start adding custom components to your project.

Last updated on