Skip to content

Tutorial: Add an Upgrade Button

In this tutorial, you’ll install the SDK, configure it in local mode, and render an upgrade button that only appears for users on the Starter plan. Takes about 10 minutes.

An upgrade button in your navigation bar that:

  • Shows “Upgrade to Pro” for Starter plan users
  • Hides automatically for Professional/Enterprise users
  • Tracks impressions and CTA clicks
  • Navigates to your pricing page on click
  • A React 18+ application (Next.js, Vite, or CRA)
  • Node.js 20+
  1. Install the SDK

    Terminal window
    pnpm add @revturbine/sdk
  2. Create an ExportedConfig fixture

    For local development, you need a config file with plans, entitlements, and placements. Create src/fixtures/exported_config.json:

    exported_config.json
    {
    "version": "v1",
    "plans": [
    { "id": "plan_starter", "unique_handle": "starter", "name": "Starter", "tier_position": 0, "sort_order": 0 },
    { "id": "plan_pro", "unique_handle": "pro", "name": "Pro", "tier_position": 1, "sort_order": 1 }
    ],
    "entitlements": [],
    "entitlement_rules": [],
    "segments": [],
    "content_ui_paths": [],
    "surface_templates": [
    { "id": "button", "surface_type": "button", "fields": [] }
    ],
    "placements": [
    {
    "id": "pl_nav_upgrade",
    "name": "Upgrade button",
    "category": "fixed",
    "trigger": { "type": "surface_render", "slot_id": "nav_upgrade" },
    "payloads": [
    {
    "id": "pl_nav_upgrade_p0",
    "target": { "plan_ids": ["plan_starter"], "segment_chips": [] },
    "surfaces": [
    {
    "template_id": "button",
    "fields": {},
    "ctas": [
    { "label": "Upgrade to Pro", "path": "open_checkout", "config": { "purchase": "pro" } }
    ]
    }
    ],
    "caps": {},
    "status": "active"
    }
    ],
    "order": 0
    }
    ]
    }
  3. Wrap your app with the provider

    src/App.tsx
    import { RevTurbineProvider } from '@revturbine/sdk';
    import exportedConfig from './fixtures/exported_config.json';
    export default function App() {
    return (
    <RevTurbineProvider
    options={{
    tenantId: 'demo',
    apiKey: 'local',
    endpoint: 'http://localhost',
    mode: 'react',
    runtimeMode: 'local_only',
    localRuntime: { exportedConfig },
    // The button's CTA fires the action you configured; wire CTA
    // handling to your navigation — see the Quickstart.
    }}
    >
    <NavBar />
    <MainContent />
    </RevTurbineProvider>
    );
    }
  4. Add the upgrade button slot

    src/components/NavBar.tsx
    import { FixedSurfaceSlot } from '@revturbine/sdk';
    export function NavBar() {
    return (
    <nav style={{ display: 'flex', alignItems: 'center', gap: 16, padding: '8px 16px' }}>
    <span style={{ fontWeight: 600 }}>MyApp</span>
    <div style={{ flex: 1 }} />
    {/* This slot renders only when targeting matches */}
    <FixedSurfaceSlot
    id="nav_upgrade"
    surfaceTemplateIds={['button']}
    />
    </nav>
    );
    }
  5. Verify it works

    Start your dev server and you should see:

    • Starter user → “Upgrade to Pro” button appears
    • Professional user → nothing renders (slot is invisible)

    To test different users, change the user context in the provider:

    <RevTurbineProvider
    options={{
    // ...
    user: { id: 'user_1', context: { plan_handle: 'starter' } },
    // Try: context: { plan_handle: 'pro' } — button disappears
    }}
    >
  1. The RevTurbineProvider initialized the SDK in local_only mode with your ExportedConfig
  2. The FixedSurfaceSlot asked the decision engine for a placement at slot nav_upgrade
  3. The engine evaluated the payload target (plan_ids: ['plan_starter']) against the user context
  4. For Starter users, it resolved the button template with the “Upgrade to Pro” CTA
  5. For Pro users, no payload matched — the slot rendered nothing

When you’re ready for real decisions from the RevTurbine API:

<RevTurbineProvider
options={{
tenantId: 'demo',
apiKey: 'local',
endpoint: 'http://localhost',
tenantId: process.env.NEXT_PUBLIC_RT_TENANT_ID!,
apiKey: process.env.NEXT_PUBLIC_RT_API_KEY!,
endpoint: process.env.NEXT_PUBLIC_RT_ENDPOINT!,
mode: 'react',
runtimeMode: 'local_only',
localRuntime: { exportedConfig },
runtimeMode: 'revturbine_server',
}}
>

Interactive Playground → Upgrade Button