BricqsBricqs
Documentation

React SDK

First-class React/Next.js integration. Install the SDK package, wrap your app with a provider, and render engagements with full TypeScript support, eligibility checks, and event callbacks.

Installation

npm install @bricqs/sdk-react @bricqs/sdk-core

Or with yarn / pnpm:

yarn add @bricqs/sdk-react @bricqs/sdk-core
# or
pnpm add @bricqs/sdk-react @bricqs/sdk-core
Requirements: React 18+ and TypeScript 5+ (recommended but not required). The SDK ships with full type definitions.

Provider Setup

Wrap your application (or a section of it) with BricqsProvider. This initializes the SDK client, manages sessions, and provides context to all child components and hooks.

Basic Setup (server-side mint, browser-side use)
// app/api/bricqs-token/route.ts (Next.js Route Handler)
import { mintParticipantToken } from '@bricqs/sdk-server';

export async function GET() {
  const { token } = await mintParticipantToken({
    adminApiKey: process.env.BRICQS_ADMIN_API_KEY!,
    participantId: 'user_123', // your stable user ID
  });
  return Response.json({ token });
}

// app/providers.tsx (browser)
import { BricqsProvider } from '@bricqs/sdk-react';

function App() {
  return (
    <BricqsProvider
      config={{
        getToken: async () => {
          const res = await fetch('/api/bricqs-token');
          return (await res.json()).token;
        },
      }}
    >
      <YourApp />
    </BricqsProvider>
  );
}
With user identification
import { BricqsProvider } from '@bricqs/sdk-react';

function App() {
  const user = useYourAuthHook(); // your auth

  return (
    <BricqsProvider
      // Provider-level defaults every hook inherits:
      participantId={user?.id}          // falls back to the token's subject
      // engagementId="eng_uuid"        // optional shared default
      config={{
        getToken: async () => {
          // Your mint route embeds the SAME user id into the token, so the
          // browser identity and the token subject always agree.
          const res = await fetch('/api/bricqs-token');
          return (await res.json()).token;
        },
      }}
    >
      <YourApp />
    </BricqsProvider>
  );
}
Config OptionTypeDescription
participantTokenstringJWT minted server-side via @bricqs/sdk-server. Use for SSR or one-shot bootstrap.
getToken() => Promise<string>Async token provider. Called once on first request and again on 401. Use for production deployments where tokens expire.
apiUrlstringAPI base URL. Defaults to https://api.bricqs.co. Override for self-hosted or staging.
runtimeBaseUrlstringRuntime base URL for managed rendering. Defaults to https://runtime.bricqs.co.
participantIdstringExplicit participant ID. Auto-generated (p_...) if omitted and no token subject is present.
debugbooleanEnable verbose console logging for development.
User Identity, Pass your stable user ID as the provider's participantId prop AND as participantId when minting the token server-side. The token's subject is authoritative; keeping both in sync gives cross-device continuity, leaderboard names, and reward delivery.

Rendering Engagements

Use the BricqsEngagement component to render a published engagement. It creates a managed iframe with auto-resize and event forwarding.

import { BricqsEngagement } from '@bricqs/sdk-react';

function CampaignPage() {
  return (
    <BricqsEngagement
      id="YOUR_ENGAGEMENT_UUID"
      onActivityComplete={(data) => {
        // data: { activityId, activityType, result?, actionResults? }
        console.log('Activity done:', data.activityType);
      }}
      onPointsAwarded={({ points, newBalance }) => {
        console.log(`+${points} points! Balance: ${newBalance}`);
      }}
      onBadgeUnlocked={({ badgeName, badgeCode }) => {
        showToast(`Badge earned: ${badgeName}`);
      }}
      onRewardClaimed={({ rewardName, rewardType, codeValue }) => {
        showCouponModal(rewardName, codeValue);
      }}
      onTierChanged={({ tierName, tierLevel }) => {
        showCelebration(`Welcome to ${tierName}!`);
      }}
      style={{ maxWidth: 640, margin: '0 auto' }}
      className="my-engagement"
    />
  );
}
PropTypeDescription
idstringRequired. Engagement UUID.
onCompletefunctionDeclared for engagement-level completion, but the runtime does not emit that message today; do not depend on it. Derive completion from onActivityComplete events. See Client Events.
onActivityCompletefunctionCalled when an individual activity (quiz, form, etc.) completes.
onPointsAwardedfunctionCalled when points are awarded to the participant.
onBadgeUnlockedfunctionCalled when a badge is unlocked.
onRewardClaimedfunctionCalled when a reward (coupon, voucher, etc.) is claimed.
onTierChangedfunctionCalled when the participant's tier changes.
styleCSSPropertiesInline styles applied to the container div.
classNamestringCSS class applied to the container div.

