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

# Usage

## Overview

WalletConnect makes distributing your Web wallet (such as Safe, Abstract Global Wallet, and many more) much faster. By integrating the Wallet SDK, your web wallet will be able to connect to any dApp that supports WalletConnect and will be available in the list of wallets on both WalletConnect, Reown AppKit, and others.

<Frame caption="Web Wallet in Reown AppKit & WalletButtons">
  <img height="400" width="300" src="https://mintlify.s3.us-west-1.amazonaws.com/reown-5552f0bb/images/web-wallet-safe.png" alt="Web Wallet in Reown AppKit" />

  <img height="600" width="300" src="https://mintlify.s3.us-west-1.amazonaws.com/reown-5552f0bb/images/web-wallet-button.png" alt="Web Wallet in WalletConnect" />
</Frame>

Additionally, you don't need to build SDKs in native languages such as Swift, Kotlin, Flutter, Unity, or React Native. This means your wallet can be available not just for web dApps, but also for native dApps, all from a single codebase.

This section provides instructions on how to initialize the WalletKit client, approve sessions with supported namespaces, and respond to session requests, enabling easy integration of Web3 wallets with dApps through a simple and intuitive interface.

## User Experience

### Default Integration

This integration automatically opens a new web wallet tab when a user clicks "Connect" in a dApp. The wallet handles the WalletConnect URI automatically, meaning users don't need to manually copy and paste the URI. This provides a seamless, one-click connection experience.

<Frame caption="Abstract Global Wallet to Wolfswap">
  <video controls autoPlay className="w-full aspect-video" src="https://mintlify.s3.us-west-1.amazonaws.com/reown-5552f0bb/images/web-wallet-demo.mp4" />
</Frame>

### QR Code Integration

This integration only handles the session proposal and approval via the WalletConnect QR code. The user will need to manually copy and paste the WalletConnect URI into the wallet.

<Frame caption="Safe Wallet Connecting to AppKit Lab">
  <video controls autoPlay className="w-full aspect-video" src="https://mintlify.s3.us-west-1.amazonaws.com/reown-5552f0bb/images/web-wallet-qr-demo.mp4" />
</Frame>

## Cloud Configuration

