TypeScript SDK
One package with six entry points. Import the one that matches your runtime, and the tree-shaken build leaves the rest out of your bundle.
Where it is published
@prodantix/sdk on npm.
Install
bun add @prodantix/sdkEntry points
Every subpath ships its own ESM and CommonJS build with its own types. The root is runtime agnostic, and the others add what one runtime needs.
| Subpath | What it exports |
|---|---|
| @prodantix/sdk | ProdantixClient, createClient, evaluateFlag, FlagsClient, MessagesClient |
| @prodantix/sdk/web | createWebClient, installAutocapture, installSessionReplay, WebTransport |
| @prodantix/sdk/node | createNodeClient |
| @prodantix/sdk/csp | prodantixConnectSrc, prodantixScriptSrc |
| @prodantix/sdk/chat | mountChat, ChatClient, ChatPanel, resolveAppearance |
| @prodantix/sdk/messenger | fetchMessengerConfig, cachedMessengerConfig, MESSENGER_CACHE_KEY |
@prodantix/sdk
The client, the flag evaluator, and the storage and transport interfaces. Nothing here touches the DOM, so you can supply your own storage, transport, clock or id factory and run it anywhere.
import { createClient, MemoryStorage } from '@prodantix/sdk';
const prodantix = createClient({
apiKey: PRODANTIX_PUBLIC_KEY,
host: 'https://eu.api.prodantix.com',
storage: new MemoryStorage(),
});
prodantix.capture('order.completed', { properties: { amount: 4200, currency: 'XAF' } });
await prodantix.flush();@prodantix/sdk/web
Browser wiring over the same client: persistence in local storage, delivery by beacon when the page hides, and pageview plus click autocapture. Session replay stays off until you give it a replay host.
import { createWebClient } from '@prodantix/sdk/web';
const prodantix = createWebClient({
apiKey: PRODANTIX_PUBLIC_KEY,
host: 'https://eu.api.prodantix.com',
flagsHost: 'https://api.prodantix.com',
autocaptureOptions: { clicks: true, pageviews: true },
});
prodantix.identify('user-42', { set: { plan: 'pro' } });
if (await prodantix.isFeatureEnabled('new-checkout')) {
// ...
}
// Every per-flag read records one $feature_flag_called exposure.
const variant = await prodantix.getVariant('new-checkout');
if (variant?.key === 'treatment') {
// ...
}
// A flag targeting a cohort reads this user's memberships from the store;
// pass them yourself to skip the lookup.
if (await prodantix.isFeatureEnabledLocal('members', { cohorts: ['<cohort id>'] })) {
// ...
}@prodantix/sdk/node
The same client with server defaults. Events are buffered and flushed in the background, so call shutdown before the process exits or the last batch never leaves.
import { createNodeClient } from '@prodantix/sdk/node';
// A node client streams flag changes over Socket.IO by default and refetches
// the snapshot on push; streamFlags: false leaves only the 30s poll.
const prodantix = createNodeClient({
apiKey: process.env.PRODANTIX_PUBLIC_KEY,
host: 'https://eu.api.prodantix.com',
streamFlags: true,
});
prodantix.capture('job.completed', { properties: { queue: 'emails' } });
await prodantix.shutdown();@prodantix/sdk/csp
The content security policy sources an app needs to reach Prodantix. It imports nothing from React or the browser, so a build config file can read it directly.
import { prodantixConnectSrc, prodantixScriptSrc } from '@prodantix/sdk/csp';
const hosts = {
ingest: 'https://eu.api.prodantix.com',
edge: 'https://eu.edge.prodantix.com',
replay: 'https://eu.replay.prodantix.com',
};
const policy = [
`connect-src ${prodantixConnectSrc(hosts)}`,
`script-src ${prodantixScriptSrc(hosts)}`,
].join('; ');@prodantix/sdk/chat
The support widget. Mount it and you get a handle that opens, closes, destroys and identifies. It renders inside a closed shadow root, so the styles of the host page never reach it.
import { mountChat } from '@prodantix/sdk/chat';
const messenger = mountChat({
apiKey: PRODANTIX_PUBLIC_KEY,
host: 'https://eu.edge.prodantix.com',
distinctId: prodantix.distinctId,
});
document.querySelector('#help')?.addEventListener('click', () => messenger.open());@prodantix/sdk/messenger
The settings reader behind the widget: it fetches the messenger configuration for a project, caches it, and reports whether the project has the messenger switched on. The self-executing snippet is built separately and is not reachable through this subpath.
import { fetchMessengerConfig } from '@prodantix/sdk/messenger';
const config = await fetchMessengerConfig({
apiKey: PRODANTIX_PUBLIC_KEY,
host: 'https://eu.edge.prodantix.com',
});
if (config?.enabled) {
// the project has the messenger switched on
}