> ## Documentation Index
> Fetch the complete documentation index at: https://docs.fingerprintiq.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Web3 Signals

Passive wallet extension detection for Sybil resistance.

## 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

| Wallet | Chain | Detection Method |
|--------|-------|-----------------|
| MetaMask | EVM | `window.ethereum.isMetaMask` |
| Phantom | Solana | `window.phantom.solana` |
| Coinbase | EVM | `window.ethereum.isCoinbaseWallet` |
| Rabby | EVM | `window.ethereum.isRabby` |
| Rainbow | EVM | `window.ethereum.isRainbow` |
| Brave Wallet | EVM | `window.ethereum.isBraveWallet` |
| Zerion | EVM | `window.ethereum.isZerion` |
| Exodus | EVM | `window.ethereum.isExodus` |
| Solflare | Solana | `window.solflare` |
| Backpack | Solana | `window.backpack` |
| Keplr | Cosmos | `window.keplr` |
| UniSat | Bitcoin | `window.unisat` |
| OKX | Multi-chain | `window.okxwallet` |
| XDEFI | Multi-chain | `window.xfi` |
| TronLink | Tron | `window.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.

## Connected Wallet Auto-Link

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

**Airdrop Protection**

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 wallets
    if (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.
  **Governance Voting**

Enforce one-device-one-vote to prevent governance manipulation by users running multiple wallet identities from a single machine.

    ```javascript
    const result = await fiq.identify();

    // Check if this device has already voted
    const hasVoted = await checkVoteStatus(result.visitorId);

    if (hasVoted) {
      showMessage("This device has already cast a vote in this proposal.");
      return;
    }

    // Record the vote linked to this device fingerprint
    await recordVote(result.visitorId, selectedOption);
    ```
  **NFT Minting Limits**

Enforce per-device minting limits to prevent bots from minting out collections.

    ```javascript
    const result = await fiq.identify();

    // Block obvious bots before any wallet interaction
    if (result.botProbability > 0.5) {
      showCaptcha();
      return;
    }

    // Enforce device-level mint limit regardless of wallet address
    const mintCount = await getDeviceMintCount(result.visitorId);
    if (mintCount >= MAX_MINTS_PER_DEVICE) {
      showMessage("Mint limit reached for this device.");
      return;
    }
    ```

**Why passive detection matters for Web3**

Traditional Sybil resistance approaches require on-chain proofs (e.g., Gitcoin Passport, Proof of Humanity) that add friction and exclude users who haven't completed those flows. FingerprintIQ's passive approach works instantly for all users without any on-chain interaction, wallet connection, or user awareness — making it complementary to on-chain proofs rather than a replacement.

  The combination of device fingerprinting + wallet detection creates a strong Sybil signal: if the same device has installed 3 wallets and visited your airdrop page 8 times, that's a high-confidence Sybil indicator regardless of whether each wallet has different on-chain history.