As a developer, you can integrate Builder into your codebase and give other team members, such as content editors, marketers, and designers, the ability to build and manage pages without ever having to ping you.
This guide is detailed. If you're using React, Next.js, Remix, Angular with standalone components, or Qwik and you'd prefer a more automated process, visit Developer Quickstart, which uses Devtools to integrate for you.
We highly recommend that you integrate Builder into an existing app, and these instructions assume you already have one. However, if you need to create an app, and would like instructions, visit Creating an App.
Want a shortcut? Get going right away with Builder and Next.js; use Builder's Devtools for Automatic Integration. Devtools fully automates your integration, so you don't have to take the steps in the rest of this document.
If you choose not to use the built-in Builder integration with Next.js with Devtools, continue with the instructions below.
At the command line, at the root of your project, use npm
to install the Builder SDK:
npm install @builder.io/react
If you're using Windows, be sure to use quotes when you install dependencies that use the @
operator; for example, npm install "@builder.io/react"
.
Start the development server:
npm run dev
Paste the following code into a new file within the pages
directory called [...page].tsx
(you must include the brackets and dots), making sure to replace YOUR_API_KEY
with your Public API Key.
Tip: If you don't have a pages
directory, be sure to create one.
This code gets your Page from Builder and displays the page between the header and footer. As a best practice, the header and footer reside in the codebase, as in this example.
// pages/[...page].tsx
import React from "react";
import { useRouter } from "next/router";
import { BuilderComponent, builder, useIsPreviewing } from "@builder.io/react";
import { BuilderContent } from "@builder.io/sdk";
import DefaultErrorPage from "next/error";
import Head from "next/head";
import { GetStaticProps } from "next";
// Replace with your Public API Key
builder.init(YOUR_API_KEY);
// Define a function that fetches the Builder
// content for a given page
export const getStaticProps: GetStaticProps = async ({ params }) => {
// Fetch the builder content for the given page
const page = await builder
.get("page", {
userAttributes: {
urlPath: "/" + ((params?.page as string[])?.join("/") || ""),
},
})
.toPromise();
// Return the page content as props
return {
props: {
page: page || null,
},
// Revalidate the content every 5 seconds
revalidate: 5,
};
};
// Define a function that generates the
// static paths for all pages in Builder
export async function getStaticPaths() {
// Get a list of all pages in Builder
const pages = await builder.getAll("page", {
// We only need the URL field
fields: "data.url",
options: { noTargeting: true },
});
// Generate the static paths for all pages in Builder
return {
paths: pages.map((page) => `${page.data?.url}`).filter(url => url !== '/'),
fallback: 'blocking',
};
}
// Define the Page component
export default function Page({ page }: { page: BuilderContent | null }) {
const router = useRouter();
const isPreviewing = useIsPreviewing();
// If the page content is not available
// and not in preview mode, show a 404 error page
if (!page && !isPreviewing) {
return <DefaultErrorPage statusCode={404} />;
}
// If the page content is available, render
// the BuilderComponent with the page content
return (
<>
<Head>
<title>{page?.data?.title}</title>
</Head>
{/* Render the Builder page */}
<BuilderComponent model="page" content={page || undefined} />
</>
);
}
A later section in this tutorial guides you through getting your Public API Key from the Account section of Builder. When you have your Public API Key be sure to add it to the builder.init()
method in this code snippet. The API Key is required for connecting your app to Builder.
Tip: If you don't have an index route, such as pages/index.tsx
, use pages/[[...page.tsx]]
with two sets of square brackets. The two square brackets means that Builder handles the app's home page.
The single set of square brackets, in this tutorial, assumes that you are keeping your home page.
The BuilderComponent
accepts several props for customization. One important prop for client-side routing is renderLink
, which means you can implement custom routing. For more information on renderLink
and other props, visit the renderLink
entry in Using BuilderComponent.
Here's an example of how you might use the renderLink
prop:
<BuilderComponent
model="page"
content={content}
renderLink={(props) => <CustomLink {...props} />}
/>
After the imports, you specify the Builder Public API Key and, with builder.init()
, connect your app to Builder.
Tip: Though it's not the syntax this example uses, if you're using the process.env
syntax with Next.js for API keys and SDK initialization, be sure to prefix it with NEXT_PUBLIC_
, as described in the Next.js documentation for Exposing Environment Variables to the Browser.
The getStaticProps()
function tells you what paths the app is building. Here, Builder gets the page and creates the URL, otherwise, if there's no page, you'll get null
and a 404.
export async function getStaticProps({ params }) {
const page = await builder
.get('page', {
userAttributes: {
urlPath: '/' + (params?.page?.join('/') || ''),
},
})
.toPromise();
return {
props: {
page: page || null,
},
revalidate: 5
};
}
revalidate: 5
means that Next.js attempts to re-generate the page under these conditions:
- When a request comes in
- At most once every 5 seconds
- To check if Builder has updates to the page
The getStaticPaths()
function returns a list of page URLs, omits unnecessary data for creating the list, and with fallback: true
, checks Builder for any new pages you might have added.
export async function getStaticPaths() {
const pages = await builder.getAll('page', {
options: { noTargeting: true },
});
return {
paths: pages.map(page => `${page.data?.url}`),
fallback: true,
};
}
The last section is a React component called Page()
. It gets the page data and checks that Builder is present. If there's no page
and no Builder, you get a 404. Otherwise, you get your Builder page.
Next, this snippet renders the title
field to be the page title. You can also add your own custom fields to render other information; for example, for SEO metadata.
export default function Page({ page }) {
const router = useRouter();
const isPreviewing = useIsPreviewing();
if (router.isFallback) {
return <h1>Loading...</h1>
}
if (!page && !isPreviewing) {
return <DefaultErrorPage statusCode={404} />
}
return (
<>
<Head>
<title>{page?.data.title}</title>
</Head>
<BuilderComponent model="page" content={page} />
</>
);
}
Builder adds the ability for your team members–even those who don't code–to create and iterate on ideas with a drag-and-drop interface.
Head over to Builder.io to sign up for an account if you don't already have one. Come back when you're logged in.
This next video covers the steps in this section of the tutorial all in one place to give you an idea of how it all works and the end result. This example uses Next.js but all frameworks use the same process:
To connect your Builder.io space to your application, add the Public API key to your code.
Find your Public API Key within Builder.io in one of two ways:
- Press
Cmd/Ctrl+k
in Builder to bring up the command palette and search for API Key. Clicking the Public API Key copies it to your clipboard. - Go to Account Settings and copy your Public API Key.
For more detail about the Public API Key, see Using Builder API Keys.
Paste the Public API Key into your app by replacing the YOUR_API_KEY
placeholder in your code. This location varies depending on your framework and is covered in the earlier sections of this tutorial. Make sure to wrap your Public API Key in quotes.
The following video shows copying the Public API Key and pasting it into a Next.js app.
To enable Builder to open your site in the Visual Editor, provide a URL that Builder can open which has the Builder rendering component in it.
- Go to Models and choose the Page model.
- Set the Preview URL to
http://localhost:<your-port>
, where<your-port>
is the port your app is using. Be sure to include thehttp://
. - Click Save.
The following video shows these steps:
Create a Builder Page to use with your integrated app.
- Go to Content.
- Click the +New button near the top right of the screen.
- Create a new Page in Builder and name it
Test Page
. Notice that Builder automatically generates the path as/test-page
. - The Editor for your new Page loads automatically.
- In your new Page, drag in a Text block.
- Click Edit and add something like, "I did it!!".
- Click the Publish button in the upper right of the browser.
The next video shows creating a Page in a Builder-integrated app and dragging in a text block:
After you deploy your updates, be sure to update this to a public URL, such as your live site or your staging site; for example, https://your-site.com
, so anyone on your team can connect to your site for visual editing.
Go to http://localhost:<your-port>/test-page
and check out your work. Well done!
If you're getting a 404 but aren't sure why, check these things:
- Make sure you've published your page in Builder by clicking the Publish button on the upper right corner.
- Check the URL. If you name the page
test2
for example, Builder adds a hyphen, so that the URL segment istest-2
. - Make sure that you've set the preview URL on the Page Model.
- For some frameworks, you might have to restart the dev server.
For more information regarding special use cases, visit Integration Tips.
We recommend that you place your Builder pages between your header and footer. A common use case is developers keeping headers and footers in their codebase while integrating page building. In this way, non-developer team members can iterate on pages, without having to rely on developers.
To use Builder pages between your header and footer, follow the guidance below for your framework:
Import your header and footer along with the other JavaScript imports at the top of [...page].jsx
.
Add the header and footer components before and after BuilderComponent
.
+ import MyHeader from '../components/my-header'
+ import MyFooter from '../components/my-footer'
export default function Page({ page }) {
...
return (
<>
<Head>
<title>{page?.data.title}</title>
</Head>
+ <MyHeader />
<BuilderComponent model="page" content={page} />
+ <MyFooter />
</>
);
}
With your app and Builder working together, the next step is the fun part–add some pages in Builder and drag in some elements. Play with styles and explore the UI.