Tutorial: Show a Trial-Ending Countdown
In this tutorial, you’ll show a trial-ending banner that counts down the final days of a user’s trial and prompts them to upgrade before it expires. Takes about 10 minutes.
What You’ll Build
Section titled “What You’ll Build”A trial countdown that:
- Fires only in the final window of a trial (the last 3 days)
- Renders the days remaining via the
{{days_remaining}}token - Links to checkout with an upgrade CTA
Prerequisites
Section titled “Prerequisites”- A React 18+ application with
@revturbine/sdkinstalled - A
RevTurbineProviderset up (see Quickstart)
-
Add a trial-ending placement to your config
The
trial_endingtrigger fires when a trial enters its closing window. This is a complete, validPlaybook.revturbine.playbook.json {"artifact_type": "playbook","format_version": "1.0.0","plans": [{ "unique_handle": "pro", "name": "Pro", "tier_position": 1, "sort_order": 1 }],"entitlements": [],"entitlement_rules": [],"segments": [],"content_ui_paths": [],"surface_templates": [{ "id": "banner_placement", "surface_type": "banner", "fields": [] }],"placements": [{"id": "pl_trial_ending","name": "Trial ending countdown","category": "trials","trigger": { "type": "trial_ending", "days_before_end": 3 },"payloads": [{"id": "pl_trial_ending_p0","target": { "plan_ids": [], "segment_chips": [] },"surfaces": [{"template_id": "banner_placement","fields": {"header": "Your trial ends in {{days_remaining}} days","body": "Upgrade now to keep your projects and Pro features.","dismissible": "Yes"},"ctas": [{ "label": "Upgrade to Pro", "path": "open_checkout", "config": { "purchase": "pro" } }]}],"caps": { "max_per_period": { "count": 1, "period": "day" } },"status": "active"}],"order": 0}]} -
Provide trial status to the SDK
In local mode the SDK reads trial state from
localRuntime.initialData(in hosted mode it arrives with the user context). Supply the trial so the trigger and{{days_remaining}}token can compute the window.src/App.tsx <RevTurbineProvideroptions={{localRuntime: {playbook,// In local mode, hydrate trial status synchronously:initialData: {trialStatus: { in_trial: true, days_remaining: 2 },},},user: { id: 'user_123', plan_handle: 'trial' },}}><AppHeader /></RevTurbineProvider> -
Render the banner slot
src/components/AppHeader.tsx import { Slot } from '@revturbine/sdk';export function AppHeader() {return (<header>{/* Hidden until the trial enters its final 3 days */}<Slot id="app_header_banner" surfaceTemplateIds={['banner_placement']} /><nav>{/* ... */}</nav></header>);} -
(Optional) Read trial status directly
To drive your own UI — a sidebar countdown, a settings notice — read trial status imperatively:
React import { useEffect, useState } from 'react';import { useRevTurbine } from '@revturbine/sdk';function TrialNotice() {const { sdk } = useRevTurbine();const [trial, setTrial] = useState(null);useEffect(() => {if (sdk) void Promise.resolve(sdk.getTrialStatus()).then(setTrial);}, [sdk]);if (!trial?.in_trial) return null;return <p>{trial.days_remaining} days left in your trial</p>;}
How It Works
Section titled “How It Works”- The
trial_endingtrigger keeps the placement hidden until the trial is withindays_before_endof expiring. {{days_remaining}}is filled from the trial status the SDK holds.- As the trial advances day by day, the banner copy updates automatically.
- The CTA opens checkout through the resolvers from Quickstart.
Try It Live
Section titled “Try It Live”Next Steps
Section titled “Next Steps”- Entitlements Guide — trials, usage limits, and credits
- Placements Guide — triggers and targeting
- Tutorial: Show a Banner Placement — targeted banners without a trigger