usecelo-react
v0.6.0
Published
Complete React SDK for pricing, feature gating, and usage management with UseCelo
Maintainers
Readme
UseCelo React SDK 🚀
A powerful React SDK for implementing feature gating, pricing tiers, and usage tracking with minimal code changes.
Transform your SaaS from manual API calls to automatic feature management in minutes, not weeks.
✨ What Makes This Special
Root Wrapper Approach - Wrap Once, Use Everywhere
No more importing components or making API calls throughout your codebase. Wrap your app once, then use simple data attributes anywhere.
Before: Manual API Management 😰
// Your old code scattered throughout components
const checkFeature = async (feature) => {
const response = await fetch(`/api/features?feature=${feature}`);
const data = await response.json();
return data.hasAccess;
};
if (await checkFeature('premium-export')) {
// Show feature
} else {
// Hide or show upgrade
}After: Simple Data Attributes ✨
<!-- No imports needed! Just use data attributes -->
<div data-feature="premium-export">
<button>Export to PDF</button>
</div>
<button data-feature="api-calls" data-track-usage="true">
Make API Call (tracks usage automatically)
</button>Quick Start
Installation
npm install usecelo-react1. Wrap Your App Once
UseCelo provides flexible setup options for different authentication providers and frameworks:
Option A: Basic Setup (Static User ID)
// app/layout.tsx (Next.js App Router)
import { UseCeloProvider } from 'usecelo-react';
export default function RootLayout({ children }) {
return (
<html>
<body>
<UseCeloProvider
appId={process.env.NEXT_PUBLIC_USECELO_APP_ID!}
publicKey={process.env.NEXT_PUBLIC_USECELO_PUBLIC_KEY!}
userId="user-123" // Static user ID
>
{children}
</UseCeloProvider>
</body>
</html>
);
}Option B: With Clerk Authentication
// app/layout.tsx
import { ClerkProvider } from '@clerk/nextjs';
import { UseCeloProvider } from 'usecelo-react';
import { ClerkAdapter } from 'usecelo-react/adapters/clerk';
export default function RootLayout({ children }) {
return (
<ClerkProvider>
<html>
<body>
<UseCeloProvider
appId={process.env.NEXT_PUBLIC_USECELO_APP_ID!}
publicKey={process.env.NEXT_PUBLIC_USECELO_PUBLIC_KEY!}
authAdapter={new ClerkAdapter()} // Auto user management
>
{children}
</UseCeloProvider>
</body>
</html>
</ClerkProvider>
);
}Option C: With Supabase Authentication
// app/layout.tsx
import { UseCeloProvider } from 'usecelo-react';
import { SupabaseAdapter } from 'usecelo-react/adapters/supabase';
import { createClientComponentClient } from '@supabase/auth-helpers-nextjs';
export default function RootLayout({ children }) {
return (
<html>
<body>
<UseCeloProvider
appId={process.env.NEXT_PUBLIC_USECELO_APP_ID!}
publicKey={process.env.NEXT_PUBLIC_USECELO_PUBLIC_KEY!}
authAdapter={new SupabaseAdapter(createClientComponentClient())}
>
{children}
</UseCeloProvider>
</body>
</html>
);
}Option D: Auto-Detect Authentication
// app/layout.tsx - Works with any auth provider!
import { UseCeloProvider } from 'usecelo-react';
export default function RootLayout({ children }) {
return (
<html>
<body>
<UseCeloProvider
appId={process.env.NEXT_PUBLIC_USECELO_APP_ID!}
publicKey={process.env.NEXT_PUBLIC_USECELO_PUBLIC_KEY!}
authAdapter="auto" // Automatically detects Clerk, Supabase, Auth0
fallbackBehavior="blur"
onUpgradeClick={() => window.location.href = '/pricing'}
>
{children}
</UseCeloProvider>
</body>
</html>
);
}Option E: Clean Provider Pattern
// app/providers.tsx
"use client";
import { UseCeloProvider, PaymentProvider } from 'usecelo-react';
import { ClerkAdapter } from 'usecelo-react/adapters/clerk';
export function Providers({ children }) {
return (
<UseCeloProvider
appId={process.env.NEXT_PUBLIC_USECELO_APP_ID!}
publicKey={process.env.NEXT_PUBLIC_USECELO_PUBLIC_KEY!}
authAdapter={new ClerkAdapter()}
>
<PaymentProvider
gateway="STRIPE"
publishableKey={process.env.NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY!}
>
{children}
</PaymentProvider>
</UseCeloProvider>
);
}
// app/layout.tsx
import { ClerkProvider } from '@clerk/nextjs';
import { Providers } from './providers';
export default function RootLayout({ children }) {
return (
<ClerkProvider>
<html>
<body>
<Providers>{children}</Providers>
</body>
</html>
</ClerkProvider>
);
}Pages Router Setup
// pages/_app.tsx
import { ClerkProvider } from '@clerk/nextjs';
import { UseCeloProvider } from 'usecelo-react';
import { ClerkAdapter } from 'usecelo-react/adapters/clerk';
export default function MyApp({ Component, pageProps }) {
return (
<ClerkProvider {...pageProps}>
<UseCeloProvider
appId={process.env.NEXT_PUBLIC_USECELO_APP_ID!}
publicKey={process.env.NEXT_PUBLIC_USECELO_PUBLIC_KEY!}
authAdapter={new ClerkAdapter()}
>
<Component {...pageProps} />
</UseCeloProvider>
</ClerkProvider>
);
}2. Use Data Attributes Anywhere
// No imports needed in your components!
export default function Dashboard() {
return (
<div>
<h1>Dashboard</h1>
{/* Hidden if user doesn't have access */}
<div data-feature="ai-analysis">
<button>Analyze with AI</button>
</div>
{/* Blurred with upgrade prompt */}
<div data-feature="premium-exports" data-fallback="blur">
<button>Export to PDF</button>
</div>
{/* Tracks usage automatically */}
<button
data-feature="api-calls"
data-track-usage="true"
data-track-quantity="1"
>
Make API Call
</button>
</div>
);
}🎯 Core Features
1. Data Attributes - Zero Import Feature Gating
Protect features with simple HTML attributes:
<!-- Basic feature gating -->
<div data-feature="feature-name">Protected content</div>
<!-- Custom fallback strategies -->
<div data-feature="premium-feature" data-fallback="blur">
Premium content gets blurred with upgrade prompt
</div>
<!-- Usage tracking -->
<button data-feature="api-calls" data-track-usage="true" data-track-quantity="5">
Use 5 API Credits
</button>2. Multiple Fallback Strategies
- hide (default): Completely hidden
- disable: Grayed out and non-interactive
- blur: Blurred with upgrade overlay
- upgrade: Replaced with upgrade prompt
- custom: Your own fallback content
3. Automatic Usage Tracking
Track feature usage without writing code:
<!-- Tracks 1 usage when clicked -->
<button data-feature="exports" data-track-usage="true">
Export Data
</button>
<!-- Tracks custom quantity -->
<button data-feature="credits" data-track-usage="true" data-track-quantity="10">
Use 10 Credits
</button>📝 Data Attributes Reference
Available Attributes
| Attribute | Description | Example Values |
|-----------|-------------|----------------|
| data-feature | Feature name to check access | "ai-analysis", "premium-export" |
| data-fallback | Fallback strategy when blocked | "hide", "disable", "blur", "upgrade", "custom" |
| data-track-usage | Enable usage tracking | "true", "false" |
| data-track-quantity | Amount to track per usage | "1", "5", "10" |
| data-fallback-content | Custom fallback content | Used with data-fallback="custom" |
Fallback Strategies in Detail
1. Hide (Default)
<div data-feature="premium-feature">
<!-- Completely removed from DOM if no access -->
</div>2. Disable
<div data-feature="premium-feature" data-fallback="disable">
<!-- Becomes semi-transparent and non-interactive -->
</div>3. Blur
<div data-feature="premium-feature" data-fallback="blur">
<!-- Content is blurred with upgrade overlay -->
</div>4. Upgrade
<div data-feature="premium-feature" data-fallback="upgrade">
<!-- Replaced with upgrade button/prompt -->
</div>5. Custom
<div data-feature="premium-feature" data-fallback="custom">
<div>Premium content here</div>
<!-- This shows when feature is blocked -->
<div data-fallback-content style="display: none;">
<h3>Upgrade Required</h3>
<p>This feature requires a Pro plan</p>
<button onclick="window.location='/pricing'">Upgrade Now</button>
</div>
</div>🎆 Real-World Examples
E-commerce Platform
<!-- Free tier: Basic product browsing -->
<div class="product-grid">
<div class="product">Basic Product Listing</div>
</div>
<!-- Premium: Product comparison -->
<div data-feature="product-comparison" data-fallback="upgrade">
<button>Compare Products</button>
</div>
<!-- Pro: Advanced filtering -->
<div data-feature="advanced-filters" data-fallback="blur">
<select name="filters">
<option>Price Range</option>
<option>Brand Filter</option>
<option>Rating Filter</option>
</select>
</div>SaaS Dashboard
<!-- Always available -->
<div class="basic-stats">
<h3>Basic Analytics</h3>
<p>Page views: 1,247</p>
</div>
<!-- Premium analytics with blur fallback -->
<div data-feature="advanced-analytics" data-fallback="blur">
<canvas id="advanced-chart"></canvas>
<div class="detailed-metrics">
<p>Conversion Rate: 3.2%</p>
<p>Revenue Attribution: $12,450</p>
</div>
</div>
<!-- API usage with automatic tracking -->
<button
data-feature="api-calls"
data-track-usage="true"
data-track-quantity="1"
onclick="makeApiCall()"
>
Make API Call (1 credit)
</button>Content Platform
<!-- Free articles -->
<article>
<h1>How to Get Started</h1>
<p>Free content available to everyone...</p>
</article>
<!-- Premium content with custom fallback -->
<div data-feature="premium-content" data-fallback="custom">
<article class="premium-article">
<h2>Advanced Strategies</h2>
<p>Exclusive insights for premium members...</p>
</article>
<div data-fallback-content style="display: none;">
<div class="paywall">
<h3>🔒 Premium Content</h3>
<p>Unlock advanced strategies with a premium subscription</p>
<button class="upgrade-btn">Start Free Trial</button>
</div>
</div>
</div>⚙️ Configuration
UseCeloProvider Props
| Prop | Type | Required | Description |
|------|------|----------|-------------|
| appId | string | ✅ | Your UseCelo app ID |
| publicKey | string | ✅ | Your public API key |
| userId | string | function | ✅ | Current user ID or function that returns it |
| apiHost | string | ❌ | API host URL (defaults to UseCelo servers) |
| fallbackBehavior | string | ❌ | Default fallback: 'hide', 'disable', 'blur', 'upgrade' |
| cacheTimeout | number | ❌ | Cache timeout in milliseconds (default: 300000) |
| onFeatureBlock | function | ❌ | Called when a feature is blocked |
| onUpgradeClick | function | ❌ | Called when user clicks upgrade |
Advanced Configuration
Dynamic User ID
<UseCeloProvider
userId={() => getCurrentUser()?.id || 'anonymous'}
// ... other props
>Custom Event Handlers
<UseCeloProvider
onFeatureBlock={(featureName) => {
// Custom analytics
analytics.track('Feature Blocked', { feature: featureName });
}}
onUpgradeClick={(featureName) => {
// Custom upgrade flow
openUpgradeModal(featureName);
}}
>💳 Payment Gateway Integration
The SDK includes built-in payment processing with multiple gateway support. Enable seamless checkout flows with automatic user authentication integration.
Quick Payment Setup
import { PaymentProvider, PricingTable } from 'usecelo-react';
function App() {
return (
<UseCeloProvider appId="app_123" publicKey="pk_...">
<PaymentProvider
gateway="STRIPE"
publishableKey="pk_test_..."
debug={true}
>
{/* PricingTable now has automatic checkout */}
<PricingTable
useCheckoutButton={true}
successUrl="/success"
cancelUrl="/pricing"
/>
</PaymentProvider>
</UseCeloProvider>
);
}Available Payment Gateways
Stripe Integration
// Method 1: Using PaymentProvider (Server-side)
import { PaymentProvider } from 'usecelo-react';
<PaymentProvider
gateway="STRIPE"
publishableKey="pk_test_..."
>
{children}
</PaymentProvider>
// Method 2: Client-side Stripe Adapter (Direct)
import { StripeAdapter } from 'usecelo-react/adapters/stripe';
const stripeAdapter = new StripeAdapter({
publishableKey: 'pk_test_...',
debug: true,
options: {
appearance: { theme: 'stripe' }
}
});
await stripeAdapter.initialize();
const session = await stripeAdapter.createCheckoutSession({
planId: 'pro_plan',
successUrl: '/success',
cancelUrl: '/pricing'
});Mock Gateway (Testing)
Perfect for development and testing:
// Using PaymentProvider
<PaymentProvider
gateway="MOCK"
debug={true}
>
{children}
</PaymentProvider>
// Using Mock Adapter directly
import { MockAdapter } from 'usecelo-react/adapters/mock';
const mockAdapter = new MockAdapter({
simulateDelay: 2000, // 2 second delay
simulateFailure: false, // No failures
debug: true
});Client-Side Payment Adapters
For maximum flexibility, use client-side adapters directly:
Installation & Usage
npm install usecelo-react// Import specific payment adapters
import { StripeAdapter } from 'usecelo-react/adapters/stripe';
import { MockAdapter } from 'usecelo-react/adapters/mock';
// Initialize adapter
const adapter = new StripeAdapter({
publishableKey: 'pk_test_...',
debug: true
});
await adapter.initialize();
// Create checkout session
const session = await adapter.createCheckoutSession({
planId: 'pro_plan',
userId: 'user_123',
successUrl: 'https://yourapp.com/success',
cancelUrl: 'https://yourapp.com/pricing',
email: '[email protected]',
metadata: { source: 'pricing_page' }
});
// Redirect to checkout (Stripe handles this automatically)
// session.url contains the checkout URLAvailable Adapters
| Adapter | Import Path | Purpose |
|---------|-------------|---------|
| StripeAdapter | usecelo-react/adapters/stripe | Live Stripe payments |
| RazorpayAdapter | usecelo-react/adapters/razorpay | Live Razorpay payments |
| MockAdapter | usecelo-react/adapters/mock | Testing & development |
Adapter Configuration
StripeAdapter Options:
const adapter = new StripeAdapter({
publishableKey: 'pk_test_...', // Required
debug: true, // Optional
options: { // Optional Stripe-specific options
apiVersion: '2023-10-16',
locale: 'en',
appearance: {
theme: 'stripe', // 'stripe' | 'night'
variables: {
colorPrimary: '#0570de'
}
}
}
});RazorpayAdapter Options:
const adapter = new RazorpayAdapter({
keyId: 'rzp_test_...', // Required: Razorpay Key ID
publishableKey: 'rzp_test_...', // Same as keyId
debug: true, // Optional
options: { // Optional Razorpay-specific options
currency: 'INR',
theme: {
color: '#3399cc',
backdrop_color: '#ffffff'
},
modal: {
backdropclose: false,
escape: false
}
}
});MockAdapter Options:
const adapter = new MockAdapter({
simulateDelay: 3000, // Delay in milliseconds
simulateFailure: false, // Whether to simulate failures
debug: true // Enable debug logging
});Automatic User Integration
When used with AuthProvider, payment gateways automatically inherit user information:
import { AuthProvider, PaymentProvider } from 'usecelo-react';
import { SupabaseAdapter } from 'usecelo-react/adapters/supabase';
function App() {
return (
<UseCeloProvider appId="app_123">
<AuthProvider adapter={new SupabaseAdapter(...)}>
<PaymentProvider gateway="STRIPE" publishableKey="pk_...">
{/* CheckoutButton automatically gets user.id and user.email */}
<CheckoutButton planId="pro_plan">
Upgrade to Pro
</CheckoutButton>
</PaymentProvider>
</AuthProvider>
</UseCeloProvider>
);
}Advanced Payment Workflows
Custom Checkout Button
import { useCheckout } from 'usecelo-react';
function CustomCheckoutButton({ planId }) {
const { createCheckoutSession, loading } = useCheckout();
const handleUpgrade = async () => {
try {
const session = await createCheckoutSession({
planId,
successUrl: window.location.origin + '/success',
cancelUrl: window.location.href,
metadata: {
source: 'custom_button',
feature: 'premium_analytics'
}
});
// For server-side gateways, redirect to session.url
// For client-side gateways like Stripe, redirect happens automatically
} catch (error) {
console.error('Checkout failed:', error);
}
};
return (
<button onClick={handleUpgrade} disabled={loading}>
{loading ? 'Processing...' : 'Upgrade Now'}
</button>
);
}Customer Portal Access
import { usePaymentGateway } from 'usecelo-react';
function BillingSettings() {
const { createPortalSession, loading } = usePaymentGateway();
const openPortal = async () => {
try {
const { url } = await createPortalSession({
customerId: 'cus_123',
returnUrl: window.location.href
});
window.location.href = url;
} catch (error) {
console.error('Portal error:', error);
}
};
return (
<button onClick={openPortal} disabled={loading}>
Manage Billing
</button>
);
}Error Handling
import { PaymentAdapterError } from 'usecelo-react/adapters/stripe';
try {
await adapter.createCheckoutSession(options);
} catch (error) {
if (error instanceof PaymentAdapterError) {
console.error(`${error.adapterName} error:`, error.message);
console.error('Error code:', error.code);
} else {
console.error('Unexpected error:', error);
}
}Payment Integration Best Practices
- Always use HTTPS in production
- Handle loading states during checkout creation
- Implement error boundaries for payment failures
- Test with mock adapter before going live
- Validate webhook endpoints on your server
- Store minimal payment data client-side
Next.js App Router Integration
// app/checkout/page.tsx
"use client";
import { PaymentProvider, CheckoutButton } from 'usecelo-react';
export default function CheckoutPage() {
return (
<PaymentProvider
gateway="STRIPE"
publishableKey={process.env.NEXT_PUBLIC_STRIPE_KEY!}
>
<div className="max-w-2xl mx-auto p-8">
<h1>Complete Your Purchase</h1>
<CheckoutButton
planId="pro_monthly"
successUrl={`${window.location.origin}/success`}
cancelUrl={`${window.location.origin}/pricing`}
>
Subscribe to Pro - $29/month
</CheckoutButton>
</div>
</PaymentProvider>
);
}🔐 Authentication Providers
UseCelo supports multiple authentication providers with automatic user management:
Supported Auth Providers
| Provider | Adapter | Import | Auto-Detect |
|----------|---------|---------|-------------|
| Clerk | ClerkAdapter | usecelo-react/adapters/clerk | ✅ |
| Supabase | SupabaseAdapter | usecelo-react/adapters/supabase | ✅ |
| Auth0 | Auth0Adapter | usecelo-react/adapters/auth0 | ✅ |
| NextAuth | NextAuthAdapter | usecelo-react/adapters/nextauth | ✅ |
| Custom | CustomAdapter | usecelo-react/adapters/custom | ❌ |
Quick Setup Examples
Clerk (Recommended)
npm install @clerk/nextjs usecelo-reactimport { ClerkProvider } from '@clerk/nextjs';
import { UseCeloProvider } from 'usecelo-react';
import { ClerkAdapter } from 'usecelo-react/adapters/clerk';
export default function RootLayout({ children }) {
return (
<ClerkProvider>
<UseCeloProvider
appId={process.env.NEXT_PUBLIC_USECELO_APP_ID!}
publicKey={process.env.NEXT_PUBLIC_USECELO_PUBLIC_KEY!}
authAdapter={new ClerkAdapter()}
>
{children}
</UseCeloProvider>
</ClerkProvider>
);
}Supabase
npm install @supabase/auth-helpers-nextjs usecelo-reactimport { UseCeloProvider } from 'usecelo-react';
import { SupabaseAdapter } from 'usecelo-react/adapters/supabase';
import { createClientComponentClient } from '@supabase/auth-helpers-nextjs';
export default function RootLayout({ children }) {
return (
<UseCeloProvider
appId={process.env.NEXT_PUBLIC_USECELO_APP_ID!}
publicKey={process.env.NEXT_PUBLIC_USECELO_PUBLIC_KEY!}
authAdapter={new SupabaseAdapter(createClientComponentClient())}
>
{children}
</UseCeloProvider>
);
}Auth0
npm install @auth0/nextjs-auth0 usecelo-reactimport { UserProvider } from '@auth0/nextjs-auth0/client';
import { UseCeloProvider } from 'usecelo-react';
import { Auth0Adapter } from 'usecelo-react/adapters/auth0';
export default function RootLayout({ children }) {
return (
<UserProvider>
<UseCeloProvider
appId={process.env.NEXT_PUBLIC_USECELO_APP_ID!}
publicKey={process.env.NEXT_PUBLIC_USECELO_PUBLIC_KEY!}
authAdapter={new Auth0Adapter()}
>
{children}
</UseCeloProvider>
</UserProvider>
);
}Custom Auth Provider
import { UseCeloProvider } from 'usecelo-react';
import { CustomAdapter } from 'usecelo-react/adapters/custom';
const customAdapter = new CustomAdapter({
getUser: async () => {
const response = await fetch('/api/auth/me');
const user = await response.json();
return user ? {
id: user.id,
email: user.email,
name: user.name,
image: user.avatar
} : null;
},
onAuthStateChange: (callback) => {
const handleChange = (e) => callback(e.detail.user, e.detail.session);
window.addEventListener('auth-change', handleChange);
return () => window.removeEventListener('auth-change', handleChange);
}
});
export default function RootLayout({ children }) {
return (
<UseCeloProvider
appId={process.env.NEXT_PUBLIC_USECELO_APP_ID!}
publicKey={process.env.NEXT_PUBLIC_USECELO_PUBLIC_KEY!}
authAdapter={customAdapter}
>
{children}
</UseCeloProvider>
);
}Environment Variables
Create a .env.local file with your configuration:
# UseCelo Configuration
NEXT_PUBLIC_USECELO_APP_ID=app_xxxxx
NEXT_PUBLIC_USECELO_PUBLIC_KEY=pk_xxxxx
# Clerk (if using)
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_test_xxxxx
CLERK_SECRET_KEY=sk_test_xxxxx
# Supabase (if using)
NEXT_PUBLIC_SUPABASE_URL=https://xxxxx.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=xxxxx
# Auth0 (if using)
AUTH0_SECRET=xxxxx
AUTH0_BASE_URL=http://localhost:3000
AUTH0_ISSUER_BASE_URL=https://xxxxx.auth0.com
AUTH0_CLIENT_ID=xxxxx
AUTH0_CLIENT_SECRET=xxxxx
# Payment Gateways (if using)
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=pk_test_xxxxx
NEXT_PUBLIC_RAZORPAY_KEY_ID=rzp_test_xxxxxSSR & Hydration
The SDK automatically handles SSR and client-side hydration. No special configuration needed - just use the providers directly in your layout files without "use client" directives.
🚀 Advanced Usage (React Hooks)
For complex scenarios, you can use React hooks for programmatic access:
useUseCelo Hook
import { useUseCelo } from 'usecelo-react';
function MyComponent() {
const {
features, // All user features
loading, // Loading state
checkAccess, // Check feature access
trackUsage // Track usage programmatically
} = useUseCelo();
const handleAnalyze = async () => {
if (checkAccess('ai-analysis')) {
await analyzeDocument();
await trackUsage('ai-analysis', 1);
} else {
showUpgradePrompt();
}
};
return (
<button
onClick={handleAnalyze}
disabled={loading}
>
{loading ? 'Loading...' : 'Analyze Document'}
</button>
);
}useFeature Hook
import { useFeature } from 'usecelo-react';
function FeatureSpecificComponent() {
const {
hasAccess,
config,
limits,
usage,
loading
} = useFeature('api-calls');
return (
<div>
<p>API Calls: {usage}/{limits?.quota || 'Unlimited'}</p>
<button disabled={!hasAccess || loading}>
{hasAccess ? 'Make API Call' : 'Upgrade Required'}
</button>
</div>
);
}Feature Component (React)
import { Feature } from 'usecelo-react';
function Dashboard() {
return (
<div>
<Feature
name="premium-dashboard"
fallback={<div>Upgrade to see premium metrics</div>}
>
<PremiumDashboard />
</Feature>
</div>
);
}🖥️ Next.js App Router Integration
For Next.js App Router, create a client component wrapper:
// components/UseCeloWrapper.tsx
"use client";
import { UseCeloProvider } from 'usecelo-react';
import { ReactNode } from 'react';
interface Props {
children: ReactNode;
}
export default function UseCeloWrapper({ children }: Props) {
return (
<UseCeloProvider
appId={process.env.NEXT_PUBLIC_USECELO_APP_ID!}
publicKey={process.env.NEXT_PUBLIC_USECELO_PUBLIC_KEY!}
userId="user-123"
onFeatureBlock={(featureName) => {
console.log(`Feature blocked: ${featureName}`);
}}
onUpgradeClick={(featureName) => {
window.location.href = '/pricing';
}}
>
{children}
</UseCeloProvider>
);
}// app/layout.tsx
import UseCeloWrapper from '../components/UseCeloWrapper';
export default function RootLayout({ children }) {
return (
<html>
<body>
<UseCeloWrapper>
{children}
</UseCeloWrapper>
</body>
</html>
);
}🐛 Troubleshooting
Common Issues
1. "PricingTable not found" or Import Errors
Problem: Module not exporting correctly
Solution: Rebuild the SDK
cd your-sdk-directory
npm run build2. Features Not Gating Properly
Problem: Data attributes not working
Solutions:
- Verify
appIdandpublicKeyare correct - Check feature names match your UseCelo dashboard
- Ensure
UseCeloProviderwraps your app - Check browser console for error messages
3. Next.js Hydration Errors
Problem: Server/client mismatch
Solution: Use client component wrapper pattern:
"use client";
import { UseCeloProvider } from 'usecelo-react';
// ... rest of component4. TypeScript Errors
Problem: Missing type definitions
Solutions:
- Update to latest SDK version
- Check TypeScript compatibility
- Import types explicitly:
import type { PricingTableProps } from 'usecelo-react';Debug Mode
Enable debug logging in browser console:
localStorage.debug = 'usecelo:*';Performance Tips
- Automatic Caching: Feature access cached for 5 minutes
- Batch Usage Tracking: Events batched and sent efficiently
- DOM Optimization: MutationObserver efficiently watches for new elements
- Lazy Loading: Features loaded only when needed
📜 Legacy Component Support
The SDK maintains backward compatibility with direct component props:
import { PricingTable } from 'usecelo-react';
function PricingPage() {
return (
<PricingTable
appId="your-app-id"
publicKey="your-public-key"
apiHost="https://your-api.com"
onSelectPlan={(planId) => {
console.log('Selected plan:', planId);
}}
showAnnualToggle={true}
className="max-w-6xl mx-auto"
/>
);
}Migration from Props to Root Wrapper
Before (v0.2.x and earlier):
// Had to pass props to every component
<PricingTable appId="app_123" publicKey="pk_..." />
<FeatureGate appId="app_123" publicKey="pk_..." feature="premium" />After (v0.3.x+):
// Wrap once at the root
<UseCeloProvider appId="app_123" publicKey="pk_...">
<App />
</UseCeloProvider>
// Then use anywhere without imports
<div data-feature="premium">Premium content</div>
<PricingTable /> {/* Props optional, gets from context */}🔧 API Reference
UseCeloProvider Props
| Prop | Type | Required | Default | Description |
|------|------|----------|---------|-------------|
| apiKey | string | ✅ | - | Your UseCelo API key |
| appId | string | ✅ | - | Your application ID |
| userId | string | ⚠️ | - | Current user's ID |
| apiHost | string | ❌ | https://use-pricing.com | API endpoint |
| enableCache | boolean | ❌ | true | Enable response caching |
| cacheTTL | number | ❌ | 300000 | Cache TTL in milliseconds |
| autoIdentify | boolean | ❌ | true | Auto-identify user on mount |
| onError | function | ❌ | - | Error callback |
| onUserChange | function | ❌ | - | User change callback |
| onSubscriptionChange | function | ❌ | - | Subscription change callback |
Hook Returns
usePricing()
Returns comprehensive pricing context plus convenience methods.
📊 TypeScript Support
Full TypeScript support with comprehensive type definitions:
import {
UseCeloProvider,
useUseCelo,
useFeature,
PricingTable,
Feature,
type PricingTableProps,
type UseCeloConfig
} from 'usecelo-react';
// All components and hooks are fully typed
const MyComponent: React.FC = () => {
const { features, loading, checkAccess } = useUseCelo();
const { hasAccess, usage } = useFeature('api-calls');
return <div>{/* Your component */}</div>;
};📊 Performance & Best Practices
Built for Scale
- Automatic Caching: Feature access cached for 5 minutes by default
- Batch Usage Tracking: Usage events batched and sent efficiently
- DOM Optimization: MutationObserver efficiently tracks DOM changes
- Lazy Loading: Features loaded only when needed
- Tree Shaking: Import only what you use
Best Practices
- Use data attributes for simple feature gating
- Use React hooks for complex logic only
- Set meaningful feature names that match your dashboard
- Handle loading states in your UI
- Test fallback behaviors thoroughly
🔗 Links & Support
- 📖 Documentation: docs.usecelo.com
- 🐛 Issues: GitHub Issues
- 💬 Support: [email protected]
- 💼 Dashboard: usecelo.com
📄 License
MIT © UseCelo
🎆 Ready to ship feature gating in minutes?
npm install usecelo-react- Wrap your app with
UseCeloProvider - Add
data-featureattributes anywhere - Deploy and start gating features! 🚀
