Product Listing Editor Component
In this lesson we combine the Website Builder with the Headless CMS. You'll create a custom Product Listing editor component that content editors can drop onto any page, and that fetches published products from the HCMS at render time to display them.
In this lesson...
Here are the topics we'll cover
Fetch CMS entries inside a Website Builder component.
Configure the Headless CMS SDK alongside the Website Builder SDK.
Register the component and publish a page that uses it.
Prerequisites:
- Website Builder starter kit running (Lesson 1)
- Product and Product Category content models set up in Webiny (from the Headless CMS chapter)
- At least 2–3 published products in Webiny
Why Combine Website Builder and Headless CMS?
The Website Builder is great for layout and editorial composition. The Headless CMS is great for structured, reusable content. Combining them lets you get the best of both: editors compose a page visually, but the actual product data lives in the CMS where it can be authored, versioned, and reused across multiple surfaces.
Step 1: Publish Some Products
If you completed the Headless CMS chapter you should already have Product entries. If not, go to Content → Product in Webiny Admin and create 2–3 products. Publish each one — unpublished entries won't be returned by the Read API.
Step 2: Set Up the Headless CMS SDK
The Website Builder starter kit already has @webiny/sdk installed (it's a dependency of @webiny/website-builder-nextjs). You just need to initialise it for Headless CMS queries.
Create src/lib/webiny.ts:
Add the variables to your .env file. Use a Read API key (not the Manage key):
The Read API endpoint includes the locale — adjust en-US if your content is in a different
locale. You can copy the full endpoint URL from the API Playground in Webiny Admin.
Step 3: Define the Product Type
Create src/lib/types.ts (or add to an existing one). The fields match the Product model from the Headless CMS chapter:
Step 4: Build the ProductListing React Component
This component is a Server Component — it fetches data at render time using the SDK. Create src/editorComponents/ProductListing.tsx:
This component is an async Server Component. It runs on the server (or at build time) and never ships the SDK or API token to the browser. This is the correct and secure pattern for fetching CMS data inside a component.
Step 5: Register the Component
Open src/editorComponents/index.tsx and add the ProductListing registration:
The "use client" directive at the top of index.tsx marks the registration file as a client
module — it does not force ProductListing itself to run on the client. ProductListing is
imported from ./ProductListing which has no "use client" directive, so Next.js treats it as a
Server Component and renders it server-side.
Step 6: Use It in the Editor
- Restart your dev server to pick up the new component.
- In the Admin sidebar, go to Website Builder → Pages and open or create a page.
- Find Product Listing in the Custom group of the component palette.
- Drag it onto the canvas.
- Set the heading and the number of products in the sidebar inputs.
- Publish the page.

- Visit the page in your Next.js app. You should see your products listed.

How the Data Flow Works
Webiny Admin Editor
└── Editor saves page document to Webiny API
(document contains: "Custom/ProductListing", inputs: { heading, limit })
Next.js request / build
└── contentSdk.getPage("/your-page-slug")
returns the page document
└── DocumentRenderer encounters "Custom/ProductListing"
maps it to the ProductListing React component
└── ProductListing (Server Component) runs
calls sdk.cms.listEntries({ modelId: "product" })
renders the product cards
The page document from the Website Builder and the product entries from the Headless CMS are fetched independently and composed at render time.
Troubleshooting
No products showing
- Check that you published the products in Webiny Admin (not just saved them).
- Verify
WEBINY_API_ENDPOINTpoints to the Read API, not the Manage API. - Check
WEBINY_API_TOKENhas Read permissions for the Headless CMS.
"Custom/ProductListing not found" in the editor
- Restart the dev server — new component registrations require a restart.
- Make sure
ProductListingis added to theeditorComponentsarray before it's passed toDocumentRenderer.
TypeScript error on product.values.name
- Check that the
Productinterface field name matches the field ID in your Webiny content model (e.g.namenotproductName).
Summary
In this lesson you built a hybrid component that bridges the Website Builder and Headless CMS:
- Configured the Headless CMS SDK alongside the existing Website Builder SDK in the starter kit.
- Built an async Server Component that fetches CMS entries inside a Website Builder component.
- Registered the component with
createComponentand configurable inputs. - Placed the component on a page in the editor and saw live product data rendered.
This pattern — a Website Builder page composing one or more Server Components that query the Headless CMS — is the core of building editorial-driven content experiences with Webiny.
It's time to take a quiz!
Test your knowledge and see what you've just learned.