Crossmint React SDK
React SDK for integrating Crossmint Wallets into your application. Provides providers, hooks, and built-in UI for wallet creation, signing, OTP verification, and passkey flows.
Prerequisites
Get a client API key from the Crossmint developer console. Ensure your key has the Wallet API scopes enabled, including wallets.fund for stagingFund.
Installation
npm install @crossmint/client-sdk-react-ui
# or
pnpm add @crossmint/client-sdk-react-ui
# or
yarn add @crossmint/client-sdk-react-ui
Quick Start
1. Setup Providers
With Crossmint Auth (default in staging)
"use client";
import {
CrossmintProvider,
CrossmintAuthProvider,
CrossmintWalletProvider,
} from "@crossmint/client-sdk-react-ui";
export default function App({ children }) {
return (
<CrossmintProvider apiKey={process.env.NEXT_PUBLIC_CROSSMINT_API_KEY}>
<CrossmintAuthProvider>
<CrossmintWalletProvider
createOnLogin={{
chain: "base-sepolia",
recoveryMethods: [{ type: "email" }],
}}
>
{children}
</CrossmintWalletProvider>
</CrossmintAuthProvider>
</CrossmintProvider>
);
}
Bring Your Own Authentication
Use this when your app already has an auth provider, and in production: connect your provider and configure JWT Authentication in the Crossmint Console (see Move to Production). Then skip CrossmintAuthProvider and pass your provider's JWT to the wallets SDK. See the Custom Auth Guide for full details.
"use client";
import {
CrossmintProvider,
CrossmintWalletProvider,
} from "@crossmint/client-sdk-react-ui";
export default function App({ children }) {
return (
<CrossmintProvider apiKey={process.env.NEXT_PUBLIC_CROSSMINT_API_KEY}>
<CrossmintWalletProvider
createOnLogin={{
chain: "base-sepolia",
recoveryMethods: [
{
type: "email",
email: "[email protected]",
},
],
}}
>
{children}
</CrossmintWalletProvider>
</CrossmintProvider>
);
}
2. Use Wallets
import { useWallet } from "@crossmint/client-sdk-react-ui";
function WalletActions() {
const { wallet, status } = useWallet();
if (status === "in-progress") return <p>Loading wallet...</p>;
if (!wallet) return <p>No wallet</p>;
// Staging only: mints USDXM, Crossmint's test stablecoin, into the wallet
const handleFund = async () => {
await wallet.stagingFund(10);
};
const handleSend = async () => {
const tx = await wallet.send("0xRecipient", "usdxm", "10");
console.log("Transaction:", tx.explorerLink);
};
return (
<div>
<p>Wallet: {wallet.address}</p>
<button onClick={handleFund}>Get 10 USDXM</button>
<button onClick={handleSend}>Send 10 USDXM</button>
</div>
);
}
Providers
| Provider | Purpose |
|---|---|
CrossmintProvider | Root provider. Required for all Crossmint features. |
CrossmintAuthProvider | Authentication (email OTP, Google, Twitter/X). Optional if using your own auth. |
CrossmintWalletProvider | Wallet creation, device signer management, and built-in OTP/passkey UI. |
createOnLogin Configuration
When createOnLogin is set on CrossmintWalletProvider, a wallet is automatically created when the user logs in:
<CrossmintWalletProvider
createOnLogin={{
chain: "base-sepolia", // required — the blockchain
recoveryMethods: [{ type: "email" }], // required — recovery method config
signers: [{ type: "device" }], // optional — defaults to device signer
}}
>
recoveryMethods accepts a list of methods on every chain, each able to recover the wallet on its own:
<CrossmintWalletProvider
createOnLogin={{
chain: "solana",
recoveryMethods: [{ type: "email" }, { type: "external-wallet", address: "9WzD..." }],
}}
>
Hooks
useWallet()
Returns the wallet instance and management functions:
const {
wallet, // Wallet | undefined
status, // "not-loaded" | "in-progress" | "loaded" | "error"
getWallet, // (props: { chain, alias? }) => Promise<Wallet | undefined>
createWallet, // (props: ClientSideWalletCreateArgs) => Promise<Wallet | undefined>
createDeviceSigner, // () => Promise<DeviceSignerDescriptor> | undefined
createPasskeySigner, // (name: string) => Promise<RegisterSignerPasskeyParams>
} = useWallet();
useWalletOtpSigner()
For custom OTP UI when using email/phone recovery methods:
const { needsAuth, sendOtp, verifyOtp, reject } = useWalletOtpSigner();
useAuth()
Authentication state and login methods:
const { login, logout, user, status } = useAuth();
Components
ExportPrivateKeyButton
Renders a button to export the wallet's private key via TEE. Only renders for email/phone signers.
import { ExportPrivateKeyButton } from "@crossmint/client-sdk-react-ui";
<ExportPrivateKeyButton appearance={{ borderRadius: "12px" }} />
React Native
For React Native apps, see @crossmint/client-sdk-react-native-ui.
Wallets SDK
The wallet object returned by useWallet() is a Wallet instance. For wallet method documentation (send, balances, sign, etc.), see the @crossmint/wallets-sdk README.
Documentation
SDK Reference Docs Generation
Source JSDoc -> TypeDoc -> api.json -+
+-> generate-reference.mjs -> MDX pages (docs/<product>/)
examples.json -+
Run with pnpm generate:docs or node scripts/generate-reference.mjs --product wallets.
License
Apache-2.0
Protected buyer fields (in development)
Render each protected UC field independently; an HTML form and Crossmint auth provider
are not required. The provider supplies the browser client key; jwt may come from
external authentication.
const codeRef = useRef<CrossmintProtectedInputRef>(null);
<CrossmintProvider apiKey={clientApiKey}>
<CrossmintProtectedInput ref={codeRef} field={codeField} jwt={buyerJwt} />
</CrossmintProvider>
const result = await codeRef.current.collect();
if (result.status === "collected") {
// Combine with ordinary answers in the application's complete UC response.
answers[codeField.key] = result.input;
} else {
showError(result.message);
}
Collection returns collected, invalid, unavailable or superseded. The developer
owns submission and error rendering. Authentication changes and frame reloads invalidate
pending host results. Only reference/outcome metadata crosses back from the hosted iframe.
Authentication crosses the verified window channel, rather than the iframe URL.
Supported protected inputs are single-line text (visible or masked), number and integer. All use a nested Basis Theory TextElement; tokenization never reads plaintext in Crossmint browser code. Codes and identifiers use text to preserve exact spelling. Unchanged references are cached until expiry; edits, clear, auth or descriptor changes invalidate collection. Disabled controls may still be collected while submission is locked.
This replaces the password-only merchantUrl/onCreated interface. The matching hosted
iframe and per-field collection are implemented locally. SDK publication, Reactor
deployment and composed provider/browser qualification remain release gates. Track AGENT-473.