Plaid logo
Docs
ALL DOCS

Wallet Onboard (beta)

  • Introduction to Wallet Onboard
  • Add Wallet Onboard to your app
  • Optimize your wallet
Plaid logo
Docs
Plaid.com
Get API keys
Open nav

Add Wallet Onboard to your app

Connect wallets to retrieve balances, sign messages, send transactions, and more

In this guide, we’ll start from scratch and walk through how to use Wallet Onboard to connect crypto wallets to your app.

Enable Wallet Onboard and retrieve a Link Token

Go to Wallet Onboard Settings in the Plaid Dashboard. After accepting the Terms of Service, you will see a Sandbox Link Token on the page. Use this token to open Wallet Onboard later.

You also need to set your Allowed Domains for Wallet Onboard. Wallet Onboard will not work on any domains except for those you configure. Wallet Onboard will only work on HTTPS domains, except for localhost.

When using a Sandbox Link Token from the dashboard, Wallet Onboard will only open on localhost:* domains. When you are ready to use Wallet Onboard on any domain, you can request production access.

Install Link SDK

Select group for content switcher

Wallet Onboard uses Plaid's Link SDK, which is used by thousands of developers in some of the most popular finance and crypto products in the world.

Include the Plaid Link initialize script on each page of your site. It must always be loaded directly from https://cdn.plaid.com, rather than included in a bundle or hosted yourself.

Copy
1<script src="https://cdn.plaid.com/link/v2/stable/link-initialize.js"></script>

Initialize Wallet Onboard

Opening Wallet Onboard for the first time involves configuring Link, opening Link, and eventually receiving a provider in an onSuccess callback.

Select Language
Copy
1const onSuccess = useCallback<PlaidWeb3OnSuccess>(
2 // provider is an EIP-1193 compatible JavaScript object https://eips.ethereum.org/EIPS/eip-1193
3 // provider can be used by other libraries to request more data
4 async (provider, metadata) => {
5 // metadata contains the connected wallet name
6 const walletName = metadata.wallet.name;
7 // provider is an EIP-1193 compatible JavaScript object https://eips.ethereum.org/EIPS/eip-1193
8 // provider can be used by other libraries to request more data
9 const accounts = await provider.request({
10 method: 'eth_accounts',
11 });
12 },
13 [],
14);
15
16const onExit = useCallback<PlaidLinkOnExit>((error, metadata) => {
17 // Optional callback, called if the user exits without connecting a wallet
18 // See https://plaid.com/docs/link/web/#onexit for details
19}, []);
20
21const { open, ready } = useEthereumProvider({
22 // retrieve from https://dashboard.plaid.com/team/wallet-onboard
23 token: '',
24 chain: {
25 // RPC gateway URL to use for non-wallet methods
26 rpcUrl: '',
27 // EVM chain ID in hexadecimal format as described in https://eips.ethereum.org/EIPS/eip-695
28 // See https://chainlist.org/ for a list of common chains
29 chainId: '0x1',
30 },
31 onSuccess,
32 onExit,
33});
34
35return (
36 <button onClick={() => open()} disabled={!ready}>
37 Connect wallet
38 </button>
39);

Using a provider

The provider returned by onSuccess will be an EIP-1193-compatible object. The EIP-1193 Appendix has a complete definition of the methods available on the object, but in summary their APIs are:

  • provider.request(message) - Send JSON RPC methods to the wallet and/or node gateway.
  • provider.on(event, callback) - Subscribe to events like account or connection changes.
  • provider.removeListener(event, callback) - Remove subscriptions added by provider.on

Here are some examples of using the provider:

Copy
1// Getting the connected accounts
2const accounts: string[] = await provider.request({ method: 'eth_accounts' });
3
4// Request a signed message
5const account = accounts[0];
6const message = Web3.utils.toHex('Hello!');
7const signature: string = await provider.request({
8 method: 'personal_sign',
9 params: [message, accounts],
10});
11// The signature can be used to verify the signer using another library
12// For example, using Web3.js:
13const recoveredAccount: string = web3.eth.accounts.recover(message, signature);
14const validSignature = recoveredAccount === account;
15
16// Send network currency (e.g. ETH)
17const to: string = '0x...';
18const from: string = account;
19// value is denominated in e.g. wei for ETH
20// Usually a library should be used to convert
21// between the denominations
22const value: string = Web3.utils.toWei('1', 'ether');
23const txHash: string = await provider.request({
24 method: 'eth_sendTransaction',
25 params: [
26 {
27 to,
28 from,
29 value,
30 },
31 ],
32});

