Skip to content

Configuration Reference

Complete reference for RevTurbineInitOptions and related configuration types.

In revturbine_server and custom_endpoints modes the browser needs publicKey; tenantId is optional because the key names its tenant. In local_only mode neither is needed — initRevTurbine({ runtimeMode: 'local_only', localRuntime: { playbook } }) is a complete configuration. For copy-paste examples per runtime, see Initialize the SDK.

FieldTypeDescription
tenantIdstringYour RevTurbine tenant identifier. Optional whenever publicKey is supplied: the key is bound to one tenant and the SDK reads the tenant back from the Playbook it fetches. A tenantId that disagrees with the key’s tenant is ignored with a one-time warning; the key wins. Required by RevTurbineServer, where it must be the server key’s own tenant.
publicKeystringIn the browser: your public key (rtk_…, type public, minted under Settings → API Token Management → Ingest Keys). Safe to ship in a bundle. Add your app’s origins to the key’s allowed origins, or Playbook delivery is refused with 403 origin_not_allowed. See Production Readiness → Keys.
apiKeystringYour server key (rtk_…, type server), minted under Settings → API Token Management → Server Token. Trusted backend initRevTurbine in RuntimeMode.Server uses it for Playbook delivery and event ingest; RevTurbineServer uses it for client sessions and server-only writes. Evaluation remains local. Never ship it to a browser. As of 0.11.0 it is not accepted as a browser credential — pass publicKey there; ingestPublicKey was removed (BL-0113).
FieldTypeDefaultDescription
runtimeMode'revturbine_server' | 'custom_endpoints' | 'local_only''revturbine_server'How the SDK loads its Playbook; evaluation remains local
endpointstring'https://revturbine.com/app'RevTurbine control-plane URL; omit it for the hosted service
mode'react' | 'snippet' | 'iframe''snippet' ('react' when <RevTurbineProvider> initializes the SDK)Integration label carried in telemetry; no decision depends on it
endpointOverridesPartial<RevTurbineEndpointOverrides>—Route the SDK’s non-decision calls through your own endpoints (custom_endpoints mode)
configProviderRevTurbineConfigProvider—Custom provider for the Playbook; implement getPlaybook()
localRuntimeRevTurbineLocalRuntimeOptions—Local-only mode configuration
FieldTypeDefaultDescription
providerRevTurbineSdkProvider | RevTurbineProviderFactory—Primary provider override
providerFallbacksArray<...>—Fallback provider chain
domainProvidersAnyDomainProvider[]—Domain-specific providers
providerFailureSlotBehavior'placeholder' | 'invisible''invisible'Slot behavior after provider failure
FieldTypeDefaultDescription
uiPathResolversRevTurbineUiPathResolverMap—Map of CTA action types to resolver functions
FieldTypeDefaultDescription
brandingBrandingConfigBuilt-in defaultsOptional workspace name, logo and partial theme. An explicit value takes priority over API branding and legacy config themes.

See Theming for an example. Set colorScheme: 'light' or 'dark' in initialization, use the React provider’s colorScheme prop, or call session.sdk.setColorScheme(scheme) in a headless integration (SDK 0.12.4).

FieldTypeDefaultDescription
userRevTurbineUserContext—Initial user context. plan_handle is the plan’s unique_handle — the value plan-scoped rules match on
clientSession() => string | Promise<string>—Mints a client-session token so the SDK keeps server-derived context fresh on its own. See Server-derived context
pageRevTurbinePageContext—Page context (URL, title, referrer, tags)
contextPolicyRevTurbineContextPolicy{ inferUser: true, inferPage: true, routerAutoTrack: true }Auto-inference behavior

Your app tells RevTurbine who the user is. Some of that state, though, is only knowable on your server — the plan a Stripe webhook just changed, trial status, a payment that failed. clientSession is how the SDK gets it without you wiring a refresh loop.

Supply a function that returns a client-session token minted by your backend (POST /api/sdk/client-sessions, with the server key; RevTurbineServer does it for you). The SDK calls it when it first needs a token, again after identify(), and again if the control plane reports one expired — then fetches GET /api/sdk/client-context and folds the result into its decisions. A purchase updates what the user can do with no further app code.

TypeScript
import { initRevTurbine } from '@revturbine/sdk';
export async function startRevTurbine() {
return initRevTurbine({
publicKey: process.env.NEXT_PUBLIC_REVTURBINE_PUBLIC_KEY!, // public key — safe in the browser
user: { id: 'user_123', plan_handle: 'free' },
clientSession: async () => {
const response = await fetch('/api/revturbine-session', { method: 'POST' });
if (!response.ok) throw new Error(`RevTurbine client session failed (${response.status})`);
const body: { client_token: string } = await response.json();
return body.client_token;
},
});
}

The route behind /api/revturbine-session is yours: it authenticates your user, mints with the server key and returns only client_token. The complete route (Next.js and Express), the failure behavior and the refresh rules are on Client sessions.

It is a function, not a token, because these tokens are short-lived (~10 minutes) — a value captured at init would go stale mid-session, and refreshing it would become your problem.

The token is a transport credential, never user context: held in memory only, never persisted, never logged, never placed in a URL. If your minter throws or the fetch fails, the SDK keeps using the context your app supplied — enrichment is best-effort and never breaks your app.

Omit clientSession and none of this happens: no token is requested and no client-context call is made. Server-derived context is opt-in.

