Skip to main content

React Integration

@1claw/wallet-react provides drop-in React components for embedded wallets. Authenticate with your plt_ Platform API key; the widget handles Email OTP, social login, wallet provisioning, Send/Swap/Receive/Buy, spend policy errors, and session refresh.

Source: github.com/1clawAI/wallet-react (MIT)

For the full prop reference, see also @1claw/wallet-react docs.

Requirements
  • React 18+
  • Pro+ plan and Platform App (plt_ key)
  • Bundler with ESM support (Next.js, Vite, etc.)

Install​

npm install @1claw/wallet-react
# or
pnpm add @1claw/wallet-react

Full widget​

import {
OneclawWalletProvider,
OneclawEmbeddedWallet,
} from "@1claw/wallet-react";

export default function WalletPage() {
return (
<OneclawWalletProvider
apiKey={process.env.NEXT_PUBLIC_ONECLAW_PLATFORM_KEY!}
baseUrl="https://api.1claw.co"
>
<OneclawEmbeddedWallet
chains={["ethereum", "base", "solana"]}
features={{ send: true, swap: true, receive: true, buy: true }}
socialProviders={["google", "apple", "discord"]}
theme="system"
onLogin={(user) => console.log("Logged in", user.user_id)}
onError={(err) => console.error(err)}
/>
</OneclawWalletProvider>
);
}

Component props​

OneclawWalletProvider​

PropRequiredDescription
apiKeyYesPlatform API key (plt_...)
baseUrlNoAPI base (default https://api.1claw.co)
childrenYesApp tree

OneclawEmbeddedWallet​

PropDefaultDescription
features["send","swap","receive","buy"]Visible views
socialProviders["google", "apple", "discord"]"google", "apple", "discord". Email OTP is always available and is not a member of this union — listing "email" is a type error.
chains["ethereum"]Chains to auto-provision on first login
theme"system""light", "dark", "system", or CSS custom properties object
onLinkRequiredAuto-redirectCustom handler when existing 1Claw user must link orgs (409)
onLogin—Callback after successful auth
onError—Error callback

OneclawTreasuryWidget​

Compact balance + quick actions UI. Accepts the same props as OneclawEmbeddedWallet.

Feature toggles​

FeatureUser experience
sendNative + token transfers with step-up auth
swap0x DEX swap UI
receiveAddress + QR per chain
buyFiat on-ramp partner widgets
<OneclawEmbeddedWallet features={{ send: true, receive: true }} />

Omit swap and buy for send-only apps.

Theming​

Built-in modes:

<OneclawEmbeddedWallet theme="dark" />

Or a ThemeConfig object for brand colour, radius, font and raw CSS variables. Note the prefix is --ocw-, and raw variables go inside cssVars:

<OneclawEmbeddedWallet
theme={{
mode: "dark",
brandColor: "#6366f1",
borderRadius: "12px",
fontFamily: "'Inter', sans-serif",
cssVars: {
"--ocw-bg": "#0f0f12",
"--ocw-text": "#fafafa",
},
}}
/>

Properties apply to the widget root element.

Headless: useOneclawWallet()​

Build your own UI while reusing auth and treasury calls:

import { useOneclawWallet } from "@1claw/wallet-react";

function CustomWallet() {
const {
wallets,
balances,
send,
swap,
sendWithPasskey,
refresh,
sendEmailOtp,
verifyEmailOtp,
socialLogin,
createOnrampSession,
} = useOneclawWallet();

return (
<div>
{wallets.map((w) => (
<p key={w.chain}>
{w.chain}: {w.address} — {balances[w.chain]?.native ?? "…"}
</p>
))}
<button onClick={() => refresh()}>Refresh</button>
</div>
);
}

Must render inside OneclawWalletProvider.

Who is signed in​

currentUser is populated on login and rehydrated from the server when the provider mounts, so it survives a reload and a change of page. You do not need to cache the onLogin payload yourself.

const { currentUser, getCurrentUser } = useOneclawWallet();

// currentUser: { userId, email, walletAddress?, isNewUser, isPasswordless } | null
if (!currentUser) return <SignIn />;
return <p>Signed in as {currentUser.email}</p>;

getCurrentUser() re-asks the server and returns null once the session is no longer valid — useful before a sensitive action, where a cached copy would happily report someone who has since been signed out.

Showing spend limits before a send​

const { getEffectiveSpendPolicy } = useOneclawWallet();
const policy = await getEffectiveSpendPolicy();
// { max_value_per_tx_eth?, daily_limit_eth?, allowed_chains?, source, ... }

This is the same data as client.treasuryWallets.getEffectiveSpendPolicy() in @1claw/sdk; it is on the hook too, because the widget flow does not otherwise hold a raw SDK client.

Calling a contract​

send takes an optional data field — hex calldata, sent as the transaction's input. That covers arbitrary contract calls without needing a Safe:

await send({
chain: "ethereum",
to: "0xContractAddress",
valueWei: "0",
data: "0xa9059cbb...", // e.g. an ERC-20 transfer, ABI-encoded by you
});

Encode the calldata yourself (viem's encodeFunctionData, ethers' Interface). The same guardrails apply as to a plain send: recipient allowlists, per-transaction and daily caps, and sanctions screening, which decodes ERC-20 transfer recipients out of data rather than only reading to.

Sign in with 1Claw button​

OAuth without the full wallet chrome:

import { SignInWith1Claw, handleSignInCallback } from "@1claw/wallet-react";

// Login page
<SignInWith1Claw
clientId="my-wallet-app"
redirectUri="https://yourapp.com/callback"
scopes={["openid", "profile", "email"]}
/>

// Callback route
const tokens = await handleSignInCallback({
code: searchParams.get("code")!,
state: searchParams.get("state")!,
clientId: "my-wallet-app",
redirectUri: "https://yourapp.com/callback",
});

Example app: sign-in-with-1claw.

Cross-org linking​

When verifyEmailOtp or social login returns 409, pass onLinkRequired:

<OneclawEmbeddedWallet
onLinkRequired={(authorizeUrl, appSlug) => {
// Custom modal, or:
window.location.href = authorizeUrl;
}}
/>

UX built-ins (v0.5.0+)​

  • Toast notifications — submit, confirm, fail, policy violation
  • Skeleton loading — wallets and balances while provisioning
  • Session expiry — redirects to login instead of blank state

Environment variables​

VariablePurpose
NEXT_PUBLIC_ONECLAW_API_KEYplt_ key (naming varies by app)
NEXT_PUBLIC_ONECLAW_BASE_URLAPI URL override

Never expose human 1ck_ keys in frontend bundles — use plt_ only.

Next.js notes​

  • Mark wallet pages "use client"
  • Load widget only on client if using SSR (dynamic import with ssr: false if needed)
  • OAuth callback routes should run handleSignInCallback server-side or client-side with PKCE verifier from secure storage