Create a new project on WalletConnect Dashboard at [https://dashboard.walletconnect.com](https://dashboard.walletconnect.com) and obtain a new project ID.

<Info>
  **Don't have a project ID?**

  Head over to WalletConnect Dashboard and create a new project now!

  <Card title="Get started" href="https://dashboard.walletconnect.com/?utm_source=cloud_banner&utm_medium=docs&utm_campaign=backlinks" />
</Info>

## Initialization

Create a new instance from Core and initialize it with a projectId created from installation. Next, create WalletKit instance by calling init on walletKit. Passing in the options object containing metadata about the app and an optional relay URL.

<Info>
  Make sure you initialize `walletKit` globally and use the same instance for all your sessions. For React-based apps, you can initialize it in the root component and export it to use in other components.
</Info>

```javascript theme={null}
import { Core } from "@walletconnect/core";
import { WalletKit } from "@reown/walletkit";

const core = new Core({
  projectId: process.env.PROJECT_ID,
});

const walletKit = await WalletKit.init({
  core, // <- pass the shared `core` instance
  metadata: {
    name: "Demo app",
    description: "Demo Client as Wallet/Peer",
    url: "https://reown.com/walletkit",
    icons: [],
  },
});
```

### Core Instance Sharing

Starting from newer versions of WalletKit, Core instances are shared globally by default to optimize resource usage. This means that multiple Core instances with the same configuration will reuse the same underlying Core.

**For parallel testing scenarios** where you need isolated Core instances, you have two options:

#### Option 1: Use customStoragePrefix

```javascript theme={null}
const core = new Core({
  projectId: process.env.PROJECT_ID,
  customStoragePrefix: `test-${Date.now()}`, // Unique prefix for each test
});
```

<Warning>
  Don't use randomly generated `customStoragePrefix` in production - this will cause the client to create new storage each time it is initialized. The client will not be able to persist/read existing data and all existing sessions will be lost after each reload.
</Warning>

#### Option 2: Disable global Core sharing

```javascript theme={null}
// Set environment variable before initializing Core
process.env.DISABLE_GLOBAL_CORE = "true";

const core = new Core({
  projectId: process.env.PROJECT_ID,
});
```

<Note>
  The global Core sharing behavior was introduced to prevent resource waste when multiple SDK instances are created. If you're running parallel tests and experiencing cross-test interference, use one of the solutions above to ensure proper test isolation.
</Note>

## Session

A session is a connection between a dapp and a wallet. It is established when a user approves a session proposal from a dapp. A session is active until the user disconnects from the dapp or the session expires.

### Handling Session Proposals

You can connect your web wallet to a dApp in three ways:

1. Retrieve the WC URI from the dApp via query parameters
2. Implement a scanner to read the WC URI from a WalletConnect QR code
3. Allow users to manually enter the WC URI in an input field

When opening the wallet directly from the dApp, the `WC_URI` will be in the following format in the query parameters:

```
{YOUR_WALLET_URL}/wc?uri={WC_URI}
```

We recommend closing the web wallet tab after the user approves the request and redirecting back to the dApp. For web requests, redirect to the original browser tab, and for mobile requests, redirect to the native mobile dApp.

<Note>
  To test your web wallet connection flow, use our [Appkit Laboratory](https://appkit-lab.reown.com/) by adding a custom wallet with your web wallet URL.
</Note>

### Handling Session Requests

When a dApp sends a session request to your wallet, the request will be available in the following format in the query parameters:

```
{YOUR_WALLET_URL}/wc?requestId={requestId}&sessionTopic={session.Topic}
```

This format allows your wallet to identify both the specific request and the session it belongs to.

<Note>
  To test your web wallet connection flow, use our [Appkit Laboratory](https://appkit-lab.reown.com/) by adding a custom wallet with your web wallet URL.
</Note>

### Handling Redirects

When handling redirects after session approval or request completion, you should:

1. For web dApps:
   * Redirect back to the original browser tab using `window.opener.location.href`
   * Close the current wallet tab using `window.close()`

2. For native dApps:
   * Check the peer metadata for a `redirect` URL in the session proposal
   * If available, use deep linking to redirect to the native app
   * If no redirect URL is found, display a "Return to App" message to the user

Example implementation:

```javascript theme={null}
function handleRedirect(session) {
  // Check if this is a native app
  const isNativeApp = session.peer.metadata.redirect !== undefined;
  
  if (isNativeApp) {
    // Redirect to native app if URL is available
    if (session.peer.metadata.redirect) {
      window.location.href = session.peer.metadata.redirect;
    } else {
      // Show "Return to App" message
      showReturnToAppMessage();
    }
  } else {
    // For web dApps, redirect back to original tab
    if (window.opener) {
      window.opener.location.href = session.peer.metadata.url;
      window.close();
    }
  }
}
```

### Namespace Builder

With WalletKit (and @walletconnect/utils) we've published a helper utility that greatly reduces the complexity of parsing the `required` and `optional` namespaces. It accepts as parameters a `session proposal` along with your user's `chains/methods/events/accounts` and returns ready-to-use `namespaces` object.

```javascript theme={null}
// util params
{
  proposal: ProposalTypes.Struct; // the proposal received by `.on("session_proposal")`
  supportedNamespaces: Record< // your Wallet's supported namespaces
    string, // the supported namespace key e.g. eip155
    {
      chains: string[]; // your supported chains in CAIP-2 format e.g. ["eip155:1", "eip155:2", ...]
      methods: string[]; // your supported methods e.g. ["personal_sign", "eth_sendTransaction"]
      events: string[]; // your supported events e.g. ["chainChanged", "accountsChanged"]
      accounts: string[] // your user's accounts in CAIP-10 format e.g. ["eip155:1:0x453d506b1543dcA64f57Ce6e7Bb048466e85e228"]
      }
  >;
};
```

Example usage

```javascript theme={null}
// import the builder util
import { WalletKit, WalletKitTypes } from '@reown/walletkit'
import { buildApprovedNamespaces, getSdkError } from '@walletconnect/utils'

async function onSessionProposal({ id, params }: WalletKitTypes.SessionProposal){
  try{
    // ------- namespaces builder util ------------ //
    const approvedNamespaces = buildApprovedNamespaces({
      proposal: params,
      supportedNamespaces: {
        eip155: {
          chains: ['eip155:1', 'eip155:137'],
          methods: ['eth_sendTransaction', 'personal_sign'],
          events: ['accountsChanged', 'chainChanged'],
          accounts: [
            'eip155:1:0xab16a96d359ec26a11e2c2b3d8f8b8942d5bfcdb',
            'eip155:137:0xab16a96d359ec26a11e2c2b3d8f8b8942d5bfcdb'
          ]
        }
      }
    })
    // ------- end namespaces builder util ------------ //

    const session = await walletKit.approveSession({
      id,
      namespaces: approvedNamespaces
    })
  }catch(error){
    // use the error.message to show toast/info-box letting the user know that the connection attempt was unsuccessful
    ....
    await walletKit.rejectSession({
      id: proposal.id,
      reason: getSdkError("USER_REJECTED")
    })
  }
}


walletKit.on('session_proposal', onSessionProposal)
```

If your wallet supports multiple namespaces e.g. `eip155`,`cosmos` & `near`
Your `supportedNamespaces` should look like the following example.

```javascript theme={null}
// ------- namespaces builder util ------------ //
const approvedNamespaces = buildApprovedNamespaces({
    proposal: params,
    supportedNamespaces: {
        eip155: {...},
        cosmos: {...},
        near: {...}
    },
});
// ------- end namespaces builder util ------------ //
```

### Get Active Sessions

You can get the wallet active sessions using the `getActiveSessions` function.

```js theme={null}
const activeSessions = walletKit.getActiveSessions();
```

### EVM methods & events

In @walletconnect/ethereum-provider, (our abstracted EVM SDK for apps) we support by default the following Ethereum methods and events:

```ts theme={null}
{
  //...
  methods: [
    "eth_accounts",
    "eth_requestAccounts",
    "eth_sendRawTransaction",
    "eth_sign",
    "eth_signTransaction",
    "eth_signTypedData",
    "eth_signTypedData_v3",
    "eth_signTypedData_v4",
    "eth_sendTransaction",
    "personal_sign",
    "wallet_switchEthereumChain",
    "wallet_addEthereumChain",
    "wallet_getPermissions",
    "wallet_requestPermissions",
    "wallet_registerOnboarding",
    "wallet_watchAsset",
    "wallet_scanQRCode",
    "wallet_sendCalls",
    "wallet_getCallsStatus",
    "wallet_showCallsStatus",
    "wallet_getCapabilities",
  ],
  events: [
    "chainChanged",
    "accountsChanged",
    "message",
    "disconnect",
    "connect",
  ]
}
```

### Session Approval

The `session_proposal` event is emitted when a dapp initiates a new session with a user's wallet. The event will include a `proposal` object with information about the dapp and requested permissions. The wallet should display a prompt for the user to approve or reject the session. If approved, call `approveSession` and pass in the `proposal.id` and requested `namespaces`.

The `pair` method initiates a WalletConnect pairing process with a dapp using the given `uri` (QR code from the dapps). To learn more about pairing, checkout out the [docs](https://docs.reown.com/advanced/api/core/pairing).

```javascript theme={null}
walletKit.on(
  "session_proposal",
  async (proposal: WalletKitTypes.SessionProposal) => {
    const session = await walletKit.approveSession({
      id: proposal.id,
      namespaces,
    });
  }
);
await walletKit.pair({ uri });
```

### 🛠️ Usage examples

* [in a demo wallet app](https://github.com/reown-com/web-examples/blob/main/advanced/wallets/react-wallet-v2/src/views/SessionProposalModal.tsx#L264)
* [in integration tests](https://github.com/reown-com/reown-walletkit-js/blob/main/packages/walletkit/test/sign.spec.ts#L55)

### ⚠️ Expected Errors

* `No matching key. proposal id doesn't exist: 1`

This rejection means the SDK can't find a record with the given `proposal.id` - in this example `1`.
This can happen when the proposal has expired (by default 5 minutes) or if you attempt to respond to a proposal that has already been approved/rejected.
If you are seeing this error, please make sure that you are calling `approveSession` with the correct `proposal.id` that is available within the proposal payload.

* `Error: Missing or invalid. approve(), namespaces should be an object with data`

This error means that the `namespaces` parameter passed to `approveSession` is either missing or invalid. Please check that you are passing a valid `namespaces` object that satisfies all required properties.

* `Non conforming namespaces. approve() namespaces <property> don't satisfy required namespaces.`

This error indicates that some value(s) in your `namespaces` object do not satisfy the required namespaces requested by the dapp.
To provide additional guidance, the message might include info about the exact property that is missing or invalid e.g. `Required: eip155:1 Approved: eip155:137`.
Please check [CAIP-25](https://github.com/ChainAgnostic/CAIPs/blob/master/CAIPs/caip-25.md) to familiarize yourself with the standard and it's nuances.
Additionally, we highly recommend you to use our `namespace` builder utility that would greatly simplify the process of parsing & building a valid `namespaces` object.

### Session Rejection

In the event you want to reject the session proposal, call the `rejectSession` method. The `getSDKError` function comes from the `@walletconnect/utils` [library](https://github.com/WalletConnect/walletconnect-monorepo/tree/v2.0/packages/utils).

```javascript theme={null}
walletKit.on(
  "session_proposal",
  async (proposal: WalletKitTypes.SessionProposal) => {
    await walletKit.rejectSession({
      id: proposal.id,
      reason: getSdkError("USER_REJECTED_METHODS"),
    });
  }
);
```

### 🛠️ Usage examples

* [in a demo wallet app](https://github.com/WalletConnect/web-examples/blob/a50c8eb5a10666f25911713c5358e78f1ca576d6/advanced/wallets/react-wallet-v2/src/views/SessionProposalModal.tsx#L287)
* [in integration tests](https://github.com/reown-com/reown-walletkit-js/blob/main/packages/walletkit/test/sign.spec.ts#L79)

### ⚠️ Expected Errors

* `No matching key. proposal id doesn't exist: 1`

This rejection means the SDK can't find a record with the given `proposal.id` - in this example `1`.
This can happen when the proposal has expired (by default 5 minutes) or if you attempt to respond to a proposal that has already been approved/rejected.
If you are seeing this error, please make sure that you are calling `rejectSession` with the correct `proposal.id` that is available within the proposal payload.

* `Error: Missing or invalid. reject() reason:`

This rejection means the `reason` parameter passed to `rejectSession` is either missing or invalid.
We recommend using the `getSDKError` function from the `@walletconnect/utils` library that will populate & format the parameter for you.

### Responding to Session requests

The `session_request` event is emitted when the SDK received a request from the peer and it needs the wallet to perform a specific action, such as signing a transaction. The event contains a `topic` and a `request` object, which will vary depending on the action requested.

To respond to the request, you can access the `topic` and `request` object by destructuring them from the event payload. To see a list of possible `request` and `response` objects, refer to the relevant JSON-RPC Methods for [Ethereum](https://docs.reown.com/advanced/multichain/rpc-reference/ethereum-rpc), [Solana](https://docs.reown.com/advanced/multichain/rpc-reference/solana-rpc), [Cosmos](https://docs.reown.com/advanced/multichain/rpc-reference/cosmos-rpc), or [Stellar](https://docs.reown.com/advanced/multichain/rpc-reference/stellar-rpc).

As an example, if the dapp requests a `personal_sign` method, you can extract the `params` array from the `request` object. The first item in the array is the hex version of the message to be signed, which can be converted to UTF-8 and assigned to a `message` variable. The second item in `params` is the user's wallet address.

To sign the message, you can use your wallet's `signMessage` method and pass in the message. The signed message, along with the `id` from the event payload, can then be used to create a `response` object, which can be passed into `respondSessionRequest`.

```javascript theme={null}
walletKit.on(
  "session_request",
  async (event: WalletKitTypes.SessionRequest) => {
    const { topic, params, id } = event;
    const { request } = params;
    const requestParamsMessage = request.params[0];

    // convert `requestParamsMessage` by using a method like hexToUtf8
    const message = hexToUtf8(requestParamsMessage);

    // sign the message
    const signedMessage = await wallet.signMessage(message);

    const response = { id, result: signedMessage, jsonrpc: "2.0" };

    await walletKit.respondSessionRequest({ topic, response });
  }
);
```

To reject a session request, the response should be similar to this.

```javascript theme={null}
const response = {
  id,
  jsonrpc: "2.0",
  error: {
    code: 5000,
    message: "User rejected.",
  },
};
```

### 🛠️ Usage examples

* [in a demo wallet app](https://github.com/WalletConnect/web-examples/blob/a50c8eb5a10666f25911713c5358e78f1ca576d6/advanced/wallets/react-wallet-v2/src/views/SessionSignModal.tsx#L36)
* [in integration tests](https://github.com/reown-com/reown-walletkit-js/blob/main/packages/walletkit/test/sign.spec.ts#L165)

### ⚠️ Expected Errors

* `Error: No matching key. session topic doesn't exist: 'xyz...'`

This rejection means the SDK can't find a session with the given `topic` - in this example `xyz...`.
This can happen when the session has been disconnected by either the wallet or the dapp while the session request was being processed or if a session with such topic doesn't exist.
If you are seeing this error, please make sure that you are using a correct topic that is available within the request payload.

* `Error: Missing or invalid. respond() response:`

This rejection means the `response` parameter passed to `respondSessionRequest` is either missing or invalid. The response should be a valid [JSON-RPC 2.0](https://www.jsonrpc.org/specification) response object.
We recommend you to use our `formatJsonRpcResult` utility from `"@walletconnect/jsonrpc-utils"` that will format the response for you.

Example usage:
`id` argument being the request id from the request payload.

```javascript theme={null}
import { formatJsonRpcResult } from "@walletconnect/jsonrpc-utils";

const signature = await cryptoWallet.signTransaction(signTransaction);
const response = await walletKit.respondSessionRequest({
  topic: session.topic,
  response: formatJsonRpcResult(id, signature),
});
```

### Updating a Session

If you wish to include new accounts or chains or methods in an existing session, `updateSession` allows you to do so.
You need pass in the `topic` and a new `Namespaces` object that contains all of the existing namespaces as well as the new data you wish to include.
After you update the session, the other peer will receive a `session_update` event.

An example adding a new account to an existing session:

```javascript theme={null}
const namespaces = session.namespaces;
const accounts = [
  "eip155:1:0xab16a96d359ec26a11e2c2b3d8f8b8942d5bfcdb",
  "eip155:1:0x1234567890123456789012345678901234567890",
];
const updatedNamespaces = {
  ...namespaces,
  eip155: {
    ...namespaces.eip155,
    accounts,
  },
};
const { acknowledged } = await walletKit.updateSession({
  topic: session.topic,
  namespaces: updatedNamespaces,
});
// If you wish to be notified when the dapp acknowledges the update.
// note that if the dapp is offline `acknowledged` will not resolve until it comes back online
await acknowledged();
```

An example adding a new chain to an existing session:

```javascript theme={null}
const namespaces = session.namespaces;
const chains = ["eip155:1", "eip155:137"];
const accounts = [
  "eip155:1:0xab16a96d359ec26a11e2c2b3d8f8b8942d5bfcdb",
  "eip155:137:0x1234567890123456789012345678901234567890",
];
const updatedNamespaces = {
  ...namespaces,
  eip155: {
    ...namespaces.eip155,
    accounts,
    chains,
  },
};
await walletKit.updateSession({
  topic: session.topic,
  namespaces: updatedNamespaces,
});
```

### 🛠️ Usage examples

* [in a demo wallet app](https://github.com/WalletConnect/web-examples/blob/a50c8eb5a10666f25911713c5358e78f1ca576d6/advanced/wallets/react-wallet-v2/src/pages/session.tsx#L77)
* [in integration tests](https://github.com/reown-com/reown-walletkit-js/blob/main/packages/walletkit/test/sign.spec.ts#L98)

### ⚠️ Expected Errors

Note that all `namespaces` validation applies and you still have to satisfy the required namespaces requested by the dapp.

* `Error: No matching key. session topic doesn't exist: 'xyz...'`

This rejection means the SDK can't find a session with the given `topic` - in this example `xyz...`.
This can happen when the session you're trying to update has already been disconnected by either the wallet or the dapp or if a session with such topic doesn't exist.
If you are seeing this error, please make sure that you are using a correct topic of an active session.

* `Error: Missing or invalid. update(), namespaces should be an object with data`

This error means that the `namespaces` parameter passed to `updateSession` is either missing or invalid. Please check that you are passing a valid `namespaces` object that satisfies all required properties.

* `Non conforming namespaces. update() namespaces <property> don't satisfy required namespaces.`

This error indicates that some value(s) in your `namespaces` object do not satisfy the required namespaces requested by the dapp.
To provide additional guidance, the message might include info about the exact property that is missing or invalid e.g. `Required: eip155:1 Approved: eip155:137`.
Please check [CAIP-25](https://github.com/ChainAgnostic/CAIPs/blob/master/CAIPs/caip-25.md) to familiarize yourself with the standard and it's nuances.
Additionally, we highly recommend you to use our `namespace` builder utility that would greatly simplify the process of parsing & building a valid `namespaces` object.

### Extending a Session

Sessions have a default expiry of 7 days. To extend a session by an additional 7 days, call `.extendSession` method and pass in the `topic` of the session you wish to extend.

```javascript theme={null}
const { acknowledged } = await walletKit.extendSession({ topic });
// if you wish to be notified when the dapp acks the extend
// note that if the dapp is offline `acknowledged` will not resolve until it comes back online
await acknowledged();
```

### 🛠️ Usage examples

* [in integration tests](https://github.com/reown-com/reown-walletkit-js/blob/main/packages/walletkit/test/sign.spec.ts#L130)

### ⚠️ Expected Errors

* `Error: No matching key. session topic doesn't exist: 'xyz...'`

This rejection means the SDK can't find a session with the given `topic` - in this example `xyz...`.
This can happen when the session you're trying to update has already been disconnected by either the wallet or the dapp or if a session with such topic doesn't exist.
If you are seeing this error, please make sure that you are using a correct topic of an active session.

### Session Disconnect

To initiate disconnect from a session(think session delete), call `.disconnectSession` by passing a `topic` & `reason` for the disconnect.
The other peer will receive a `session_delete` and be notified that the session has been disconnected.

<Note>
  **Note**

  It's important that you're subscribed to the `session_delete` event as well, to be notified when the other peer initiates a disconnect.
</Note>

<Tip>
  We recommend using the `getSDKError` utility function, that will provide ready-to-use `reason` payloads and is available in the `@walletconnect/utils` [library](https://github.com/WalletConnect/walletconnect-monorepo/tree/v2.0/packages/utils).
</Tip>

```javascript theme={null}
await walletKit.disconnectSession({
  topic,
  reason: getSdkError("USER_DISCONNECTED"),
});
```

### 🛠️ Usage examples

* [in integration tests](https://github.com/reown-com/reown-walletkit-js/blob/main/packages/walletkit/test/sign.spec.ts#L222)

### ⚠️ Expected Errors

* `Error: No matching key. session topic doesn't exist: 'xyz...'`

This rejection means the SDK can't find a session with the given `topic` - in this example `xyz...`.
This can happen when the session you're trying to update has already been disconnected by either the wallet or the dapp or if a session with such topic doesn't exist.
If you are seeing this error, please make sure that you are using a correct topic of an active session.

### Emitting Session Events

To emit session events, call the `emitSessionEvent` and pass in the params. If you wish to switch to chain/account that is not approved (missing from `session.namespaces`) you will have to update the session first. In the following example, the wallet will emit `session_event` that will instruct the dapp to switch the active accounts.

```javascript theme={null}
await walletKit.emitSessionEvent({
  topic,
  event: {
    name: "accountsChanged",
    data: ["0xab16a96D359eC26a11e2C2b3d8f8B8942d5Bfcdb"],
  },
  chainId: "eip155:1",
});
```

In the following example, the wallet will emit `session_event` when the wallet switches chains.

```javascript theme={null}
await walletKit.emitSessionEvent({
  topic,
  event: {
    name: "chainChanged",
    data: 1,
  },
  chainId: "eip155:1",
});
```