FieldTypeDefaultDescription
placementBehaviorPartial<RevTurbinePlacementBehaviorFlags>derived from the PlaybookOverrides for flags the SDK derives from what the Playbook authors (see below)
FieldTypeDefaultDescription
persistentStorageRevTurbineStoragelocalStoragePersistent storage override
sessionStorageRevTurbineStoragesessionStorageSession storage override

FieldTypeDefaultDescription
inferUserbooleantrueAuto-detect user info from browser APIs
inferPagebooleantrueAuto-capture URL, title, referrer
routerAutoTrackbooleantrueTrack SPA route changes

FieldTypeDescription
playbookPlaybookFull Playbook snapshot for local execution
placementsLocalPlacementDatasetOptional static placements dataset
initialDataobjectStatic data for local decisions (see below)
resolversobjectOptional resolver callbacks (see below)
storageKeystringOptional localStorage key override
getContext() => Promise<JsonObject>Reactive context callback
FieldType
placementDecisionsByPlacementIdRecord<string, RevTurbinePlacementDecision>
userContextByUserIdRecord<string, UserTargetingContext>
trialStatusRevTurbineTrialContext

Entitlement grants are evaluated from localRuntime.playbook. For a custom source, implement the documented checkEntitlement resolver; do not seed grants through initialData.

Placements work the same way: getPlacement is a pure function of the user context and localRuntime.playbook, evaluated through the same decision path as getPlacementDecision and the server SDKs. There is no seeded-output lane: initialData.placementsByLookupKey was removed in 0.12.0 (ignored since 0.11.21). Author the placement in the Playbook instead, or implement the getPlacement resolver for a custom source.

FieldSignature
getPlacementDecision(input, placement?, context?) => Promise<RevTurbinePlacementDecision>
getPlacement(config) => Promise<PlacementOutput | null>
checkEntitlement(handle, context?) => Promise<EntitlementResult>
fetchUserContext(userId) => Promise<UserTargetingContext>
getTrialStatus() => Promise<RevTurbineTrialContext>
resolvePlaybook() => Promise<Playbook>

Each flag is derived from the loaded Playbook; an explicit value in placementBehavior overrides the derivation. You rarely need to set them.

FlagTypeDerived defaultDescription
enableClientCapsEnforcementbooleantrue when any placement payload authors a cap, cooldown, or remind-laterClient-side cap enforcement
enableAutoGatedPlacementbooleantrue when the Playbook has a gated placementAuto-render gated placements
enableTrialAutoTriggersbooleantrue when the Playbook has a trials placementAuto-derive trial lifecycle triggers

The calls the SDK makes over the network, and the key that reroutes each one in custom_endpoints mode. None of them is a decision — entitlements and placements are evaluated inside your app in every mode. A relative value is appended to endpoint; an absolute URL replaces it.

KeyWhat it carriesDefault path
clientContextServer-derived user context, read with an rt_client_ session token/api/sdk/client-context
userContextUser context read/api/sdk/user-context
trialStatusTrial status read/api/sdk/trial-status
ingestEventsClickstream events (track / capture)/api/track
touchpointTransitionPlacement interactions — impression, dismiss, CTA/api/events/interactions
ingestSdkMetaThe anonymous sdk_init beacon/api/sdk/meta
surfaceSlotsSurface-slot inventory registration/api/placements
placementTypesCustom placement-type persistence — meaningful only when overridden/api/sdk/placement-types

Not overridable: Playbook delivery. The SDK fetches the launched Playbook from endpoint directly (/api/sdk/bootstrap, then the signed manifest and bundle), so custom_endpoints routes context and telemetry through your proxy but not the Playbook itself.

Keep endpoint pointing at RevTurbine and use absolute override URLs for a proxy on another origin. In local mode, import the Playbook checked into your app. In either mode, preserve the validated artifact: do not insert an app endpoint that reshapes or strips Playbook fields before the SDK reads them. See Runtime Modes.

The type also declares decide, decideContext, bootstrapContext, getPlacement and checkEntitlement. They are retired: the SDK never reads them, because there is no decision endpoint. They remain on the type so existing configurations still compile.


Interface for custom storage providers:

TypeScript
interface RevTurbineStorage {
getItem(key: string): string | null;
setItem(key: string, value: string): void;
removeItem(key: string): void;
}

TypeScript
{
tenantId?: string; // optional: the key names its tenant
publicKey: string; // ✅ Required (public key, browser). `apiKey` is not read here: a server uses a Playbook snapshot instead
endpoint?: string; // defaults to 'https://revturbine.com/app'
mode?: string; // defaults to 'snippet' ('react' via the provider)
}
TypeScript
{
runtimeMode: 'local_only'; // ✅ Required
localRuntime: {
playbook: Playbook; // ✅ Required
};
// tenantId, publicKey, endpoint, mode — optional; no account or key is needed
}
TypeScript
{
tenantId?: string; // optional: the key names its tenant
publicKey: string; // ✅ Required (public key, browser)
endpoint?: string; // defaults to 'https://revturbine.com/app'
mode?: string; // defaults to 'snippet' ('react' via the provider)
runtimeMode: 'custom_endpoints'; // ✅ Required
endpointOverrides: { // ✅ At least one override required
clientContext?: string;
ingestEvents?: string;
touchpointTransition?: string;
};
}