The React SDK provides hooks and components for checking entitlements on the client side, with automatic reactivity and SSR support.
Installation
npm install @revstackhq/react
Quick Start
1. Wrap your app with RevstackProvider
import { RevstackProvider } from "@revstackhq/react" ;
function App () {
return (
< RevstackProvider
config = { {
publicKey: process . env . NEXT_PUBLIC_REVSTACK_PUBLIC_KEY ! ,
getToken : async () => {
// Return the current user's JWT, or null if unauthenticated
const session = await getSession ();
return session ?. token ?? null ;
},
} }
>
< YourApp />
</ RevstackProvider >
);
}
Use your public key for client-side SDKs. Never expose your secret key in the browser.
2. Check entitlements with hooks
import { useEntitlement } from "@revstackhq/react" ;
function PremiumFeature () {
const feature = useEntitlement ( "premium-feature" );
if ( ! feature . hasAccess ) {
return < PaywallBanner /> ;
}
return < PremiumContent /> ;
}
Configuration
RevstackProvider Props
interface RevstackConfig {
/** Project public key from Revstack Dashboard */
publicKey : string ;
/** Function that returns the current user's JWT token */
getToken : () => Promise < string | null >;
/** API base URL (optional) */
apiUrl ?: string ;
/** Custom guest ID resolver — overrides fingerprinting (optional) */
getGuestId ?: () => Promise < string >;
/** Disable browser fingerprinting (optional) */
disableFingerprint ?: boolean ;
}
Authentication Integration
The getToken function should return your user’s JWT from your auth provider:
import { useAuth } from "@clerk/nextjs" ;
import { RevstackProvider } from "@revstackhq/react" ;
function App () {
const { getToken } = useAuth ();
return (
< RevstackProvider
config = { {
publicKey: process . env . NEXT_PUBLIC_REVSTACK_PUBLIC_KEY ! ,
getToken : async () => {
const token = await getToken ();
return token ?? null ;
},
} }
>
< YourApp />
</ RevstackProvider >
);
}
Hooks
useEntitlement
Subscribe to entitlement changes for a specific feature.
import { useEntitlement } from "@revstackhq/react" ;
function FeatureGate () {
const feature = useEntitlement ( "advanced-analytics" );
return (
< div >
< p > Access: { feature . hasAccess ? "Granted" : "Denied" } </ p >
{ feature . value && < p > Limit: { feature . value } </ p > }
</ div >
);
}
Returns:
interface Entitlement {
/** Feature key */
key : string ;
/** Whether the user has access */
hasAccess : boolean ;
/** Optional value (limits, tier names, etc.) */
value ?: string | number | boolean ;
}
useEntitlement is reactive — it automatically re-renders when entitlements change.
useRevstack
Access the raw RevstackClient instance.
import { useRevstack } from "@revstackhq/react" ;
function BillingPortalButton () {
const revstack = useRevstack ();
const handleOpenPortal = async () => {
await revstack . openBillingPortal ({
returnUrl: window . location . href ,
});
};
return < button onClick = { handleOpenPortal } > Manage Billing </ button > ;
}
Client Methods:
interface RevstackClient {
/** Check if client is initialized */
isInitialized : boolean ;
/** Check if init() has completed (success or failure) */
isReady : boolean ;
/** Initialize the client (called automatically by provider) */
init () : Promise < void >;
/** Get entitlement from cache */
getEntitlement ( key : string ) : Entitlement ;
/** Check if user has access to a feature */
hasAccess ( key : string ) : boolean ;
/** Start a checkout session */
startCheckout ( params : CheckoutParams ) : Promise < void >;
/** Open the billing portal */
openBillingPortal ( params : BillingPortalParams ) : Promise < void >;
}
Common Patterns
Feature Gating
Show/hide UI based on entitlements:
import { useEntitlement } from "@revstackhq/react" ;
function Dashboard () {
const analytics = useEntitlement ( "analytics" );
const exports = useEntitlement ( "data-exports" );
return (
< div >
< h1 > Dashboard </ h1 >
{ analytics . hasAccess && (
< section >
< h2 > Analytics </ h2 >
< AnalyticsCharts />
</ section >
) }
{ exports . hasAccess ? (
< ExportButton />
) : (
< UpgradePrompt feature = "Data Exports" />
) }
</ div >
);
}
Usage Limits
Display remaining quota from entitlement values:
import { useEntitlement } from "@revstackhq/react" ;
function ApiUsageWidget () {
const apiCalls = useEntitlement ( "api-calls" );
if ( ! apiCalls . hasAccess ) {
return < p > API access not available on your plan </ p > ;
}
const limit = apiCalls . value as number ;
return (
< div >
< h3 > API Usage </ h3 >
< p > Limit: { limit } calls/month </ p >
< ProgressBar current = { 0 } max = { limit } />
</ div >
);
}
Checkout Flow
Start a checkout session and redirect to payment:
import { useRevstack } from "@revstackhq/react" ;
function PricingCard ({ planId } : { planId : string }) {
const revstack = useRevstack ();
const [ loading , setLoading ] = useState ( false );
const handleSubscribe = async () => {
setLoading ( true );
try {
await revstack . startCheckout ({
planId ,
successUrl: ` ${ window . location . origin } /dashboard?success=true` ,
cancelUrl: ` ${ window . location . origin } /pricing` ,
});
// User is redirected to checkout
} catch ( error ) {
console . error ( "Checkout failed:" , error );
setLoading ( false );
}
};
return (
< button onClick = { handleSubscribe } disabled = { loading } >
{ loading ? "Loading..." : "Subscribe" }
</ button >
);
}
Billing Portal
Let users manage their subscription:
import { useRevstack } from "@revstackhq/react" ;
function SettingsPage () {
const revstack = useRevstack ();
const handleManageBilling = async () => {
await revstack . openBillingPortal ({
returnUrl: window . location . href ,
});
// User is redirected to billing portal
};
return (
< div >
< h2 > Billing Settings </ h2 >
< button onClick = { handleManageBilling } >
Manage Subscription
</ button >
</ div >
);
}
Loading States
Handle initialization loading:
import { useRevstack } from "@revstackhq/react" ;
function App () {
const revstack = useRevstack ();
if ( ! revstack . isReady ) {
return < LoadingSpinner /> ;
}
return < Dashboard /> ;
}
SSR Support
The React SDK is SSR-safe and works with Next.js, Remix, and other frameworks.
useEntitlement returns { key, hasAccess: false } on the server
The provider initializes on mount (client-side only)
No hydration mismatches
For server-side entitlement checks, use the Next.js SDK server helpers.
TypeScript Support
Full type definitions included:
import type {
RevstackConfig ,
Entitlement ,
CheckoutParams ,
BillingPortalParams ,
} from "@revstackhq/react" ;
Advanced: Custom Guest ID
Override the default browser fingerprinting:
< RevstackProvider
config = { {
publicKey: "pk_..." ,
getToken : async () => token ,
getGuestId : async () => {
// Use your own anonymous user ID
return localStorage . getItem ( "anonymous_user_id" ) ! ;
},
} }
>
< App />
</ RevstackProvider >
Advanced: Disable Fingerprinting
For privacy-sensitive applications:
< RevstackProvider
config = { {
publicKey: "pk_..." ,
getToken : async () => token ,
disableFingerprint: true ,
} }
>
< App />
</ RevstackProvider >
Disabling fingerprinting means unauthenticated users won’t have entitlements tracked.
Next Steps
Next.js SDK Server and client components for Next.js
Browser SDK Vanilla JavaScript SDK for any framework
Entitlements Learn about feature gating and access control
Subscriptions Build subscription checkout flows