How Wallet Detection Works

FingerprintIQ detects installed Web3 wallet extensions without requiring a wallet connection. Detection is entirely passive — there is no popup, no permission request, and no signature prompt. The user is never aware that wallet detection occurred.

Wallet detection works by checking for known JavaScript objects that wallet extensions inject into the window scope. FingerprintIQ never reads wallet addresses, private keys, or any account data — it only detects which wallet software is installed.

Detection uses two complementary methods:

  1. EIP-6963 provider discovery — The modern standard where wallets announce themselves via a eip6963:announceProvider event. Works with all compliant wallets.
  2. Legacy window object detection — Checks known wallet-specific properties (e.g., window.ethereum.isMetaMask) for wallets that predate EIP-6963.

Supported Wallets

WalletChainDetection Method
MetaMaskEVMwindow.ethereum.isMetaMask
PhantomSolanawindow.phantom.solana
CoinbaseEVMwindow.ethereum.isCoinbaseWallet
RabbyEVMwindow.ethereum.isRabby
RainbowEVMwindow.ethereum.isRainbow
Brave WalletEVMwindow.ethereum.isBraveWallet
ZerionEVMwindow.ethereum.isZerion
ExodusEVMwindow.ethereum.isExodus
SolflareSolanawindow.solflare
BackpackSolanawindow.backpack
KeplrCosmoswindow.keplr
UniSatBitcoinwindow.unisat
OKXMulti-chainwindow.okxwallet
XDEFIMulti-chainwindow.xfi
TronLinkTronwindow.tronWeb

Plus EIP-6963 discovery for any compliant wallet not listed above.

Response Format

json
{ "wallets": { "detected": ["MetaMask", "Phantom"], "count": 2, "evmProviders": ["MetaMask"], "solanaProviders": ["Phantom"], "multipleWallets": true, "versions": { "MetaMask": "11.16.0" } }}

Wallet version information (versions) is available for wallets that expose it via their provider object. Not all wallets expose version numbers.

Detection tells you which wallets a visitor has installed. Auto-link goes one step further: when the user actually connects a wallet — through your dapp's existing connect button, Wagmi, RainbowKit, web3modal, or any other connector — FingerprintIQ notices the connection passively and ships the address to your project so it can be linked to the visitor and enriched on-chain.

You don't have to call any FingerprintIQ method for this to happen. The SDK attaches passive listeners (accountsChanged, EIP-6963, Solana connect) the moment you new FingerprintIQ(...). When an address shows up:

  1. The SDK debounces for ~300ms (in case more accounts arrive)
  2. It POSTs the address to /v1/identify/wallet-link with the visitorId from your most recent identify() call
  3. The address is linked to the visitor in visitor_wallets, the sybil score updates, and async enrichment fetches ENS, portfolio, wallet age, and labels
javascript
const fiq = new FingerprintIQ({ apiKey });const result = await fiq.identify(); // visitorId is now known// ...later, your dapp shows its connect button.// User clicks → your wagmi/web3modal flow runs → MetaMask popup appears.// You don't need to call anything on `fiq` — the address is already on its// way to /v1/identify/wallet-link, the visitor profile is being enriched,// and any webhook you have configured for `wallet.identified` will fire.

Auto-link only runs after the first identify() returns. Addresses observed before that are buffered locally and shipped on the first identify call. If the wallet-link request fails (offline, etc.), the address stays in the local buffer and rides along on the next identify() call.

You can also subscribe to the same stream yourself for client-side personalization:

javascript
import { onWalletAddress } from "@fingerprintiq/js";onWalletAddress((address, connection) => { // connection.method = "pre-connected" | "listener" | "manual" // connection.chain = "evm" | "solana" console.log("New wallet linked:", address, connection.provider);});

Sybil Detection Use Cases

Prevent users from claiming multiple airdrop allocations by linking different wallet addresses to the same device fingerprint.

javascript
const result = await fiq.identify();const walletCount = result.web3?.walletsDetected.length ?? 0;// Same device claiming multiple airdrop walletsif (result.visitCount > 3 && walletCount > 1) { // This device has visited multiple times with multiple wallets // Flag as potential Sybil before allowing airdrop claim await flagSybilRisk(result.visitorId); showChallenge();}

Always verify the visitorId server-side before making airdrop decisions. Client-side checks alone can be bypassed.