React SDK

First-class React integration with hooks, components, and HOCs. Built on top of the JavaScript SDK.

Installation

npm install @retenshun/react
# or
yarn add @retenshun/react

The React SDK includes the JavaScript SDK as a dependency — no need to install both.

Provider Setup

Wrap your app with RetenshunProvider at the root level:

// app/layout.tsx (Next.js App Router)
import { RetenshunProvider } from '@retenshun/react'

export default function RootLayout({ children }) {
  return (
    <html>
      <body>
        <RetenshunProvider
          projectId="YOUR_PROJECT_ID"
          apiKey="pk_live_YOUR_PUBLIC_KEY"
          config={{
            apiUrl: 'https://your-domain.com',  // optional
            debug: false,                        // optional
            autoTrack: { pageViews: true },      // optional
          }}
        >
          {children}
        </RetenshunProvider>
      </body>
    </html>
  )
}

Pages Router

// pages/_app.tsx
import { RetenshunProvider } from '@retenshun/react'

export default function App({ Component, pageProps }) {
  return (
    <RetenshunProvider
      projectId="YOUR_PROJECT_ID"
      apiKey="pk_live_YOUR_PUBLIC_KEY"
    >
      <Component {...pageProps} />
    </RetenshunProvider>
  )
}

useRetenshun Hook

The main hook that gives you access to everything:

import { useRetenshun } from '@retenshun/react'

function Dashboard() {
  const {
    isReady,           // boolean — SDK initialized
    identify,          // (userId, properties?) => void
    track,             // (eventName, properties?) => void
    page,              // (pageName?, properties?) => void
    setUserProperties, // (properties) => void
    reset,             // () => void
    getUserId,         // () => string | null
    ecommerce,         // e-commerce helpers
  } = useRetenshun()

  // Wait for SDK
  if (!isReady) return null

  return <div>Dashboard for {getUserId()}</div>
}

Identify Users

import { useRetenshun } from '@retenshun/react'

function LoginForm() {
  const { identify } = useRetenshun()

  async function handleLogin(email, password) {
    const user = await api.login(email, password)

    // Identify after successful login
    identify(user.id, {
      email: user.email,
      name: user.name,
      plan: user.subscription.plan,
    })
  }

  return <form onSubmit={...}>...</form>
}

Track Events

import { useTrack } from '@retenshun/react'

function UpgradeButton() {
  const { track } = useTrack()

  return (
    <button
      onClick={() => {
        track('upgrade_clicked', { from: 'free', to: 'pro' })
        // ... handle upgrade
      }}
    >
      Upgrade to Pro
    </button>
  )
}

Specialized Hooks

Use focused hooks when you only need one capability:

import { useTrack, useIdentify, useEcommerce } from '@retenshun/react'

// Only tracking
function FeatureComponent() {
  const { track, isReady } = useTrack()
  // ...
}

// Only identification
function AuthWrapper() {
  const { identify, isReady } = useIdentify()
  // ...
}

// Only e-commerce
function ProductPage({ product }) {
  const { ecommerce, isReady } = useEcommerce()

  useEffect(() => {
    if (isReady) {
      ecommerce.productViewed({
        product_id: product.id,
        name: product.name,
        price: product.price,
      })
    }
  }, [isReady, product.id])

  return <div>...</div>
}

Tracking Components

Declarative components for common tracking patterns:

TrackPageView

import { TrackPageView } from '@retenshun/react'

// Tracks a page view when this component mounts
function PricingPage() {
  return (
    <>
      <TrackPageView name="Pricing" properties={{ variant: 'annual' }} />
      <h1>Pricing</h1>
      {/* ... */}
    </>
  )
}

TrackEvent

import { TrackEvent } from '@retenshun/react'

// Tracks an event when this component mounts
function OnboardingComplete() {
  return (
    <>
      <TrackEvent
        event="onboarding_completed"
        properties={{ steps: 5 }}
        once={true}  // Only track once per session
      />
      <h1>You're all set!</h1>
    </>
  )
}

Higher-Order Component

Automatically track when a component is viewed:

import { withTracking } from '@retenshun/react'

function FeatureCard({ name, description }) {
  return (
    <div>
      <h3>{name}</h3>
      <p>{description}</p>
    </div>
  )
}

// Tracks "feature_card_viewed" every time this component mounts
export default withTracking(
  FeatureCard,
  'feature_card_viewed',
  (props) => ({ feature: props.name })  // optional: extract properties from props
)

E-commerce

import { useEcommerce } from '@retenshun/react'

function ProductPage({ product }) {
  const { ecommerce } = useEcommerce()

  return (
    <div>
      <h1>{product.name}</h1>
      <button
        onClick={() =>
          ecommerce.addedToCart({
            product_id: product.id,
            name: product.name,
            price: product.price,
            quantity: 1,
          })
        }
      >
        Add to Cart
      </button>
    </div>
  )
}

// Checkout flow
function CheckoutPage({ cart }) {
  const { ecommerce } = useEcommerce()

  useEffect(() => {
    ecommerce.checkoutStarted({
      cart_id: cart.id,
      total: cart.total,
      item_count: cart.items.length,
    })
  }, [])

  async function handlePurchase() {
    const order = await api.placeOrder(cart)
    ecommerce.orderCompleted({
      order_id: order.id,
      total: order.total,
      currency: 'USD',
      products: order.items,
    })
  }

  return <button onClick={handlePurchase}>Place Order</button>
}

Logout / Reset

import { useRetenshun } from '@retenshun/react'

function UserMenu() {
  const { reset } = useRetenshun()

  return (
    <button onClick={() => {
      reset()          // Clear Retenshun identity
      auth.signOut()   // Your auth logout
    }}>
      Sign Out
    </button>
  )
}

Complete Example

// app/layout.tsx
import { RetenshunProvider } from '@retenshun/react'

export default function RootLayout({ children }) {
  return (
    <html>
      <body>
        <RetenshunProvider
          projectId="proj_abc123"
          apiKey="pk_live_your_key"
        >
          {children}
        </RetenshunProvider>
      </body>
    </html>
  )
}

// app/page.tsx
import { useRetenshun, TrackPageView } from '@retenshun/react'

export default function HomePage() {
  const { track, identify, isReady } = useRetenshun()

  return (
    <>
      <TrackPageView name="Home" />
      <h1>Welcome</h1>
      <button onClick={() => track('cta_clicked')}>
        Get Started
      </button>
    </>
  )
}

What's Next?