For more documentation on the available JSON RPC methods, review the Ethereum.org docs and Plaid's provider TypeScript definitions.

As shown above, many usages of the provider are simplified by libraries such as Web3.js and Ethers.js. These libraries will use EIP-1193 providers to build other abstractions and implement more complicated numberic or cryptographic operations:

Copy
1// Example: Web3.js https://web3js.readthedocs.io/en/v1.7.3/
2const web3 = new Web3(provider);
3const address = (await web3.eth.getAccounts())[0];
4const balance = await web3.eth.getBalance(address);
5
6// Example: Ethers.js https://docs.ethers.io/v5/
7const web3Provider = new providers.Web3Provider(provider);
8const signer = web3Provider.getSigner();
9const address = await signer.getAddress();
10const balance = await web3Provider.getBalance(address);

Your app should listen for important provider events and respond appropriately:

Copy
1const handleChainChanged = (chainId) => {
2 if (isCompatibleChain(chainId)) {
3 // update UI
4 } else {
5 // alert the user
6 }
7};
8provider.on('chainChanged', handleChainChanged);
9
10const handleAccountsChanged = (accounts) => {
11 if (accounts.length > 0) {
12 // update UI
13 } else {
14 // alert the user
15 }
16};
17provider.on('accountsChanged', accountsChanged);
RPC URLs

An RPC URL is required for any interactions with the blockchain that cannot be processed by the wallet (e.g. signing transactions). In addition to running your own node and/or RPC HTTP gateway, you can check this list of providers of RPC gateways.

Chain Management

If the user selects an account in their wallet that is not the chainId configured, Wallet Onboard will attempt to automatically switch to a compatible chain if the wallet supports that functionality (EIP-3326 and EIP-3085); if the wallet does not support that functionality, Link will instruct the user on the issue and suggest possible solutions.

Reinitialize previous connections

If a user has previously connected a wallet, your app can optionally detect that and reuse the connection without opening Link again:

Select Language
Copy
1const config = { token: '', chain: { chainId, rpcUrl } };
2const {
3 open,
4 ready,
5 getCurrentEthereumProvider,
6 isProviderActive,
7} = useEthereumProvider(config);
8
9useEffect(() => {
10 if (!ready || !getCurrentEthereumProvider || !isProviderActive) {
11 return;
12 }
13 (async () => {
14 const provider = await getCurrentEthereumProvider(config.chain);
15 if (!provider) {
16 // UX to handle no existing connection
17 return;
18 }
19 const isActive = await isProviderActive(provider);
20 if (isActive) {
21 // use provider
22 } else {
23 // UX to handle no existing connection
24 }
25 })();
26}, [ready, getCurrentEthereumProvider, isProviderActive]);

The connection will persist for as long as possible on the same device. The user may disconnect your app via their wallet at any time, so be sure to check isProviderActive and listen for disconnected events per EIP-1193.

Disconnecting

Your app can optionally disconnect itself from the user's wallet:

Select Language
Copy
1const { open, ready, disconnectEthereumProvider } = useEthereumProvider(config);
2
3const disconnect = useCallback(() => {
4 if (!disconnectEthereumProvider || !provider) {
5 return;
6 }
7
8 async () => {
9 await disconnectEthereumProvider(provider);
10 };
11}, [disconnectEthereumProvider, provider]);
12
13if (provider) {
14 return <button onClick={disconnect}>Disconnect</button>;
15}
16
17return (
18 <button onClick={() => open()} disabled={!ready}>
19 Connect wallet
20 </button>
21);

This is appropriate for any "sign out" flows your app may have.

Customization

Wallet Onboard supports some of the Link customizations available in the Dashboard:

  • Background Color
  • Consent

More customizations, including Dark Themes and Wallet Select options, will be available soon.

Was this helpful?
Developer community
GitHub
GitHub
Stack Overflow
Stack Overflow
YouTube
YouTube
Twitter
Twitter
Discord
Discord