Overview
Core resolves two things on every visit: which project the request belongs to, and who the visitor is — an anonymous identifier (app user ID) Core generates the first time someone visits, with no login or account required, and persists across sessions (cookie/local storage). Every other SDK reads that identity from Core instead of resolving it independently, so it only needs to be established once per session. Core performs no network calls itself; identity and config resolution are purely local. It is a required dependency for every product SDK on this site.Implementation
Install
Project config
Generate config with the Embeddables CLI, then import the output in every Core entry point:publishableKey when initializing if it is not already in the generated file — use the keys em init printed, or find them under Settings → Portal / SDK in the admin app.
Client (browser)
initEmbeddables returns an EmbeddablesInstance — the object every other SDK’s core option expects. Its read methods are getAppUserId, getProjectId, getPublishableKey, and getExperiments.
Server
Use the server entry point for SSR / Node code. It needs a way to read cookies from the incoming request, since it can’t touchlocalStorage:
SSR identity handoff
When you render on the server first, read the id frominitEmbeddablesServer, serialize it in your loader or page props, and pass it into EmbeddablesProvider as serverAppUserId. The provider forwards that value to initEmbeddables, which writes it to browser storage before any product SDK runs.
serverAppUserId if you want the same id immediately, because browser Core does not re-read response headers during React initialization.
React
Install the peer dependency and wrap your app once, above every product SDK:modules prop registers the product SDKs (Analytics, Experiments, Forms) on the provider — the product hooks on each SDK’s page read their client back from it. The CLI generates that list in embeddables/_dist/modules from your config.yaml when you run em build, ordered analytics → experiments → forms. If you only use Core, omit modules; add it as soon as you enable a product SDK.
useEmbeddables is the hook name; embeddables is the recommended name for the returned value.
Initialization runs in an effect after the component mounts, never during server rendering. So
useEmbeddables() returns null and useAppUserId() returns null on the server render and the
very first client render — even if you passed serverAppUserId. Always handle that loading state;
don’t assume the instance is available immediately.Do I ever call Core directly?
Usually not much beyond initializing it. Its getters (getAppUserId, getProjectId, getPublishableKey, getExperiments) are mostly consumed internally by Analytics, Experiments, and Forms — you’ll interact with those SDKs directly far more often than with Core’s own API. Experiments reads getExperiments() for its config instead of taking a separate experiments option.
