Pattern: spin campaign
A 10-day sale spin wheel with email gate, server-side prize draw, one spin per identity per day, and one-tap redeem. The whole campaign ships in a working day if your auth and ESP are already wired.
Key takeaways
Quick read- Configure the spin engagement once. Prize segments and odds live server-side.
- Email gate runs before the spin, not after. Capture rate halves if you wait.
- Server-side prize draw. The client animates to the predetermined outcome; never decides.
- One spin per identity per day enforced server-side via idempotency keys.
- Auto-apply the reward at checkout via API; no copy-paste codes.
Anatomy
What you are building
API
The spin engagement (segments, weights, prizes, window, rate limit) is built in the dashboard. Your app submits each spin; the server runs the weighted draw and returns the prize.
SDK
useSpinWheel({ engagementId, activityId, config }) returns the segments and a spin() that resolves to the server-drawn prize.
User sees
Email field, then a spinning wheel that lands on a prize. Reveal moment, then a one-tap claim button.
Step 1: config
Build the spin in the dashboard
The spin engagement is created in the Builder, not via a public API. You configure it there, publish it, and your app renders it with the SDK. What you set up in the Builder:
Spin wheel engagement (Builder -> new engagement -> Spin Wheel):
Window 2026-10-25 to 2026-11-05
Rate limit 1 spin per identity per day
Segments weight prize
Free outfit 1 voucher 5000
500 INR off 15 voucher 500
Free shipping 35 coupon / benefit
5% off 49 coupon 5%
Prizes map to reward definitions you also create in the dashboard. The server
does the weighted draw at spin time; the client never sees the odds.Step 2: email gate
Capture before the spin
"use client";
import { useState } from "react";
export function SpinGate({ onPass }: { onPass: () => void }) {
const [email, setEmail] = useState("");
return (
<form
onSubmit={async (e) => {
e.preventDefault();
await fetch("/api/bricqs/identify", {
method: "POST",
body: JSON.stringify({ email }),
});
onPass();
}}
>
<h2>Spin to win up to 5,000 INR off</h2>
<input
type="email"
required
value={email}
onChange={(e) => setEmail(e.target.value)}
placeholder="you@email.com"
/>
<button>Spin to reveal</button>
</form>
);
}The /api/bricqs/identify route on your server creates or upserts the participant via the admin API and returns a participant token.
Step 3: spin
Server-determined draw
"use client";
import { useSpinWheel } from "@bricqs/sdk-react";
export function SpinWheel() {
const { isSpinning, result, rotation, spin, confirmResult } = useSpinWheel({
engagementId: "diwali_spin_2026",
activityId: "spin_wheel_1",
config: { segments: SEGMENTS },
});
async function onSpin() {
// Server draws the result first — the client only animates to it.
const outcome = await spin();
await animateToRotation(rotation);
// Records completion + applies the reward's onCompletion actions.
await confirmResult();
if (outcome) setRevealedReward(outcome.segment.label);
}
return (
<button onClick={onSpin} disabled={isSpinning}>
{result ? "Spin again" : "Spin"}
</button>
);
}The server draws before the wheel moves, so the animation always lands on the real prize. confirmResult() applies the reward once the animation completes.
Step 4: claim
Auto-apply the reward
async function claimAndCheckout(rewardId: string) {
const res = await fetch("/api/bricqs/claim-reward", {
method: "POST",
body: JSON.stringify({ rewardId }),
});
const { code } = await res.json();
// Apply to the cart server-side, route to checkout
await applyDiscountCode(code);
router.push("/checkout");
}Step 5: anti-fraud
What runs automatically
Bricqs enforces:
- One spin per identity per day (configured rate_limit)
- max_reward_liability cap; jackpot allocation halts when exceeded
- Server-side draw (segment is decided on the server, never on the client)
- Disposable email pattern detection
- IP and device velocity caps (cross-day attempts from same fingerprint)
You should add:
- hCaptcha or Turnstile on the email gate for cold traffic
- Email confirmation step before claiming high-value prizes
- Manual review for jackpot wins above a thresholdDeveloper FAQ
Common questions when integrating gamification with Bricqs.
Ready to ship?
Wire it up with the Bricqs SDK or API
Headless SDK for React UIs, REST API for any backend. Same engine behind both.
