CommunityCoding & Developmentgithub.com

croct-tech/agent-skills

>- Use when installing or using a Croct SDK in application code: rendering slot content, evaluating CQL queries, server or client fetching, prerendering, identifying users, app ID / API key env vars, testing, or debugging. Covers JavaScript (`@croct/plug`, `croct.fetch`, `croct.evaluate`), React (`@croct/plug-react`, `<CroctProvider>`, `useContent`, `<Slot>`, `useEvaluation`, `useCroct`), Next.js (`@croct/plug-next`, `fetchContent`, `cql`, middleware/proxy, `NEXT_PUBLIC_CROCT_APP_ID`, `CROCT_API_KEY`), Vue (`@croct/plug-vue`), Nuxt (`@croct/plug-nuxt`), Shopify Hydrogen (`@croct/plug-hydrogen`), PHP (`croct/plug-php`), Laravel, Symfony, and Drupal. Triggers: slot IDs like `home-hero@1`, `SlotContent`, "Croct is not plugged in", "initial content is required for server-side rendering", "Did you forget to configure Croct's middleware?", CORS errors.

What is agent-skills?

agent-skills is a Claude Code agent skill that >- Use when installing or using a Croct SDK in application code: rendering slot content, evaluating CQL queries, server or client fetching, prerendering, identifying users, app ID / API key env vars, testing, or debugging. Covers JavaScript (`@croct/plug`, `croct.fetch`, `croct.evaluate`), React (`@croct/plug-react`, `<CroctProvider>`, `useContent`, `<Slot>`, `useEvaluation`, `useCroct`), Next.js (`@croct/plug-next`, `fetchContent`, `cql`, middleware/proxy, `NEXT_PUBLIC_CROCT_APP_ID`, `CROCT_API_KEY`), Vue (`@croct/plug-vue`), Nuxt (`@croct/plug-nuxt`), Shopify Hydrogen (`@croct/plug-hydrogen`), PHP (`croct/plug-php`), Laravel, Symfony, and Drupal. Triggers: slot IDs like `home-hero@1`, `SlotContent`, "Croct is not plugged in", "initial content is required for server-side rendering", "Did you forget to configure Croct's middleware?", CORS errors.

Works with~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/croct-tech/agent-skills/tree/HEAD/skills/croct-integrate-sdk

Installed? Explore more Coding & Development skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · View all 6 →

Ask in your favorite AI

Open a new chat with this agent skill pre-loaded.

Documentation

Integrate a Croct SDK

Wire a Croct SDK into an app so it renders slot content, evaluates CQL, and identifies users. Content and audiences live in the Croct dashboard; the code only references slots by ID and version and supplies a fallback.

Workflow

- [ ] 1. Detect the stack and pick the SDK (table below)
- [ ] 2. Install with the CLI (`croct init`, run by the user), manual only if asked or the CLI cannot run
- [ ] 3. Add the slot with the CLI (`npx croct@latest add slot home-hero@1 --example`) for types + fallback
- [ ] 4. Render it: server-side when the framework allows, client-side otherwise
- [ ] 5. Identify/anonymize users at login/logout (or pass the user ID at init)
- [ ] 6. Verify: Integration page shows "Received traffic in the past 24 hours"; else debug mode

1. Pick the SDK

Read package.json / composer.json first. Pick the most specific SDK for the framework; never use the plain JavaScript SDK inside React, Next.js, Vue, Nuxt, or Hydrogen.

