Skip to main content

Connect Wallet

Connecting a wallet is the first step in any KEA Wallet integration. When your app calls connect(), the SDK opens a modal overlay where the user authenticates with their passkey and selects which account(s) to share with your dApp. No browser extension is required — everything runs inside a secure iframe.

This guide covers three integration approaches: a drop-in React component, React hooks for custom UI, and the vanilla JavaScript SDK.

Prerequisites

How Connection Works

  1. Your app calls connect() (or the user clicks <KeaConnectButton />)
  2. The SDK creates a hidden iframe pointing to the wallet's embedded page
  3. A full-screen modal overlay appears over your app
  4. The user authenticates via passkey inside the modal
  5. The user selects which account(s) to authorize for your dApp
  6. The modal closes and your app receives a ConnectResult with the authorized accounts
  7. The SDK emits a connect event and transitions to the connected state
tip

connect() auto-initializes the SDK. You can call initialize() beforehand to pre-load the iframe for a faster first connection.

React Integration

For React apps, KEA Wallet provides a context provider, hooks, and pre-built UI components. Choose the approach that matches your UI requirements.

Set Up the Provider

All React approaches require wrapping your app with KeaProvider:

import { KeaProvider } from '@kea-wallet/react-sdk';

const config = {
rpcUrl: 'https://grpc-web.alphanet.thruput.org',
autoConnect: true,
};

function App() {
return (
<KeaProvider config={config}>
<YourApp />
</KeaProvider>
);
}

See BrowserSDKConfig for all available config options.

Option A: Pre-built Connect Button

The fastest path — a single component that handles all visual states automatically:

import { KeaConnectButton } from '@kea-wallet/react-ui';

function Toolbar() {
return <KeaConnectButton />;
}

The button handles four states:

StateButton textBehavior
Disconnected"Connect Wallet"Click opens the wallet modal
Connecting"Connecting..."Disabled while modal is open
Reconnecting"Reconnecting..."Disabled during auto-reconnect
ConnectedTruncated address (e.g. taJO...yrKk)Click to disconnect
warning

<KeaConnectButton /> uses dark-themed inline styles that are not customizable via CSS. For branded or custom-styled buttons, use Option B below.

See KeaConnectButton API reference.

Option B: Custom UI with Hooks

For full control over styling and behavior, use the useWallet() hook:

import { useWallet } from '@kea-wallet/react-sdk';

function ConnectButton() {
const { connect, disconnect, isConnected, isConnecting, selectedAccount } = useWallet();

const handleConnect = async () => {
try {
await connect({
metadata: {
appName: 'My App',
appUrl: 'https://myapp.com',
imageUrl: 'https://myapp.com/logo.png',
},
});
} catch (err) {
console.error('Connection failed:', err);
}
};

if (isConnected) {
return (
<div>
<p>Connected: {selectedAccount?.address}</p>
<button onClick={() => disconnect()}>Disconnect</button>
</div>
);
}

return (
<button onClick={handleConnect} disabled={isConnecting}>
{isConnecting ? 'Connecting...' : 'Connect Wallet'}
</button>
);
}

Key points:

  • metadata is optional. When omitted, appName and appUrl are auto-derived from window.location. Providing imageUrl is recommended for a polished consent screen.
  • isConnecting is true while the modal is open — always use it to disable the button and show loading feedback.
  • connect() returns a Promise<ConnectResult> — if the user rejects or closes the modal, the promise throws. Use try/catch as shown above, or handle errors via the error event.

See UseWalletReturn and ConnectOptions for all available properties.

Vanilla JavaScript

For non-React apps (or when you need full lifecycle control), use BrowserSDK directly:

import { BrowserSDK } from '@kea-wallet/browser-sdk';

// 1. Create the SDK instance
const sdk = new BrowserSDK({
rpcUrl: 'https://grpc-web.alphanet.thruput.org',
autoConnect: true,
});

// 2. Initialize (pre-loads the iframe for faster connect)
await sdk.initialize();

// 3. Connect on user click
connectButton.addEventListener('click', async () => {
try {
const result = await sdk.connect({
metadata: { appName: 'My App' },
});

const accounts = sdk.getAccounts();
const selected = sdk.getSelectedAccount();
console.log('Connected:', selected.address);
} catch (err) {
console.error('Connection failed:', err);
}
});
  • initialize() is optional — connect() calls it automatically if needed. Calling it early pre-loads the iframe for faster UX.
  • If the user rejects the connection or closes the modal, connect() throws an error.
  • After connecting, use getAccounts() and getSelectedAccount() to access account data.
Cleanup required

When your app unmounts or the page unloads, call sdk.destroy() to tear down the iframe and remove event listeners. Failing to do so may cause memory leaks.

See BrowserSDKConfig for all configuration options.

Session Persistence

When autoConnect is enabled, the SDK automatically restores the wallet session on page reload — no modal is shown:

  1. On connect, the SDK stores a hint in localStorage (kea_wallet_state)
  2. On page reload, it detects the hint and silently queries the wallet iframe to check if the session is still valid
  3. If valid, the SDK transitions to connected state without showing the modal
  4. If the session has expired or storage is blocked, the SDK stays disconnected — no error is thrown
function ConnectButton() {
const { connect, isConnected, isConnecting, isReconnecting } = useWallet();

if (isReconnecting) {
return <span>Restoring session...</span>;
}

if (isConnected) {
return <span>Connected</span>;
}

return (
<button onClick={() => connect()} disabled={isConnecting}>
{isConnecting ? 'Connecting...' : 'Connect Wallet'}
</button>
);
}
tip

Use isReconnecting to show a skeleton or "Restoring session..." placeholder instead of briefly flashing the "Connect Wallet" button on every page load.

Disconnecting

Calling disconnect() ends the wallet session, clears internal state, emits a disconnect event, and updates the localStorage hint so auto-connect will not fire on next reload.

const { disconnect } = useWallet();

<button onClick={() => disconnect()}>Disconnect</button>
note

disconnect() ends the session but keeps the SDK instance alive. Call destroy() only when you are completely done with the SDK (e.g., page unload in a vanilla JS app). In React, KeaProvider handles cleanup automatically on unmount.

UX Best Practices

  • User-initiated click requiredconnect() opens a modal overlay. Browsers may block it if not triggered by a direct user interaction (click/tap). Never call connect() on page load.
  • Always show loading state — Use isConnecting (React) or track your own boolean (vanilla JS) to disable the connect button and show "Connecting..." while the modal is open.
  • Handle reconnection gracefully — When autoConnect is enabled, show a skeleton or neutral state during isReconnecting instead of flashing the connect button.
  • Provide app metadata — While metadata is optional, providing an explicit appName and imageUrl improves the consent screen experience.
  • Handle rejection — The user can close the modal or reject the connection. Wrap connect() in a try/catch or handle the error state. See the Error Handling guide.

What's Next

  • Handle Accounts — Work with multiple accounts and switch the active account
  • Sign Transactions — Build and sign transactions using the wallet
  • SDK Events — Subscribe to connection, disconnection, and account change events
  • Error Handling — Handle user rejection, timeouts, and connection failures