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.
- GitHub: https://github.com/solana-foundation/connectorkit
- NPM:
npm i @solana/connector
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
- React:
- Use
@solana/connectoras a convenience re-export (it re-exports both./reactand./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.
// app/providers.tsx
'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, // reads NEXT_PUBLIC_WALLETCONNECT_PROJECT_ID
}),
[],
);
const mobile = useMemo(
() =>
getDefaultMobileConfig({
appName: 'My App',
appUrl: getOrigin(),
}),
[],
);
return (
<AppProvider connectorConfig={connectorConfig} mobile={mobile}>
{children}
</AppProvider>
);
}
// app/layout.tsx
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, // optional; reads NEXT_PUBLIC_WALLETCONNECT_PROJECT_ID
});
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'
// Default rendering
<WalletListElement />
<AccountElement showAvatar showCopy />
<BalanceElement showTokens />
// Custom via render prop
<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',
// getAuthHeaders: () => ({ Authorization: `Bearer ${token}` }),
});
const config = getDefaultConfig({
appName: 'My App',
additionalWallets: [remoteWallet],
});
- Server: implement the Next.js route handler to actually sign.
// app/api/connector-signer/route.ts
import { createRemoteSignerRouteHandlers } from '@solana/connector/server';
const { GET, POST } = createRemoteSignerRouteHandlers({
provider: { type: 'custom', signer: myRemoteSigner }, // implements RemoteSigner (see references/remote-signer.md)
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 (seepackages/connector/README.md). - Token logo privacy: set
imageProxyif you render token images to avoid leaking user IPs to arbitrary token metadata hosts (seepackages/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 => {
/* react to changes */
});
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; // string | null
compat.connected; // boolean
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, acceptsconfigandmobileprops.<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