Skip to main content
Descriptive alt text
💡 Headless is in early-access at the moment and available to limited users. Contact us to get access.
AppKit Headless allows developers to build a fully customizable “Connect” experience powered by AppKit’s existing features without using the AppKit modal. Headless exposes wallet discovery, rendering WalletConnect QR codes, and social provider flows via simple hooks and utility functions.

Installation

Headless requires AppKit to be configured with the headless flag. See the installation docs before getting started and make sure you’re enabling headless as expected.
createAppKit({
  ...
  features: {
    headless: true
  }
})

useAppKitWallets

The essential hook for accessing all types of wallets and methods to build your custom connection user interface.
const { data, isFetchingWallets, isFetchingWcUri, wcUri, page, count, fetchWallets, connect } =
  useAppKitWallets()

Returns

wallets
WalletItem[]
List of wallets for the initial connect view including WalletConnect wallets and injected wallets together. If the user doesn’t have any injected wallets, it’ll fill the list with the most ranked WalletConnect wallets.
wcWallets
WalletItem[]
List of WalletConnect wallets from Wallet Guide API. Useful to display all available WalletConnect wallets in a separate Search Wallets view.
isFetchingWallets
boolean
Boolean that indicates if WalletConnect wallets are being fetched.
isFetchingWcUri
boolean
Boolean that indicates if a WalletConnect URI is being fetched.
isInitialized
boolean
Boolean that indicates if the AppKit is initialized. It’s useful to render a fallback UI when the AppKit initializes and detects all injected wallets.
wcUri
string | undefined
The current WalletConnect URI for QR code display. This is set when connecting to a WalletConnect wallet. Reset with resetWcUri().
connectingWallet
WalletItem | undefined
The wallet currently being connected to. This is set when a connection is initiated and cleared when it completes or fails. For WalletConnect wallets, resetWcUri() should be called to clear the state.
page
number
The current page number of WalletConnect wallets.
count
number
The total number of available WalletConnect wallets based on the AppKit configurations and given parameters.
fetchWallets
(options?: { page?: number; query?: string; }) => Promise<void>
Function to fetch WalletConnect wallets from the explorer API. Allows you to list, search, and paginate through the wallets.
connect
(wallet: WalletItem, namespace?: ChainNamespace) => Promise<void>
Function to connect to a wallet. For WalletConnect wallets: initiates WC connection and returns the URI with the wcUri state. For injected connectors: triggers the extension/wallet directly.
resetWcUri
() => void
Function to reset the WC URI. Useful to keep the connectingWallet state in sync with the WC URI. Can be called when the QR code is closed.

Examples

Build a Connect UI

Descriptive alt text
The useAppKitWallets hook returns a list of injected and WalletConnect wallets that let you render directly in the connect page. If you configure your AppKit as multi-chain, we suggest rendering a namespace selection component where users should select which namespace to connect when using browser extensions. This could be achieved with the connectors array of the WalletItem. If a user selects a WalletConnect wallet, you can show the QR code to the users and let them scan it with their preferred wallets. To handle the QR flows, you can use the isFetchingWcUri, wcUri, and resetWcUri props from the useAppKitWallets hook.
import React, { useState } from 'react'
import type { WalletItem } from '@reown/appkit'
import type { ChainNamespace } from '@reown/appkit/networks'
import { useAppKitWallets } from '@reown/appkit/react'
import { NamespaceSelectionDialog } from './NamespaceDialog'
import { WalletConnectQRDialog } from './WalletConnectQRDialog'

function ConnectView() {
  const { wallets, connect } = useAppKitWallets()
  const [selectedWallet, setSelectedWallet] = useState<WalletItem | null>(null)

  async function handleConnect(wallet: WalletItem, namespace?: ChainNamespace) {
    await connect(wallet, namespace)
      .then(() => {
        toast({ title: 'Connected', status: 'success' })
      })
      .catch(() => {
        toast({ title: 'Connection declined', status: 'error' })
      })
  }

  return (
    <>
      {wallets.map(wallet => (
        <WalletListItem
          key={wallet.id}
          wallet={wallet}
          onConnect={() => {
            if (wallet.connectors.length > 1) {
              setSelectedWallet(wallet)
            } else {
              handleConnect(wallet, wallet.connectors[0]?.chain)
            }
          }}
        />
      ))}
      <NamespaceSelectionDialog
        wallet={selectedWallet}
        onSelect={handleConnect}
        onClose={() => setSelectedWallet(null)}
      />
      <WalletConnectQRDialog />
    </>
  )
}

Search and Connect to WalletConnect Wallets

Descriptive alt text
WalletConnect supports 500+ wallets. You can let users search for their own wallets to connect to your app.
import React, { useState, useEffect } from 'react'
import { useAppKitWallets } from '@reown/appkit/react'

function AllWalletsView() {
  const { wcWallets, isFetchingWcUri, isFetchingWallets, fetchWallets, connect, page } =
    useAppKitWallets()
  const [inputValue, setInputValue] = useState('')
  const searchQuery = useDebounceValue(inputValue, 500)

  useEffect(() => {
    fetchWallets?.()
  }, [])

  useEffect(() => {
    if (searchQuery.length > 0) {
      fetchWallets?.({ query: searchQuery })
    } else {
      fetchWallets?.()
    }
  }, [searchQuery])

  function handleLoadMore() {
    if (searchQuery.length > 0) {
      fetchWallets?.({ page: page + 1, query: searchQuery })
    } else {
      fetchWallets?.({ page: page + 1 })
    }
  }

  return (
    <>
      <input
        type="text"
        placeholder="Search wallets..."
        value={inputValue}
        onChange={e => setInputValue(e.target.value)}
      />
      {isFetchingWallets && <div>Loading wallets...</div>}
      {wcWallets.map(wallet => {
        return <WalletListItem key={wallet.id} wallet={wallet} onConnect={connect} />
      })}
      <button onClick={handleLoadMore} disabled={isFetchingWallets}>
        Load More
      </button>
    </>
  )
}

Demo