Eligibility & Trigger Rules

The React SDK supports eligibility checks, decide whether to show an engagement based on conditions like URL patterns, user attributes, time windows, and frequency caps.

Check eligibility before rendering
import { useEligibility } from '@bricqs/sdk-react';

function ConditionalEngagement() {
  const { isEligible, isLoading, reason } = useEligibility({
    engagementId: 'YOUR_UUID',
    context: {
      url: window.location.href,
      referrer: document.referrer,
      userAgent: navigator.userAgent,
    },
  });

  if (isLoading) return <Spinner />;
  if (!isEligible) return null; // Don't render

  return <BricqsEngagement id="YOUR_UUID" />;
}
BricqsSpot, auto-eligibility component

BricqsSpot combines eligibility checking with rendering in a single component. Place it anywhere in your app and it will only render if the engagement is eligible for the current context.

import { BricqsSpot } from '@bricqs/sdk-react';

function ProductPage() {
  return (
    <div>
      <h1>Product Details</h1>
      <ProductInfo />

      {/* Only renders if the engagement is eligible */}
      <BricqsSpot
        engagementId="YOUR_UUID"
        trigger={{
          url: '/products/*',        // URL pattern match
          minTimeOnPage: 10,         // Wait 10 seconds
          scrollDepth: 50,           // 50% scroll depth
          maxImpressions: 3,         // Show max 3 times
          maxImpressionsWindow: 'day', // Per day
        }}
        placement="inline"          // 'inline' | 'modal' | 'slide-in'
        onDismiss={() => console.log('User dismissed')}
        onImpression={() => analytics.track('bricqs_impression')}
      />
    </div>
  );
}
Trigger RuleTypeDescription
urlstringGlob pattern matched against the current URL path (e.g. /products/*).
minTimeOnPagenumberSeconds the user must spend on the page before showing.
scrollDepthnumberMinimum scroll percentage (0-100) before showing.
maxImpressionsnumberMaximum times to show the engagement.
maxImpressionsWindowstringTime window for impression limit: session, day, week, month, lifetime.
userAttributeobjectMatch on user attributes: { key, operator, value }.
scheduleobjectTime-based rules: { startDate, endDate, daysOfWeek, timeRange }.

Available Hooks

The React SDK exports hooks for accessing Bricqs data and state. These are available within a BricqsProvider context.

useBricqsClient()

Access the underlying BricqsClient instance for direct API calls.

useEligibility(options)

Check if an engagement should be shown based on trigger rules, frequency caps, and eligibility conditions.

usePoints(options)

Access points balance, transaction history, and tier info. Auto-refreshes on points:awarded events.

useBricqsStream(options)

Subscribe to real-time server-sent events (points, badges, rewards, challenge progress) with automatic reconnect and replay.

Want full headless control? The SDK also includes advanced hooks for building completely custom UIs, useQuiz, useSpinWheel, useForm, useBadgesHeadless, useChallenge, and more. See the Headless SDK page.

Next.js Integration

The SDK works with both the Pages Router and App Router. Since the provider uses React context and browser APIs, it must run on the client.

App Router (app/layout.tsx + route handler)
// app/api/bricqs-token/route.ts (server-side)
import { mintParticipantToken } from '@bricqs/sdk-server';

export async function GET() {
  const { token } = await mintParticipantToken({
    adminApiKey: process.env.BRICQS_ADMIN_API_KEY!,
    participantId: 'user_123', // your stable user ID
  });
  return Response.json({ token });
}

// app/layout.tsx (browser)
'use client';

import { BricqsProvider } from '@bricqs/sdk-react';

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html>
      <body>
        <BricqsProvider config={{
          getToken: async () => {
            const res = await fetch('/api/bricqs-token');
            return (await res.json()).token;
          },
        }}>
          {children}
        </BricqsProvider>
      </body>
    </html>
  );
}
Pages Router (_app.tsx + API route)
// pages/api/bricqs-token.ts (server-side)
import { mintParticipantToken } from '@bricqs/sdk-server';

export default async function handler(req, res) {
  const { token } = await mintParticipantToken({
    adminApiKey: process.env.BRICQS_ADMIN_API_KEY!,
    participantId: 'user_123',
  });
  res.status(200).json({ token });
}

// pages/_app.tsx (browser)
import { BricqsProvider } from '@bricqs/sdk-react';
import type { AppProps } from 'next/app';

export default function App({ Component, pageProps }: AppProps) {
  return (
    <BricqsProvider config={{
      getToken: async () => {
        const res = await fetch('/api/bricqs-token');
        return (await res.json()).token;
      },
    }}>
      <Component {...pageProps} />
    </BricqsProvider>
  );
}
Environment variable: Store your admin API key in .env.local as BRICQS_ADMIN_API_KEY=bq_live_xxx. Do NOT use the NEXT_PUBLIC_ prefix, that exposes the key to the browser, which the SDK refuses at construction. The admin key stays on your server; only the short-lived participant token reaches the browser.

TypeScript Support

The SDK ships with complete TypeScript definitions. All props, events, and return types are fully typed.

import type {
  BricqsConfig,
  EngagementResult,
  ActivityResult,
  PointsAwardedEvent,
  BadgeUnlockedEvent,
  RewardClaimedEvent,
  TierChangedEvent,
  EligibilityResult,
  TriggerConfig,
} from '@bricqs/sdk-react';

// All event callbacks are fully typed
const handlePoints = (event: PointsAwardedEvent) => {
  // event.points: number
  // event.newBalance: number
};

const handleReward = (event: RewardClaimedEvent) => {
  // event.rewardName: string
  // event.rewardType: string
  // event.codeValue: string | undefined
};

Full Example

A complete React app with Bricqs integration, engagement rendering, event handling, and points display.

import { BricqsProvider, BricqsEngagement, usePoints } from '@bricqs/sdk-react';

// Pair this with a server route (e.g. /api/bricqs-token) that calls
// mintParticipantToken from @bricqs/sdk-server — see "Next.js" above.
function App() {
  return (
    <BricqsProvider config={{
      getToken: async () => {
        const res = await fetch('/api/bricqs-token');
        return (await res.json()).token;
      },
    }}>
      <div className="app">
        <Header />
        <CampaignPage />
      </div>
    </BricqsProvider>
  );
}

function Header() {
  const { balance } = usePoints({ engagementId: 'YOUR_UUID' });
  return (
    <header>
      <h1>My App</h1>
      <span>{balance} points</span>
    </header>
  );
}

function CampaignPage() {
  return (
    <main>
      <h2>Today's Challenge</h2>
      <BricqsEngagement
        id="YOUR_ENGAGEMENT_UUID"
        onPointsAwarded={({ points }) => {
          // Points display auto-updates via usePoints hook
          showToast(`+${points} points!`);
        }}
        onRewardClaimed={({ rewardName, codeValue }) => {
          showCouponModal(rewardName, codeValue);
        }}
        onActivityComplete={({ activityType }) => {
          // Route when the final activity completes (engagement-level
          // onComplete is not emitted by the runtime today).
          if (activityType === 'quiz') router.push('/thank-you');
        }}
      />
    </main>
  );
}

Next Steps