Skip to content

Runtime and Playbook

For the complete body inventory and reference relationships, see the Playbook field map.

Every RevTurbine decision, whether it is “may this user export?” or “which banner should this user see?”, is one calculation with two inputs:

  • the Playbook: what you decided about plans, entitlements, targeting and messages. It is the same for every user, and you author it.
  • the Runtime: who is asking right now, and what they have used. It is different for every user and changes while they use your app.

The SDK combines the two locally, in your app or on your server. Nothing in that calculation waits on RevTurbine.

Playbook (authored, versioned) Runtime (per user, per moment)
plans · entitlements · segments UserContext · usage · app answers
placements · payloads (AccountContext: planned)
\ /
\ /
+---- SDK: local evaluation ----+
|
entitlement result · winning placement
|
your UI renders it · your server enforces it

The Playbook is the portable artifact RevTurbine evaluates: one JSON file, revturbine.playbook.json, that you edit in the dashboard, with the CLI or with your coding agent. Every launch is an immutable, versioned Release. In local mode you bundle the file; in hosted mode the SDK fetches the launched Release. Either way the SDK evaluates the same artifact the same way.

PrimitiveIn plain EnglishWhy it existsExample
PlanA tier a customer can be on. A plan can have more than one price, each called a plan variation (monthly, annual or regional); variations share the plan’s tier, so switching between them is never an upgrade.So your app asks “what is this user entitled to?” instead of “are they on Pro?”starter, pro
EntitlementOne thing a user may be allowed to do, and how much: a feature, a usage limit, credits or seats.One vocabulary for gating, metering and upgrade prompts.batch_export, api_calls (limit 1,000)
Entitlement ruleSays which plans, segments or seat types get an entitlement, and how much.Changing who gets what is a Playbook edit, not a deploy.”Pro gets api_calls up to 1,000 a month”
SegmentA named group of users, defined by rules over their context.Targeting and experiments: show this to trial users only.trial_users
PlacementA message the engine may show at the right moment: a banner, modal, toast or button. Its payload is the copy, offer and call to action.Upgrade prompts are decided by caps, cooldowns and priority, not by your code.A “you have 5 exports left” banner

Related terms you will meet:

  • An add-on is something a customer buys on top of a plan.
  • A gate is where your app asks an entitlement question (<Gate>, gate(), can()); a slot is where your app can show a placement (<Slot>). Both are covered in Core Concepts.

The Runtime is everything the SDK knows about the moment of the decision.

PieceIn plain EnglishWho supplies it
UserContextThe user: id, plan, usage balances, trial state, custom traits.Your app at init and as things change, plus plan, trial and payment state from Stripe through a client session in hosted mode. See RevTurbineUserContext.
UsageHow much the user has consumed. Always an absolute balance, never a delta.Your app (update({ usage })).
App answersWhen your own system already decides an entitlement, you pass its answer in the entitlements field. This is Entitlement Mirroring.Your app.
Entitlement grantWhat a user ends up with for one entitlement, and where it came from: a rule, an answer your app passed, or an override.Derived by the engine.

Your app’s own answer and the Playbook’s can disagree. By default your app’s answer wins, and the Playbook’s rule is then only used to tell you which plans include the entitlement. That default is the Entitlement Mirroring precedence setting; set it the same way in the browser and on your server so they agree. It is separate from how overrides combine, below.

  1. Initialize. You give the SDK the Playbook (a bundled file, or a public key so it can fetch the launched Release) and the user. See Initialize the SDK.
  2. Load. In hosted mode the SDK fetches the Playbook once and re-checks for a new Release about once a minute, keeping the last good copy if a refresh fails. Until the first Playbook arrives, a check denies with config_unavailable. It never grants on a guess.
  3. Change the context. identify(), update() and a client-session refresh change the Runtime. The SDK re-evaluates against the Playbook it already holds. No Playbook is fetched for that.
  4. Decide. can() returns an entitlement result; a <Slot> returns the one placement that won, after eligibility, caps, cooldowns and priority.

Local evaluation is what keeps this fast and independent of RevTurbine’s availability. Two boundaries matter:

  • Browser versus server. The browser’s decision drives the UI. It is a convenience, because a user controls their own browser. Your server makes the decision that protects money and data, by building its own instance from the Playbook and its own record of the user. See Client vs Server Enforcement.
  • Local versus hosted. Hosted changes where the Playbook and the server-derived user state come from, not where the decision runs. See Runtime Modes.

You sell a “batch export” feature, included in Pro, with a limit of 10 exports a month on Starter.

  • Playbook: the batch_export entitlement; one rule that gives Pro unlimited and Starter a limit of 10; a placement that shows an upgrade banner when a Starter user has used 8.
  • Runtime: Maya is on Starter and has used 8 (UserContext and usage).
  • Decision: can('batch_export') returns allowed, with 2 remaining. The banner placement is eligible, so the <Slot> shows it.
  • Change: Maya upgrades. Stripe tells RevTurbine; the client session brings the new plan to the SDK; the Runtime changes, and the same Playbook now says unlimited. Nothing was redeployed.