For dApps & ServicesLedger Wallet ProviderBuildGet Started

Get started with Ledger Wallet Provider

This quick-start shows how to add the Ledger Wallet Provider to a web application and request accounts through the injected EIP-6963 provider.

Partner Program: Ledger Wallet Provider requires enrollment in Ledger’s partner program to obtain API keys. Contact our team to discuss integration.

Install the SDK

npm install @ledgerhq/ledger-wallet-provider

Optionally install with yarn or pnpm if that aligns with your tooling.

Initialize the provider

import { initializeLedgerProvider } from '@ledgerhq/ledger-wallet-provider'
import '@ledgerhq/ledger-wallet-provider/styles.css'
 
// Initialize the Ledger provider
const cleanup = initializeLedgerProvider({
  devConfig: {
    stub: {
      base: false,              // Enable base stub mode for development
      account: false,           // Enable account stubbing
      device: false,            // Enable device stubbing
      web3Provider: false,      // Enable Web3 provider stubbing
      dAppConfig: false,        // Enable dApp config stubbing
    },
  },
  target: document.body,        // Optional: specify where to mount the UI
  dAppIdentifier: 'my-dapp',   // Your dApp identifier
  apiKey: 'your-api-key',      // Your Ledger API key
  loggerLevel: 'info',         // Log level: 'debug', 'info', 'warn', 'error'
  dmkConfig: undefined,        // Device Management Kit configuration (optional)
})

See the Configuration page for detailed information about all available options.

Discover the provider (EIP-6963)

window.dispatchEvent(new Event('eip6963:requestProvider'))

Listen for provider announcements:

window.addEventListener('eip6963:announceProvider', (event) => {
  const detail = event as CustomEvent
  console.log('Ledger provider discovered', detail.detail)
})

Request accounts

const accounts = await provider.request({
  method: 'eth_requestAccounts',
  params: [],
})

Once users connect their device through the Ledger Wallet Provider flow, you will receive accounts and can start signing transactions or messages.

Complete React example

Here’s a full working example that demonstrates provider discovery, account connection, and transaction signing:

import { useEffect, useState, useCallback } from 'react'
import type { EIP6963ProviderDetail } from '@ledgerhq/ledger-wallet-provider'
 
function useProviders() {
  const [providers, setProviders] = useState<EIP6963ProviderDetail[]>([])
  const [selectedProvider, setSelectedProvider] = useState<EIP6963ProviderDetail | null>(null)
 
  const handleAnnounceProvider = useCallback((e: CustomEvent<EIP6963ProviderDetail>) => {
    setProviders(prev => {
      const found = prev.find(p => p.info.uuid === e.detail.info.uuid)
      if (found) return prev
      return [...prev, e.detail]
    })
  }, [])
 
  useEffect(() => {
    // Dynamic import is required because the library uses browser APIs
    // and won't work with Server-Side Rendering (SSR)
    const initializeProvider = async () => {
      await import('@ledgerhq/ledger-wallet-provider/styles.css') // Import styles dynamically
      const { initializeLedgerProvider } = await import('@ledgerhq/ledger-wallet-provider')
 
      const cleanup = initializeLedgerProvider({
        devConfig: {
          stub: {
            base: false,              // Set to true for development
            account: false,           // Enable account stubbing
            device: false,            // Enable device stubbing
            web3Provider: false,      // Enable Web3 provider stubbing
            dAppConfig: false,        // Enable dApp config stubbing
          },
        },
        dAppIdentifier: 'my-dapp',
        apiKey: 'your-api-key',
        loggerLevel: 'info',         // Log level configuration
        dmkConfig: undefined,       // Device Management Kit config (optional)
      })
 
      window.addEventListener('eip6963:announceProvider', handleAnnounceProvider)
 
      return cleanup
    }
 
    let cleanup: (() => void) | undefined
 
    initializeProvider().then(cleanupFn => {
      cleanup = cleanupFn
    })
 
    return () => {
      cleanup?.()
      window.removeEventListener('eip6963:announceProvider', handleAnnounceProvider)
    }
  }, [handleAnnounceProvider])
 
  return { providers, selectedProvider, setSelectedProvider }
}
 
function App() {
  const { providers, selectedProvider, setSelectedProvider } = useProviders()
  const [account, setAccount] = useState<string | null>(null)
 
  const connectWallet = async () => {
    if (!selectedProvider) return
 
    try {
      const accounts = await selectedProvider.provider.request({
        method: 'eth_requestAccounts',
        params: []
      })
      setAccount(accounts[0])
    } catch (error) {
      console.error('Failed to connect:', error)
    }
  }
 
  const signTransaction = async (transaction: any) => {
    if (!selectedProvider) return
 
    try {
      const result = await selectedProvider.provider.request({
        method: 'eth_signTransaction',
        params: [transaction]
      })
      return result
    } catch (error) {
      console.error('Failed to sign transaction:', error)
    }
  }
 
  return (
    <div>
      {providers.map(provider => (
        <button
          key={provider.info.uuid}
          onClick={() => setSelectedProvider(provider)}
        >
          Connect {provider.info.name}
        </button>
      ))}
 
      {selectedProvider && (
        <button onClick={connectWallet}>
          Request Accounts
        </button>
      )}
 
      {account && <p>Connected: {account}</p>}
    </div>
  )
}

Why dynamic imports are necessary:

  • The library uses Web APIs (window, document, CustomEvent) that don’t exist in Node.js
  • Direct imports will cause build errors in SSR frameworks (Next.js, Nuxt, SvelteKit, etc.)
  • Dynamic imports ensure the code only runs in the browser environment

Next steps

Customize your integration

Explore Configuration options to set up chain support, connection methods, and behavior.

Review the API

Deep-dive into provider methods, events, and TypeScript types in the API Reference.

Ledger
Copyright © Ledger SAS. All rights reserved. Ledger, Ledger Stax, Ledger Flex, Ledger Nano, Ledger Nano S, Ledger OS, Ledger Wallet, [LEDGER] (logo), [L] (logo) are trademarks owned by Ledger SAS.