Integrate Strapi with Croct

Add personalization and AB testing to your Strapi-powered site.

This integration connects your Strapi project to Croct. Strapi keeps managing your static content, while Croct renders dynamic content on top of it, so you can run AB tests and personalize experiences without migrating your CMS or restructuring your content types.

How it works

The integration builds on Strapi’s dynamic zones. A dynamic zone is a field that lets editors combine and arrange reusable components to build a page. Each of those components is a natural unit for dynamic content, so you map the ones you want to make dynamic to a Croct slot.

A single Croct slot holds a map from Strapi dynamic zone components to Croct slots. When rendering a page, each dynamic zone component with a mapping gets its content from Croct, using the original Strapi content as fallback.

When an experience targets the visitor, Croct returns the dynamic variant. If the request fails, the component renders your original Strapi content. That makes the integration additive: pages keep working exactly as they do today until you launch your first experience.

Croct's mascot amazed
No content restructuring

Your content types, dynamic zones, and editing workflow stay exactly as they are. Croct reads nothing from Strapi and writes nothing back to it, so you can adopt it one component at a time and roll back by removing a single fetchContent call.

Prerequisites

Before you start, make sure you have:

Set up the integration

If you are starting from scratch, this demo gives you an example of a working project.

From your project, run the CLI. It detects your setup, installs the SDK, and wires the provider and middleware for you.

Command to initialize your project
npx croct@latest init

If you prefer to set things up by hand, choose your SDK and follow the manual instructions.

Create components and slots

A Croct component defines the content structure that mirrors your Strapi schema, and the slot is the placeholder your application fetches content from. Follow this tutorial to create both for each component you want to make dynamic.

Map your dynamic zones

A single Croct slot holds a map from Strapi dynamic zone components to Croct slots. Follow the same tutorial to create your dynamic zone component using the following attributes:

AttributeDescriptionTypeRequired
mapThe list of pages and maps of dynamic zones to slots.List of structureYes
map[*].slugThe slug of the page as defined in Strapi.Plain textYes
map[*].sectionsThe list of the sections that should be connected.List of structureYes
map[*].sections[*].componentThe ID of the component as defined in Strapi.Plain textYes
map[*].sections[*].slotThe ID of the slot as defined in Croct.Plain textYes

For the component and slot attributes, select the Not empty option and use the pattern ^[a-z0-9_-]+$.

Then, create the slot home-page-dynamic-zones to map the pages and sections you want to connect to Croct.

Finally, follow this example to implement your dynamic zone mapping in the source code.

Decide where default content lives

Croct and Strapi can both serve the default content visitors see when no experience or AB test targets them. Choosing which side owns that layer is a structural decision.

Default content in Croct

In the recommended approach, we serve both default and dynamic content, while Strapi serves as the fallback. Once a dynamic zone component is connected, your team manages all of its content in Croct rather than in Strapi. That is what the mapping example does: it merges the content Croct returns over the original Strapi component content.

Default content in Croct
const {content} = await fetchContent(mapping.slot, {  preferredLocale: params.locale,  fallback: zone,});
return {...zone, ...content};

Default content in Strapi

In the alternative approach, we serve only the dynamic content, while Strapi serves both the default and the fallback. Once a dynamic zone component is connected, your team keeps managing default content in Strapi and manages only experience and AB test content in Croct. Teams often prefer this so their editorial workflow stays mostly unchanged once Croct comes into play.

Default content in Croct

To implement it, check where the content came from before rendering it. When the metadata.contentSource value is slot, the request matched no experience or A/B test, so the result contains no dynamic content, and your Strapi content should be rendered instead.

const {content, metadata} = await fetchContent(mapping.slot, {  preferredLocale: params.locale,  fallback: zone,});
// Use the Strapi content unless Croct returned dynamic contentreturn metadata?.contentSource === 'slot' ? zone : {...zone, ...content};

Verify the integration

Once the SDK is running, confirm that dynamic content reaches your site:

  1. Open your application

    Load a page that renders the connected component. You should see the default content.

  2. Launch a personalized experience

    Create and publish a personalized experience or an AB test targeting the connected slot.

  3. Confirm dynamic content

    Reload the page as a visitor who matches your audience. You should see the dynamic content instead of the default.