| name | connectorkit |
| description | Solana wallet connection library with headless core and React UI components. Use when working with @solana/connector, ConnectorKit, Solana wallet connection, wallet standard integration, ConnectorClient, wallet elements, render props, useWallet, useConnectWallet, useBalance, useTransactionSigner, WalletListElement, AccountElement, BalanceElement, TransactionHistoryElement, migrating from @solana/wallet-adapter, remote signer, server-side signing, Fireblocks Solana, Privy Solana, or mobile wallet adapter integration.
|
ConnectorKit
@solana/connector — Headless wallet connection library for Solana.
Entry Points
| Import | Purpose |
|---|
@solana/connector | Full library (React + headless) |
@solana/connector/headless | Framework-agnostic core (Vue, Svelte, vanilla JS) |
@solana/connector/react | React hooks + element components |
@solana/connector/compat | Bridge for existing @solana/wallet-adapter code |
@solana/connector/remote | Browser-side remote wallet adapter |
@solana/connector/server | Server-side route handlers for remote signing |
React hooks and elements are only available via @solana/connector or @solana/connector/react. For non-React frameworks, use ConnectorClient from @solana/connector/headless and subscribe to state changes directly.
Recommended Imports
- Prefer explicit entry points for clarity:
- React:
@solana/connector/react
- Headless/core:
@solana/connector/headless
- Use
@solana/connector as a convenience re-export (it re-exports both ./react and ./headless).
Next.js (App Router) Setup
Put providers in a single client boundary (typically app/providers.tsx) and keep the rest of your app as Server Components.
'use client';
import type { ReactNode } from 'react';
import { useMemo } from 'react';
import { AppProvider } from '@solana/connector/react';
import { getDefaultConfig, getDefaultMobileConfig } from '@solana/connector/headless';
function getOrigin() {
if (typeof window === 'undefined') return 'http://localhost:3000';
return window.location.origin;
}
export function Providers({ children }: { children: ReactNode }) {
const connectorConfig = useMemo(
() =>
getDefaultConfig({
appName: 'My App',
appUrl: getOrigin(),
network: 'devnet',
autoConnect: true,
enableMobile: true,
walletConnect: true,
}),
[],
);
const mobile = useMemo(
() =>
getDefaultMobileConfig({
appName: 'My App',
appUrl: getOrigin(),
}),
[],
);
return (
<AppProvider connectorConfig={connectorConfig} mobile={mobile}>
{children}
</AppProvider>
);
}
import type { ReactNode } from 'react';
import { Providers } from './providers';
export default function RootLayout({ children }: { children: ReactNode }) {
return (
<html lang="en">
<body>
<Providers>{children}</Providers>
</body>
</html>
);
}
Quick Start (React)
import { AppProvider } from '@solana/connector/react';
import { getDefaultConfig } from '@solana/connector/headless';
const config = getDefaultConfig({
appName: 'My App',
network: 'devnet',
autoConnect: true,
enableMobile: true,
walletConnect: true,
});
function App() {
return (
<AppProvider connectorConfig={config}>
<WalletUI />
</AppProvider>
);
}
Common Patterns
Connect a Wallet
import { useConnectWallet, useWalletConnectors, useWallet } from '@solana/connector/react';
function ConnectButton() {
const { status, account } = useWallet();
const { connect, isConnecting } = useConnectWallet();
const connectors = useWalletConnectors();
if (status === 'connected') return <div>{account}</div>;
return connectors.map(w => (
<button key={w.id} onClick={() => connect(w.id)} disabled={isConnecting}>
{w.name}
</button>
));
}
Sign & Send a Transaction
import { useTransactionSigner } from '@solana/connector/react';
const { signer, ready } = useTransactionSigner();
const sig = await signer.signAndSendTransaction(transaction);
For @solana/kit compatible signer: useKitTransactionSigner().
Elements with Render Props
All elements accept a render prop for full UI customization:
import { WalletListElement, AccountElement, BalanceElement } from '@solana/connector/react'
<WalletListElement />
<AccountElement showAvatar showCopy />
<BalanceElement showTokens />
<AccountElement render={({ address, formatted, copy, copied }) => (
<div onClick={copy}>{copied ? 'Copied!' : formatted}</div>
)} />
<WalletListElement render={({ wallets, connectById, connecting }) => (
wallets.map(w => (
<button key={w.id} onClick={() => connectById(w.id)}>{w.name}</button>
))
)} />
All elements: WalletListElement, AccountElement, ClusterElement, DisconnectElement, BalanceElement, TransactionHistoryElement, TokenListElement, SkeletonShine
Switch Networks
import { useCluster } from '@solana/connector/react';
const { cluster, clusters, setCluster, isMainnet, isDevnet } = useCluster();
await setCluster('devnet');
Wallet Filtering & Ordering
Improve UX for users with lots of installed wallets by filtering and/or featuring wallets at the config level:
import { getDefaultConfig } from '@solana/connector/headless';
const config = getDefaultConfig({
appName: 'My App',
wallets: {
allowList: ['Phantom', 'Solflare', 'Backpack'],
denyList: ['MetaMask'],
featured: ['Phantom', 'Solflare'],
},
});
WalletConnect (QR / Deep Link)
- Install the WalletConnect peer dependency:
npm i @walletconnect/universal-provider
- Set
NEXT_PUBLIC_WALLETCONNECT_PROJECT_ID=...
- Enable in config:
walletConnect: true
When a pairing URI is available, render a QR/deep link UI (e.g. a dialog). The provider exposes walletConnectUri and clearWalletConnectUri.
'use client';
import { useConnector } from '@solana/connector/react';
export function WalletConnectQrModal() {
const { walletConnectUri, clearWalletConnectUri } = useConnector();
if (!walletConnectUri) return null;
return (
<div>
<div>WalletConnect URI: {walletConnectUri}</div>
<button onClick={clearWalletConnectUri}>Close</button>
</div>
);
}
For a full QR example, see packages/connector/README.md (WalletConnect section).
Remote Signer (Server-backed Signing)
Remote signing is a two-part setup:
- Browser: create a Wallet Standard wallet that delegates signing to your API.
import { createRemoteSignerWallet } from '@solana/connector/remote';
import { getDefaultConfig } from '@solana/connector/headless';
const remoteWallet = createRemoteSignerWallet({
endpoint: '/api/connector-signer',
name: 'Treasury',
});
const config = getDefaultConfig({
appName: 'My App',
additionalWallets: [remoteWallet],
});
- Server: implement the Next.js route handler to actually sign.
import { createRemoteSignerRouteHandlers } from '@solana/connector/server';
const { GET, POST } = createRemoteSignerRouteHandlers({
provider: { type: 'custom', signer: myRemoteSigner },
authorize: async request => true,
policy: {
validateTransaction: async bytes => true,
validateMessage: async bytes => true,
},
rpc: { endpoint: process.env.RPC_URL },
chains: ['solana:mainnet'],
name: 'Treasury',
});
export { GET, POST };
Details (provider configs + protocol types + security) live in references/remote-signer.md.
Devtools (Development Only)
ConnectorKit also ships devtools (@solana/connector-debugger) that can be dynamically mounted in development.
'use client';
import { useEffect } from 'react';
export function DevtoolsLoader() {
useEffect(() => {
if (process.env.NODE_ENV !== 'development') return;
let devtools: { mount: (el: HTMLElement) => void; unmount: () => void } | undefined;
let container: HTMLDivElement | undefined;
import('@solana/connector-debugger').then(({ ConnectorDevtools }) => {
container = document.createElement('div');
document.body.appendChild(container);
devtools = new ConnectorDevtools({ config: { position: 'bottom-right', theme: 'dark' } });
devtools.mount(container);
});
return () => {
devtools?.unmount();
container?.remove();
};
}, []);
return null;
}
Security & Production Checklist
- RPC API keys: don’t expose paid RPC URLs as
NEXT_PUBLIC_*; use a Next.js RPC proxy route and point your cluster URL at the proxy (see packages/connector/README.md).
- Token logo privacy: set
imageProxy if you render token images to avoid leaking user IPs to arbitrary token metadata hosts (see packages/connector/README.md).
- CoinGecko rate limits: if you use token prices heavily, configure
coingecko.apiKey.
- Remote signer: always implement
authorize + policy.validateTransaction, use HTTPS, and rate limit the signer endpoint.
Headless (Non-React)
import { ConnectorClient } from '@solana/connector/headless';
const client = new ConnectorClient({
autoConnect: true,
cluster: { initialCluster: 'devnet' },
});
client.subscribe(state => {
});
await client.connectWallet('wallet-standard:phantom');
const snapshot = client.getSnapshot();
Wallet Adapter Compat Bridge
import { useWalletAdapterCompat } from '@solana/connector/compat';
const compat = useWalletAdapterCompat(signer, disconnect);
compat.publicKey;
compat.connected;
compat.signTransaction(tx);
compat.sendTransaction(tx, connection);
Key Concepts
Connector IDs
Wallets use stable branded WalletConnectorId strings:
'wallet-standard:phantom', 'wallet-standard:solflare', etc.
'walletconnect'
'mwa:phantom' (Mobile Wallet Adapter on iOS/Android)
Wallet Status State Machine
useWallet() returns a discriminated union:
status: 'disconnected' | 'connecting' | 'connected' | 'error';
When status === 'connected', session contains accounts, selectedAccount, selectAccount().
Type guards: isDisconnected(), isConnecting(), isConnected(), isStatusError()
Providers
<AppProvider> — Convenience wrapper (recommended). Auto-wires ConnectorProvider, WalletConnect, error boundaries.
<ConnectorProvider> — Lower-level, accepts config and mobile props.
<ConnectorErrorBoundary> — Catches errors in connector tree.
Reference Files
- Hooks & Elements API — All hooks with return types, all elements with props
- Connector Package README — WalletConnect QR, RPC proxy pattern,
imageProxy, CoinGecko config, headless examples
- Next.js Example Providers — End-to-end Next.js provider wiring (clusters, WalletConnect, remote signer, devtools)
- Remote & Server Signing — Remote wallet adapter, server route handlers, Fireblocks/Privy/custom provider setup
- Migration Guide — Compat bridge details, wallet-adapter to connector migration steps