Skip to main content
This guide adds Claimr to a client-rendered React app (Vite, Create React App, or any React Router setup). For Next.js, follow the Next.js guide instead, since it adds server-side rendering and server routes. You will build four small pieces:
Read How the loader works first if you want to understand why the code is split this way. In short: the script loads once at the app root, and the widget attaches to whichever container is currently rendered.

Prerequisites

  • React 18 or later.
  • Your organization ID and campaign ID from Publish > Get embed code in the Claimr admin panel.

Set up the integration

1

Add environment variables

Create or update .env in your project root. These values are public.
.env
With Create React App, use the REACT_APP_ prefix and read them from process.env instead of import.meta.env.
2

Add the shared loader module

Create src/lib/claimr.ts with the contents of the shared loader module. Copy it as is. It has no dependencies.
3

Create the provider

The provider is the only place that loads the script and assigns callbacks. It turns SDK callbacks into React state.
src/claimr/ClaimrProvider.tsx
4

Create the widget component

The widget component only renders the container. The loader notices it and attaches the widget. When the component unmounts, the loader removes the widget on its own.
src/claimr/ClaimrWidget.tsx
Render at most one ClaimrWidget at a time. The loader attaches to the first element with the container ID.
5

Create the hook

src/claimr/useClaimr.ts
6

Wrap your app

Wrap the whole app once, above your router, so the script survives route changes.
src/main.tsx
7

Render the widget

Place ClaimrWidget on the page or route where the campaign should appear.
src/pages/QuestsPage.tsx
With React Router, other routes simply do not render the container, and the loader detaches the widget when you leave this route.

Use the SDK from components

Call SDK methods through the hook. Methods that need a loaded widget are wrapped in withWidget, so they are safe to call at any time.
complete_task only works for tasks configured as front-end tasks in the campaign. See SDK tasks. To react to other widget events, add more callbacks in the provider’s setup function, for example claimr.on_leaderboard_open or claimr.on_analytics_event, and expose them through context. Do not assign callbacks from other components: each callback has a single owner, so the last assignment wins.

Sign users in with your own accounts

If your users already sign in to your app, give them a Claimr user token so they do not have to sign in again inside the widget.
1

Generate the token on your server

Your API token is secret. Call the token endpoint from your backend, never from React code.
server/claimr-token.ts
Expose it through an authenticated endpoint of your own, for example GET /api/claimr-token, that reads the current user from the session. The token does not expire, so you can store it with the user record.
2

Pass the token to the provider

Wrap ClaimrProvider in a component that knows your signed-in user, and use it in main.tsx in place of the plain <ClaimrProvider>. It must render inside your auth provider.
src/claimr/ClaimrAuthProvider.tsx
3

Log out of Claimr when the user logs out of your app

When a different user signs in without a page reload, call logout() before the new token reaches set_user_token.
Enable the matching sign-in option in the campaign under Settings > Sign-in options.

Connect the user’s wallet (dApps)

If your app already connects a wallet, let the widget use it instead of asking the user to connect again. Set platform: 'dapp' in the provider config and implement on_wallet_request. This example uses wagmi and RainbowKit, and must render inside WagmiProvider and RainbowKitProvider.
src/claimr/ClaimrWalletBridge.tsx
Render ClaimrWalletBridge inside ClaimrProvider and only after the provider reports loaded, for example {loaded && <ClaimrWalletBridge />}. That guarantees window.claimr exists when the handler is assigned.
Each op must return a value or throw. Throwing reports a failure to the widget immediately, instead of leaving it waiting. See on_wallet_request for the full contract and Integrate Claimr widget into your dApp for the campaign settings a dApp needs.

Verify the integration

  1. Run the app and open the page with ClaimrWidget. The campaign renders inside the container.
  2. In the browser console, run window.claimr.is_claimr_ready. It returns true.
  3. Navigate to another route and back. The widget disappears and comes back, and document.querySelectorAll('#claimr-script').length is still 1.
  4. Open a quest, then press the browser back button. The page still scrolls.
  5. If you use user tokens, sign in to your app and confirm the widget shows the same user without a second sign-in.
To see what the loader is doing, add debug: true to the provider config. The loader then logs its steps to the console.