Skip to content

Quickstart

This guide takes you from install to a working feature gate: a free user hits an upgrade prompt, a paid user gets through — all client-side, with no account, no API keys, and no backend.

  • A React 18+ application
  • Node.js 22.13+
  1. Install the SDK

    @revturbine/sdk is published to the public npm registry — no auth, token, or registry configuration needed.

    Terminal window
    npm install @revturbine/sdk
  2. Add a Playbook

    You don’t need a RevTurbine account for this. Scaffold a starter Playbook straight into your app:

    Terminal window
    npx revturbine create

    That installs the SDK and CLI and drops a local-mode playbook.json in place. If you already have an account, revturbine download --live --save ./playbook.json pulls your real config instead.

    The Playbook contains your plans, entitlements, placements, targeting rules, surface templates, and UI paths — everything the SDK needs to run locally.

  3. Wrap your app in RevTurbineProvider with local runtime

    src/App.tsx
    import { RevTurbineProvider, Slot, RuntimeMode } from '@revturbine/sdk';
    import playbook from './playbook.json';
    import { useMemo } from 'react';
    function App() {
    const options = useMemo(() => ({
    runtimeMode: RuntimeMode.LocalOnly,
    localRuntime: { playbook },
    user: {
    id: 'user_123',
    plan_handle: 'starter',
    },
    uiPathResolvers: {
    navigate_to_plans: (ctx) => {
    window.location.href = '/pricing';
    },
    open_checkout_modal: (ctx) => {
    // Open your checkout flow, e.g. Stripe Checkout
    console.log('Checkout for plan:', ctx.plan_handle);
    },
    book_demo: (ctx) => {
    window.open(ctx.url ?? '/sales/demo', '_blank');
    },
    custom_url: (ctx) => {
    if (ctx.url) window.location.href = ctx.url;
    },
    },
    }), []);
    return (
    <RevTurbineProvider options={options}>
    <YourApp />
    </RevTurbineProvider>
    );
    }
  4. Add a placement slot

    Drop a <Slot> where you want a placement to appear:

    src/components/Dashboard.tsx
    import { Slot } from '@revturbine/sdk';
    function Dashboard() {
    return (
    <div>
    <h1>Dashboard</h1>
    {/* RevTurbine renders an upgrade banner here — or nothing */}
    <Slot
    id="dashboard_top_banner"
    surfaceTemplateIds={["banner_placement"]}
    />
    {/* Rest of your dashboard */}
    </div>
    );
    }
  5. Gate a paid feature

    Wrap the gated UI in <Gate>. It renders its children when the user is entitled, and shows the configured upgrade placement when they aren’t — no manual check.

    src/components/BatchExport.tsx
    import { Gate } from '@revturbine/sdk';
    function BatchExport() {
    return (
    <Gate id="batch_export_gate" can="batch_export">
    <BatchExportButton />
    </Gate>
    );
    }

    can="batch_export" is shorthand for check={{ entitlement: 'batch_export' }}. For custom deny UI, use the useCan hook instead — see the Entitlements guide.

  6. Verify it works

    Start your dev server. With the starter Playbook’s free plan, <Gate> renders the upgrade placement instead of the button. Switch the user to the paid plan — change plan in the user option — and the button appears. Placement slots behave the same way: if no placement matches the current user context, the component renders nothing, which is the additive principle at work.

A UI path is the bridge between a RevTurbine placement and your application’s navigation. When a user clicks a CTA button inside a placement (e.g., “Upgrade Now” or “View Plans”), the SDK doesn’t navigate directly — instead, it invokes a UI path resolver function that you provide, giving your app full control over what happens next.

Each UI path has an action_type that identifies the intent:

Action TypeTypical Use
navigate_to_plansGo to pricing / plan comparison page
open_checkout_modalOpen Stripe Checkout or your billing flow
book_demoOpen a sales demo booking form
custom_urlNavigate to an arbitrary URL
open_upgrade_modalShow an upgrade modal
open_feature_tourLaunch a product tour
dismissClose / dismiss the placement

The resolver receives a context object with any metadata attached in the config (e.g., plan_handle, url, promotion_id). This keeps your conversion flows decoupled from placement content — marketers can change CTA copy and targeting without code changes.

When a placement is configured and the user matches targeting rules, the slot renders the appropriate component — a banner, modal, button, toast, or other surface. When no placement is eligible, it renders nothing.