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-coreOr with yarn / pnpm:
yarn add @bricqs/sdk-react @bricqs/sdk-core
# or
pnpm add @bricqs/sdk-react @bricqs/sdk-coreProvider 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.
// 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>
);
}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 Option | Type | Description |
|---|---|---|
participantToken | string | JWT 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. |
apiUrl | string | API base URL. Defaults to https://api.bricqs.co. Override for self-hosted or staging. |
runtimeBaseUrl | string | Runtime base URL for managed rendering. Defaults to https://runtime.bricqs.co. |
participantId | string | Explicit participant ID. Auto-generated (p_...) if omitted and no token subject is present. |
debug | boolean | Enable verbose console logging for development. |
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"
/>
);
}| Prop | Type | Description |
|---|---|---|
id | string | Required. Engagement UUID. |
onComplete | function | Declared 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. |
onActivityComplete | function | Called when an individual activity (quiz, form, etc.) completes. |
onPointsAwarded | function | Called when points are awarded to the participant. |
onBadgeUnlocked | function | Called when a badge is unlocked. |
onRewardClaimed | function | Called when a reward (coupon, voucher, etc.) is claimed. |
onTierChanged | function | Called when the participant's tier changes. |
style | CSSProperties | Inline styles applied to the container div. |
className | string | CSS 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.
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 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 Rule | Type | Description |
|---|---|---|
url | string | Glob pattern matched against the current URL path (e.g. /products/*). |
minTimeOnPage | number | Seconds the user must spend on the page before showing. |
scrollDepth | number | Minimum scroll percentage (0-100) before showing. |
maxImpressions | number | Maximum times to show the engagement. |
maxImpressionsWindow | string | Time window for impression limit: session, day, week, month, lifetime. |
userAttribute | object | Match on user attributes: { key, operator, value }. |
schedule | object | Time-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.
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/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/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>
);
}.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>
);
}