Skip to content

Getting started

Croct Nanostores bridges Croct’s personalization engine with Nanostores, giving you reactive, type-safe atoms that deliver personalized content to any UI framework.

Because it builds on the Nanostores ecosystem, the same store works seamlessly across React, Vue, Solid, Preact, and Svelte — no framework-specific SDK required.

Before you begin, make sure you have:

  • A Croct account with an application set up
  • Your application ID (found in the Croct dashboard)
  • Slots configured with the content structure you want to personalize

Install the croct-nanostores package along with @croct/plug and the connector for your framework:

Terminal window
npm install croct-nanostores @croct/plug @nanostores/react

Use croctContent to create a reactive atom for a slot. You provide the slot ID and a fallback content object that matches the slot’s schema:

src/stores/banner.ts
import { croctContent } from 'croct-nanostores';
export const bannerContent = croctContent('home-banner@1', {
title: 'Welcome to our store',
subtitle: 'Check out our latest products',
ctaLabel: 'Shop now',
ctaLink: '/products',
});

The atom immediately holds the fallback content, then fetches personalized content from Croct in the background. When the fetch completes, the atom updates and any subscribed component re-renders automatically.

Croct’s API is optimized for low-latency content delivery, so in most cases the personalized content will be available before your app finishes rendering. Your users see the right experience from the start, with no visible flash of fallback content.

Once you have an atom, subscribe to it using your framework’s Nanostores connector:

src/components/Banner.tsx
import { useStore } from '@nanostores/react';
import { bannerContent } from '../stores/banner';
export function Banner() {
const banner = useStore(bannerContent);
return (
<section>
<h1>{banner.content.title}</h1>
<p>{banner.content.subtitle}</p>
<a href={banner.content.ctaLink}>
{banner.content.ctaLabel}
</a>
</section>
);
}

Croct Nanostores fully supports the type system from the Croct SDK. When you use the Croct CLI to generate type declarations for your slots, those types automatically flow through to your atoms and components.

Run the Croct CLI to generate a type declaration file for your application’s slots:

Terminal window
npx croct typegen

This produces a .d.ts file that augments the @croct/plug/slot module with your slot schemas. For example, a slot named home-banner with version 1 generates types like:

croct.d.ts
type HomeBannerV1 = {
title: string;
subtitle: string;
ctaLabel: string;
ctaLink: string;
};
declare module '@croct/plug/slot' {
export interface VersionedSlotMap {
'home-banner': {
latest: HomeBannerV1;
'1': HomeBannerV1;
};
}
}

Once the type declaration file is in place, TypeScript validates your code end-to-end:

  1. Slot ID validationcroctContent('home-banner@1', ...) checks that 'home-banner' is a known slot and '1' is a valid version.
  2. Fallback content validation — The fallback object you pass must match the slot’s content schema. Missing or extra properties produce a type error.
  3. Component-level inference — The content field on the atom’s state is typed to the slot’s schema, so your components get full autocomplete and type checking.
// ✅ TypeScript validates the fallback matches the slot schema
const banner = croctContent('home-banner@1', {
title: 'Default title',
subtitle: 'Default subtitle',
ctaLabel: 'Learn more',
ctaLink: '/about',
});
// ❌ Type error — 'unknown-slot' is not a valid slot ID
const broken = croctContent('unknown-slot@1', { title: 'Oops' });
  • Learn about the content rendering lifecycle — how atoms manage state, handle errors, persist content, and auto-refresh on user behavior changes.
  • See the full API reference for all options and types.
  • Check out the live demo to see multi-framework rendering in action.