The Browser SDK is a framework-agnostic JavaScript library for client-side entitlement checks, checkout flows, and billing portal access.
Installation
npm install @revstackhq/browser
Include the SDK via CDN: < script src = "https://unpkg.com/@revstackhq/browser@latest" ></ script >
< script >
const client = new Revstack . RevstackClient ({
publicKey: "pk_..." ,
getToken : async () => localStorage . getItem ( "auth_token" ),
});
</ script >
Quick Start
1. Initialize the client
import { RevstackClient } from "@revstackhq/browser" ;
const revstack = new RevstackClient ({
publicKey: "pk_..." , // your public key from Revstack Dashboard
getToken : async () => {
// Return the current user's JWT, or null if unauthenticated
return localStorage . getItem ( "auth_token" ) ?? null ;
},
});
// Initialize and fetch entitlements
await revstack . init ();
Use your public key for client-side SDKs. Never expose your secret key in the browser.
2. Check entitlements
const feature = revstack . getEntitlement ( "premium-feature" );
if ( feature . hasAccess ) {
console . log ( "User has access to premium features!" );
} else {
console . log ( "Access denied. Show paywall." );
}
Configuration
RevstackClient Options
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 ;
}
Example Configuration
const revstack = new RevstackClient ({
publicKey: "pk_live_..." ,
apiUrl: "https://api.custom.com" , // optional
getToken : async () => {
const session = await fetchSession ();
return session ?. token ?? null ;
},
disableFingerprint: false , // optional
});
Core Methods
init()
Initialize the client and fetch entitlements:
try {
await revstack . init ();
console . log ( "Revstack initialized" );
} catch ( error ) {
console . error ( "Failed to initialize:" , error );
}
Call init() once on app startup. The provider handles this automatically in React/Next.js.
getEntitlement(key)
Get an entitlement from the local cache (synchronous):
const analytics = revstack . getEntitlement ( "analytics" );
console . log ( analytics . key ); // "analytics"
console . log ( analytics . hasAccess ); // true or false
console . log ( analytics . value ); // optional limit/value
Returns:
interface Entitlement {
key : string ;
hasAccess : boolean ;
value ?: string | number | boolean ;
}
If the entitlement key doesn’t exist, returns { key, hasAccess: false }.
hasAccess(key)
Check if the user has access to a feature (boolean shorthand):
if ( revstack . hasAccess ( "premium-feature" )) {
showPremiumContent ();
} else {
showPaywall ();
}
startCheckout(params)
Start a checkout session and redirect to the payment page:
await revstack . startCheckout ({
planId: "plan_pro" ,
successUrl: "https://yourapp.com/dashboard?success=true" ,
cancelUrl: "https://yourapp.com/pricing" ,
});
// User is redirected to https://checkout.revstack.dev
Parameters:
interface CheckoutParams {
planId : string ; // Plan to subscribe to
successUrl : string ; // Redirect after successful payment
cancelUrl : string ; // Redirect on cancellation
}
openBillingPortal(params)
Open the billing portal for subscription management:
await revstack . openBillingPortal ({
returnUrl: window . location . href ,
});
// User is redirected to the billing portal
Parameters:
interface BillingPortalParams {
returnUrl : string ; // URL to return to after leaving the portal
}
Client Properties
isInitialized
Check if the client has successfully initialized:
if ( revstack . isInitialized ) {
console . log ( "Ready to check entitlements" );
}
isReady
Check if initialization has completed (success or failure):
if ( ! revstack . isReady ) {
showLoadingSpinner ();
}
Reactivity (Advanced)
The browser SDK implements the external store protocol for use with React hooks.
subscribe(listener)
Subscribe to entitlement changes:
const unsubscribe = revstack . subscribe (() => {
console . log ( "Entitlements updated!" );
render ();
});
// Later: cleanup
unsubscribe ();
getSnapshot()
Get the current version number (for change detection):
const version = revstack . getSnapshot ();
console . log ( "Current version:" , version );
React hooks like useEntitlement use subscribe and getSnapshot internally.
Usage Patterns
Feature Gating
function renderDashboard () {
const analytics = revstack . getEntitlement ( "analytics" );
const exports = revstack . getEntitlement ( "data-exports" );
let html = "<h1>Dashboard</h1>" ;
if ( analytics . hasAccess ) {
html += "<section><h2>Analytics</h2><div id='charts'></div></section>" ;
}
if ( exports . hasAccess ) {
html += "<button id='export-btn'>Export Data</button>" ;
} else {
html += "<a href='/pricing'>Upgrade to export data</a>" ;
}
document . getElementById ( "app" ). innerHTML = html ;
}
Pricing Page
function renderPricingCard ( plan ) {
return `
<div class="pricing-card">
<h3> ${ plan . name } </h3>
<p> ${ plan . price } </p>
<button onclick="subscribe(' ${ plan . id } ')">Subscribe</button>
</div>
` ;
}
async function subscribe ( planId ) {
await revstack . startCheckout ({
planId ,
successUrl: window . location . origin + "/dashboard" ,
cancelUrl: window . location . href ,
});
}
Settings Page
function renderSettings () {
return `
<div>
<h2>Billing Settings</h2>
<button onclick="openBilling()">Manage Subscription</button>
</div>
` ;
}
async function openBilling () {
await revstack . openBillingPortal ({
returnUrl: window . location . href ,
});
}
Framework Integration
Vanilla JavaScript
import { RevstackClient } from "@revstackhq/browser" ;
const revstack = new RevstackClient ({
publicKey: "pk_..." ,
getToken : async () => localStorage . getItem ( "token" ),
});
async function init () {
await revstack . init ();
render ();
}
function render () {
const feature = revstack . getEntitlement ( "premium" );
document . getElementById ( "content" ). innerHTML = feature . hasAccess
? "<div>Premium Content</div>"
: "<div>Upgrade to access</div>" ;
}
init ();
Vue.js
< script setup >
import { ref , onMounted } from "vue" ;
import { RevstackClient } from "@revstackhq/browser" ;
const revstack = new RevstackClient ({
publicKey: "pk_..." ,
getToken : async () => localStorage . getItem ( "token" ),
});
const feature = ref ({ key: "premium" , hasAccess: false });
onMounted ( async () => {
await revstack . init ();
feature . value = revstack . getEntitlement ( "premium" );
// Subscribe to changes
revstack . subscribe (() => {
feature . value = revstack . getEntitlement ( "premium" );
});
});
</ script >
< template >
< div v-if = " feature . hasAccess " >
< h1 > Premium Content </ h1 >
</ div >
< div v-else >
< a href = "/pricing" > Upgrade to Premium </ a >
</ div >
</ template >
Svelte
< script >
import { onMount } from "svelte" ;
import { RevstackClient } from "@revstackhq/browser" ;
const revstack = new RevstackClient ({
publicKey: "pk_..." ,
getToken : async () => localStorage . getItem ( "token" ),
});
let feature = { key: "premium" , hasAccess: false };
onMount ( async () => {
await revstack . init ();
feature = revstack . getEntitlement ( "premium" );
revstack . subscribe (() => {
feature = revstack . getEntitlement ( "premium" );
});
});
</ script >
{# if feature . hasAccess }
< h1 > Premium Content </ h1 >
{: else }
< a href = "/pricing" > Upgrade to Premium </ a >
{/ if }
Authentication Integration
The getToken function should return the current user’s JWT:
import { createAuth0Client } from "@auth0/auth0-spa-js" ;
const auth0 = await createAuth0Client ({
domain: "your-domain.auth0.com" ,
client_id: "your-client-id" ,
});
const revstack = new RevstackClient ({
publicKey: "pk_..." ,
getToken : async () => {
try {
return await auth0 . getTokenSilently ();
} catch {
return null ;
}
},
});
Anonymous Users
The SDK automatically fingerprints anonymous users for entitlement tracking.
Custom Guest ID
Provide your own anonymous user ID:
const revstack = new RevstackClient ({
publicKey: "pk_..." ,
getToken : async () => null ,
getGuestId : async () => {
return localStorage . getItem ( "anonymous_id" );
},
});
Disable Fingerprinting
For privacy-sensitive applications:
const revstack = new RevstackClient ({
publicKey: "pk_..." ,
getToken : async () => token ,
disableFingerprint: true ,
});
Disabling fingerprinting means unauthenticated users won’t have entitlements.
TypeScript Support
Full type definitions included:
import {
RevstackClient ,
type RevstackConfig ,
type Entitlement ,
type CheckoutParams ,
} from "@revstackhq/browser" ;
const revstack : RevstackClient = new RevstackClient ({
publicKey: "pk_..." ,
getToken : async () : Promise < string | null > => {
return localStorage . getItem ( "token" );
},
});
const feature : Entitlement = revstack . getEntitlement ( "premium" );
Next Steps
React SDK Use React hooks for better integration
Next.js SDK Server and client components for Next.js
Entitlements Learn about feature gating and access control
Subscriptions Build subscription checkout flows