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
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
<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.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.
app/layout.tsx
7
Render the widget on a page
Pages stay Server Components. Only the widget itself is a client component.When the user navigates with
app/quests/page.tsx
<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
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
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.Use
app/api/claimr/token/route.ts
claimr/ClaimrAuthProvider.tsx
ClaimrAuthProvider in the root layout in place of ClaimrProvider.4
Log out of Claimr when the user logs out
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 theloadClaimrconfig and render theClaimrWalletBridgecomponent 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
- Run
npm run devand open the page withClaimrWidget. The campaign renders, and the terminal shows nowindow is not definederrors. - In the browser console,
window.claimr.is_claimr_readyreturnstrue. - Navigate away with a
<Link>and back. The widget comes back, anddocument.querySelectorAll('#claimr-script').lengthis still1. - Run
npm run build. The build succeeds, andCLAIMR_API_TOKENdoes not appear in.next/static. - If you use user tokens, sign in to your app and confirm the widget shows the same user without a second sign-in.