StackPackageInitialize withServer renderingReference
Plain JS, any bundler, or <script> tag@croct/plug (or https://cdn.croct.io/js/v1/lib/plug.js)croct.plug({appId}) once at startupStandalone fetchContent/evaluate from @croct/plug/api with apiKeyjavascript.md
React (SPA, Vite, any non-Next SSR)@croct/plug-react<CroctProvider appId="..."> at the rootClient hooks need initial; low-level @croct/plug-react/apireact.md
Next.js (App or Pages Router)@croct/plug-nextmiddleware (≤15) / proxy (≥16) + <CroctProvider> from @croct/plug-next/CroctProviderYes: @croct/plug-next/servernextjs.md
Vue@croct/plug-vueapp.use(createCroct({appId}))Composables/components; SSR needs initial valuesvue.md
Nuxt@croct/plug-nuxtmodules: ['@croct/plug-nuxt'] in nuxt.configYesnuxt.md
Shopify Hydrogen (React Router 7 or Remix)@croct/plug-hydrogenVite plugin + createCroctMiddleware / createCroctContext from @croct/plug-hydrogen/serverYeshydrogen.md
Plain PHPcroct/plug-php (+ a PSR-18 client, e.g. guzzlehttp/guzzle nyholm/psr7)Croct::fromDotenv() then Croct::emitCookies() before outputYes (server-first)php.md
Laravelcroct/plug-laravel.env credentialsYeslaravel.md
Symfonycroct/plug-symfony symfony/twig-bundleRegister bundle in config/bundles.php + .env credentialsYes (Twig)symfony.md
Drupalcroct/plug-drupalEnable module; credentials in settings.php; rebuild cacheYesdrupal.md
Storyblok (JS or PHP)—Use the croct-integrate-platforms skill——
Unsupported language or raw HTTP—Use the croct-use-api skill——

2. Install

Every SDK's integration page, including PHP, Laravel, Symfony, Drupal, and Hydrogen, recommends the CLI. init is interactive and needs a signed-in session, so ask the user to run it from the project root in their own terminal:

npx croct@latest init

croct init detects the framework, signs in, selects the organization/workspace/application, installs the matching SDK, and wires the setup (provider, middleware, env vars). When the user already has a session and knows the IDs, you can run the non-interactive form yourself: npx croct@latest --no-interaction init --sdk next --org <org> --wor <workspace> --dev-app <dev-app> --prod-app <prod-app> (--sdk accepts only javascript, react, vue, next, nuxt; omit it to auto-detect). Flags, CI use, and croct.json live in the croct-use-cli skill. Fall back to the manual steps in the framework's reference file only when the user asks or the CLI cannot run.

3. Add the slot

Always pass the slot ID and version. Without them, the CLI prompts for a slot, which you cannot answer:

npx croct@latest add slot home-hero@1 --example

This generates TypeScript types (so useContent('home-hero@1') / fetchContent('home-hero@1') are typed), downloads the slot's default content as automatic fallback, and writes a working example. Re-run croct install / croct update to resync after dashboard changes (see croct-use-cli).

Core concepts (all SDKs)

Slot IDs and versions

  • Reference a slot as <id>@<version>, e.g. home-hero@1. No version (home-hero) means home-hero@latest.
  • Always pin a version. Unpinned slots pick up breaking schema changes immediately. When the dashboard creates a new major version, the app keeps receiving the old version until the code is bumped.
  • Type content with SlotContent<'home-hero@1'> and ComponentContent<'card@1'> (exported by @croct/plug, @croct/plug-react, @croct/plug-next). Union slots resolve to a discriminated union on _type.

Fallback, default, and initial content

TermWhat it isWhere it comes from
Default contentSlot content shown when no experience matches, the locale has none, static content is requested, or retrieval failsDashboard
FallbackValue rendered when the request failsfallback option in code, else CLI-downloaded default content (@croct/content)
Initial (React/Next client hooks)Value rendered during SSR/prerender and while loading on the clientinitial option; CLI adds it automatically

Resolution order in the SDK: dynamic content → explicit fallback → CLI default content → error. Without a fallback and without CLI content, a failed fetch throws (JS croct.fetch rejects). Read CLI content directly with getSlotContent(slotId, locale?) / loadSlotContent(slotId, locale?) from @croct/content (prefer the async one with code splitting).

Client vs server rendering

NeedDo
Final content in first HTML, no flicker, crawlableFetch on the server (Next fetchContent from @croct/plug-next/server, Nuxt, Hydrogen, PHP family)
Page must stay a static file / CDN / output: 'export'Client hooks/components with an initial value or a <Suspense> boundary
Below-the-fold section where a skeleton is fineClient-side is fine
Server rendering in plain React / custom SSRfetchContent / evaluate from @croct/plug-react/api (or @croct/plug/api) with apiKey, then pass content as props

Server-side requests authenticate with an API key (never ship it to the browser); client-side requests use the application ID. Passing both appId and apiKey to a standalone function is an error.

Query evaluation

Evaluate CQL at runtime with croct.evaluate(query, {attributes}) (JS), useEvaluation / <Personalization> (React/Next client), or evaluate / cql`...` (Next server). Queries are limited to 500 characters; results can be any JSON ('location' returns an object). Always supply a fallback (.catch(() => false) or fallback: false). CQL syntax: croct-cql skill.

Evaluation or slot? The docs present slots as the way to update content without code changes; an evaluated query lives in code and changes only with a deploy.

NeedUse
Content, audience, or rollout that marketers change, schedule, or A/B testA slot plus an experience (see croct-personalize-and-test)
Logic fixed by engineering (show/hide a widget, branch on a condition), no content to editevaluate / useEvaluation with a fallback

Context attributes

Pass app-specific data (plan, cart state) as attributes (JS/React) or context.attributes (Next server, standalone functions); read it in CQL as context's plan is "premium". Limits: up to 30 entries, 5 levels deep, keys ≤ 50 chars, string values ≤ 50 chars.

Credentials and environment variables

StackApp IDAPI key
Next.jsNEXT_PUBLIC_CROCT_APP_IDCROCT_API_KEY
NuxtNUXT_PUBLIC_CROCT_APP_IDNUXT_CROCT_API_KEY
HydrogenPUBLIC_CROCT_APP_IDCROCT_API_KEY
PHP, Laravel, SymfonyCROCT_APP_IDCROCT_API_KEY
Drupal$settings['croct.app_id']$settings['croct.api_key']
JavaScript, React, VueappId option / propserver-side standalone functions only
  • Find the app ID on the application's Integration page; create keys on its API keys page.
  • For server SDKs that issue user tokens (Next.js), the API key needs the Issue user tokens permission.
  • Each environment has its own application. A production app ID used on localhost (or vice versa) fails with invalid credentials.

Identify and anonymize

  • Call identify(userId) on login/sign-up and anonymize() on logout. Identity changes end the current session and start a new one.
  • If the user is already logged in when the page loads, pass the ID at init (userId in croct.plug / <CroctProvider>) so the SDK does not create an extra anonymous session.
  • userId must be a string; convert numeric IDs (preferably server-side). Prefer random IDs (UUID v4) over emails or sequential numbers.
  • When Require signed token is on in Application settings, userId/identify (unsigned tokens) fail; pass a signed token instead. Next.js signs tokens for you with CROCT_API_KEY.
  • Next.js: prefer withCroct({userIdResolver}) in middleware/proxy to keep the token in sync with the auth session on every request.

Plug options worth knowing

appId, debug, test, track (auto tracking, default true), userId / token (mutually exclusive), tokenScope (global | isolated | contextual), defaultFetchTimeout (JS/React 5000 ms; Next 2000 ms), defaultPreferredLocale, baseEndpointUrl (mock servers), cookie (store client ID / user token / preview token in first-party cookies), eventMetadata, urlSanitizer, logger. Full list: javascript.md.

Tracking and data collection

Track goals with croct.track('goalCompleted', {goalId}); edit profile/session with croct.user.edit().set(...).save() / croct.session.edit(). Event catalog, recommended events, and attribute rules: croct-track-events skill.

Pitfalls

Do:

  • Pin slot versions (home-hero@1) and keep fallbacks (CLI default content or explicit).
  • Provide initial (or <Suspense>) for every client useContent/useEvaluation that may render on the server.
  • Call client-only Plug methods (useCroct().track, identify, user.edit) inside useEffect or event handlers, never during render.
  • Add every domain that loads the SDK to the application's Trusted origins.
  • Turn on debug mode first when something is off (debug: true, NEXT_PUBLIC_CROCT_DEBUG=true), then check the Network tab.

Don't:

  • Call croct.plug twice (call unplug() first) or call any method before plug ("Croct is not plugged in").
  • Put the API key in client code or in NEXT_PUBLIC_* variables.
  • Specify the app ID both in the script tag ?appId= and in plug (conflicting app ID error).
  • Call Next fetchContent on a route you want to stay static; it opts the route into dynamic rendering. Use client hooks there.
  • Use the cql tag outside the Next.js App Router; use evaluate with route.

Common errors

ErrorFix
Croct is not plugged in.Call croct.plug at startup before other calls
The app ID must be specified when it cannot be auto-detected.Pass appId (or ?appId= on the script tag)
The request was not authorized, most likely due to invalid credentials.Wrong app ID, wrong environment, expired/tampered token (clear cookies + local storage), or unsigned token with Require signed token on
CORS error / The origin of the request is not allowed in your application settings.Add the domain under Trusted origins
The user ID must be a string.Convert the ID to a string
The request timed out.Raise timeout / default timeout; check X-Croct-Timing / X-Croct-Region in debug logs
The query is too complex.Query over 500 chars; simplify, split, or pass data via attributes
The service is temporarily suspended.Not a code bug: workspace suspended or bot traffic (X-Suspension-Reason); keep fallbacks
The application has exceeded the monthly active users (MAU) quota.Upgrade plan or wait for next cycle
useCroct() can only be used in the context of a <CroctProvider> component.Wrap the tree in <CroctProvider>
The initial content/value is required for server-side rendering (SSR).Add initial, or fetch on the server
Did you forget to configure Croct's middleware?Add Next middleware/proxy
someFunction() requires specifying the route parameter outside app routes.Pass route: context (Pages Router/API routes)
Did you forget to set the SOME_ENV_VAR environment variable?Set NEXT_PUBLIC_CROCT_APP_ID / CROCT_API_KEY
Content not updated after publishing (no error)Client hooks cache results for expiration (60 s, extended on every render); change cacheKey to force a refetch. Check the change is published, not a draft. A pinned version (home-hero@1) never gets a new major version: run croct upgrade. Stale fallback after a failed request: croct update refreshes CLI default content

Reference index

Load only the file for the stack in use.

Live docs

  • SDK index: https://docs.croct.com/reference/sdk.md
  • Any SDK page as markdown: https://docs.croct.com/reference/sdk/<framework>/<page>.md (e.g. .../nextjs/content-rendering.md)
  • Search: https://docs.croct.com/api/search.md?term=<terms>; index: https://docs.croct.com/llms.txt

Individual skills in this repo

This repo contains 4 individual skills — each has its own dedicated page.

croct-tech/agent-skills

>- Use when writing, reading, reviewing, or debugging Croct's Contextual Query Language (CQL): audience criteria, `croct.evaluate()` / `useEvaluation` / `<Personalization query>` / Next.js `cql` tag queries, Evaluation API `query` bodies (`/client/web/evaluate`, `/external/web/evaluate`), and dynamic content values (`"type": "dynamic"`, `"expression"`). Covers context variables (user, session, page, location, campaign, cart, device, browser, context, now/today), data types and conversions, accessors and selectors (`'s`, `property X of`, `[1st]`, `[*]`, `[...]`), tests (`is`, `matches`, `is like`, `contains either`, `is between`, `is defined`, `is returning`), quantifiers (`some ... satisfies`), macros, modifiers, event expressions (`user has viewed a page`, `user has abandoned a cart`, `user has completed goal`), audience estimation, and recipes. Triggers: "write an audience", "target mobile users in New York", "CQL syntax error", "audience never matches", "unavailable estimate".

croct-tech/agent-skills

>- Use when connecting Croct to a third-party platform or migrating to Croct from another personalization or experimentation tool. Covers Storyblok (Optimize by Croct app, @croct/plug-storyblok, Storyblok withCroct, resolveContent, croct/plug-storyblok, CroctStoriesApi), Sanity and Strapi (slot fallback, dynamic zones, metadata.contentSource), Shopify Hydrogen storefront events, Shopify custom pixel (croctPixel, PUBLIC_CROCT_SHOPIFY_PIXEL, checkout and order tracking), VTEX, Google Tag Manager data layer, Microsoft Clarity tags, HubSpot forms (hbspt.forms.create, hs-form-event), firmographic providers 6sense, Demandbase, Clearbit Reveal, and ZoomInfo WebSights (firmographics attributes, account-based audiences in CQL), and migrations from Mutiny and Ninetailed (Experience component, Contentful sunset). Triggers include cdn.croct.io/plug-integration scripts, "personalize Storyblok blocks", "track Shopify checkout", "send VTEX events", "ABM personalization", "replace Mutiny".

croct-tech/agent-skills

>- Use when designing or changing Croct content models: regular vs union components, what becomes a component, slot, structure, or primitive attribute; writing component schema JSON (`structure`, `union`, `reference`, `text`, `number`, `boolean`, `list`, `@croct/file`, `@croct/richText` rich text, `format`, `choices`, `optional`, `private`, `position`); writing content definition JSON (`static`/`dynamic` values, `nullable`, `default`, `{{placeholder}}` paths); slot default, localized, experience, experiment, or content group content; schema limit errors (30 attributes, 6 nesting levels, 10 union members, complexity score 50); component versioning and breaking changes (`home-hero@2`); refactoring (duplicate and modify, duplicate and replace, flatten and merge); Markdown in text attributes with `@croct/md-lite`. Phrasings: "model content for a hero", "add an attribute to the banner component", "support variations", "component is too complex", "localize the hero", "translations", `preferredLocale`.

croct-tech/agent-skills

>- Use when planning or implementing personalization or A/B testing with Croct: creating an experience (audience, slots, content, priority, scheduling, drafts), adding an experiment (A/B/n, primary goal ID, traffic allocation, variants, cross-device consistency), wiring the code it needs (slots, `croct.track('goalCompleted', {goalId})`, `orderPlaced`, `leadGenerated`, `userSignedUp`), server-side feature-flag experiments, redirect experiments, personalization recipes (UTM campaigns, ABM, search terms, location, free shipping, interests, blog readers, leads, customers, organic intent, HubSpot forms), or reading the experience, experiment, application, or workspace dashboards (probability to be best, potential loss, "Experiment in progress", "Recommended winner", "No clear winner", "Track your goal"). Phrasings: "personalize the hero for LinkedIn visitors", "A/B test this CTA", "which variant won?", "why does my experiment show no conversions?".

Related Skills