Skip to main content
This guide adds Claimr to a Next.js 13.4+ app. It covers the App Router first, then the Pages Router. The widget always runs in the browser; Next.js server features are only used to keep your API token secret while generating user tokens. Paths below assume the @/ import alias points at your source root, which is the create-next-app default.
Read How the loader works for the reasoning behind this layout. In short: the script loads once in the root layout, which persists across client-side navigation, and the widget attaches to whichever page currently renders the container.

Set up the integration (App Router)

1

Add environment variables

.env.local
You only need CLAIMR_API_TOKEN and CLAIMR_PLATFORM if your users sign in through your app. CLAIMR_PLATFORM is a short name for your platform. It cannot be claimr.
2

Add the shared loader module

Create lib/claimr.ts with the contents of the shared loader module. It guards every window access, so importing it from a client component is safe during server rendering.
3

Create the provider

claimr/ClaimrProvider.tsx
4

Create the widget component

claimr/ClaimrWidget.tsx
The empty <div> is rendered on the server too. That is intended: the script loads after hydration, so the loader adds its iframe to a node React has already hydrated, and there is no hydration mismatch.
5

Create the hook

claimr/useClaimr.ts
6

Add the provider to the root layout

The root layout is a Server Component. It can render the client provider directly.
app/layout.tsx
Put the provider in the root layout, not in a nested layout or a page. The root layout never unmounts during client-side navigation, so the script loads exactly once.
7

Render the widget on a page

Pages stay Server Components. Only the widget itself is a client component.
app/quests/page.tsx
When the user navigates with <Link> to a page without ClaimrWidget, the loader detaches the widget. When they come back, it attaches it again.
Prefer next/script? You can load the script with <Script id="claimr-script" src="https://widgets.claimr.io/claimr.min.js" strategy="afterInteractive" data-organization="..." data-campaign="..." data-container="claimr-widget" data-autoresize="true" onLoad={...} /> in the root layout instead of loadClaimr. Keep the ID exactly claimr-script, keep it in the root layout only, and assign callbacks in onLoad. The rest of this guide works the same way.

Use the SDK from components

Any client component inside the provider can call SDK methods through the hook:
components/OpenQuestButton.tsx
openQuest works on pages without the widget too: the quest is remembered and opens when the user reaches a page that renders ClaimrWidget. Methods such as completeTask and setLanguage wait for the widget internally.

Sign users in with your own accounts

If your users already sign in to your app, generate a Claimr user token on the server and pass it to the provider.
1

Create the server helper

lib/claimr-server.ts
The server-only import makes the build fail if a client component ever imports this file. Install it with npm install server-only.
2

Pass the token from the root layout

app/layout.tsx
Reading the session in the root layout makes every route dynamic, and this example calls the Claimr API on each request. The token never expires, so store it with your user record after the first request and read it from there.
3

Or fetch the token from a route handler

If you want to keep pages static, or users sign in without a full page load, expose the token through a route handler and fetch it from the client.
app/api/claimr/token/route.ts
claimr/ClaimrAuthProvider.tsx
Use ClaimrAuthProvider in the root layout in place of ClaimrProvider.
4

Log out of Claimr when the user logs out

Enable the matching sign-in option in the campaign under Settings > Sign-in options. See User token.

Pages Router

The same files work with the Pages Router. Drop the 'use client' directives (they are ignored there), replace server-only with a plain module that you only import from API routes or getServerSideProps, and wire it up like this:
pages/_app.tsx
pages/api/claimr-token.ts
_app persists across client-side navigation in the Pages Router, just as the root layout does in the App Router.

Wallets and Telegram

  • dApp with its own wallet: add platform: 'dapp' to the loadClaimr config and render the ClaimrWalletBridge component from the React guide inside your wagmi providers. Mark it 'use client'.
  • Telegram Mini App: add platform: 'telegram' to the config. See Telegram Mini App.

Verify the integration

  1. Run npm run dev and open the page with ClaimrWidget. The campaign renders, and the terminal shows no window is not defined errors.
  2. In the browser console, window.claimr.is_claimr_ready returns true.
  3. Navigate away with a <Link> and back. The widget comes back, and document.querySelectorAll('#claimr-script').length is still 1.
  4. Run npm run build. The build succeeds, and CLAIMR_API_TOKEN does not appear in .next/static.
  5. If you use user tokens, sign in to your app and confirm the widget shows the same user without a second sign-in.