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.
- 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
| Prop | Required | Description |
|---|---|---|
apiKey | Yes | Platform API key (plt_...) |
baseUrl | No | API base (default https://api.1claw.co) |
children | Yes | App tree |
OneclawEmbeddedWallet
| Prop | Default | Description |
|---|---|---|
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 |
onLinkRequired | Auto-redirect | Custom 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
| Feature | User experience |
|---|---|
send | Native + token transfers with step-up auth |
swap | 0x DEX swap UI |
receive | Address + QR per chain |
buy | Fiat 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
| Variable | Purpose |
|---|---|
NEXT_PUBLIC_ONECLAW_API_KEY | plt_ key (naming varies by app) |
NEXT_PUBLIC_ONECLAW_BASE_URL | API 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: falseif needed) - OAuth callback routes should run
handleSignInCallbackserver-side or client-side with PKCE verifier from secure storage
Related
- Authentication — OTP, social, passkeys
- Send, swap, receive — programmatic sends
- Getting started — platform setup
- 2-minute quickstart — minimal SDK sample