npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

usecelo-react

v0.6.0

Published

Complete React SDK for pricing, feature gating, and usage management with UseCelo

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-react

1. 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 URL

Available 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

  1. Always use HTTPS in production
  2. Handle loading states during checkout creation
  3. Implement error boundaries for payment failures
  4. Test with mock adapter before going live
  5. Validate webhook endpoints on your server
  6. 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-react
import { 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-react
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 (
    <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-react
import { 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_xxxxx

SSR & 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 build

2. Features Not Gating Properly

Problem: Data attributes not working
Solutions:

  • Verify appId and publicKey are correct
  • Check feature names match your UseCelo dashboard
  • Ensure UseCeloProvider wraps 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 component

4. 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

  1. Use data attributes for simple feature gating
  2. Use React hooks for complex logic only
  3. Set meaningful feature names that match your dashboard
  4. Handle loading states in your UI
  5. Test fallback behaviors thoroughly

🔗 Links & Support

📄 License

MIT © UseCelo


🎆 Ready to ship feature gating in minutes?

  1. npm install usecelo-react
  2. Wrap your app with UseCeloProvider
  3. Add data-feature attributes anywhere
  4. Deploy and start gating features! 🚀