- Pairing - Creating secure connections between wallets and DApps
- Session Management - Handling proposal, approval, rejection, and termination of sessions
- WebSocket Connection - Maintaining stable connection with the relay network
- Error Handling - Processing and communicating errors between components
Checklist Before Going Live
To ensure your wallet adheres to best practices, implement the following before deployment:| Category | Best Practice | Details |
|---|---|---|
| Success and Error Messages | Display clear messages for all interactions | • Show connection success messages • Show connection error messages • Provide loading indicators during waiting periods |
| Inform users of connection status | • Display real-time connection state • Show transaction status updates | |
| Implement internet availability indicators | • Alert users when connection is lost • Provide recovery options | |
| Provide feedback to both users and DApps | • Communicate errors to both user interfaces | |
| Mobile Linking | Implement automatic redirection | • Enable seamless transitions between wallet and DApp |
| Use deep linking over universal linking | • More reliable direct app launching • Better parameter passing support | |
| Ensure proper return to DApp | • Redirect after transaction completion | |
| Latency | Optimize performance | • Minimize delays in all interactions |
| Connection time in normal conditions | • Target: under 5 seconds | |
| Connection time in poor network (3G) | • Target: under 15 seconds | |
| Signing time in normal conditions | • Target: under 5 seconds | |
| Signing time in poor network (3G) | • Target: under 10 seconds | |
| Verify API | Present security status indicators | • Domain match: verified domain • Unverified: domain not in registry • Mismatch: domain doesn’t match registry • Threat: flagged as malicious |
| SDK Version | Use latest SDK version | • Benefit from latest features and security updates |
| Update SDK regularly | • Fix known bugs • Improve performance | |
| Subscribe to SDK updates | • Stay informed of new releases and deprecations |
1. User Feedback and Messaging
Context
Users often face ambiguity determining whether their connection or transactions were successful. Clear messaging reduces anxiety and improves user experience.Best Practices
- ✅ Display clear success and error messages for all user interactions
- ✅ Provide loading indicators during connection and transaction processing
- ✅ Include status indicators for internet availability
- ✅ Return errors to the DApp (not just the user) to allow proper state management

An example of a successful connection message in a Rainbow wallet
2. Pairing Implementation
Pairing Overview
What is Pairing? A pairing is a secure connection between a wallet and a DApp with fixed permissions that allows the DApp to propose sessions.Pairing Process
- Web
- React Native
- iOS
- Android
Pairing State Management
Pairing Expiry
All pairings expire after 5 minutes if no successful session is established. After a successful session establishment, monitor these events to update your UI accordingly.- Web
- React Native
- iOS
- Android
Expected Pairing Errors
| Error Type | Description | User Action | DApp Action |
|---|---|---|---|
| No Internet | Connection attempt with no network | Retry with active connection | Display error, allow retry |
| Expired Pairing | QR code/URI has expired | Refresh QR code and scan again | Generate new pairing URI |
| Pairing Already Exists | Attempting to use an already paired URI | Scan a new QR code | Generate new pairing URI |
| Malformed Pairing URI | URI does not follow WalletConnect protocol format | Try a different DApp or report issue | Ensure correct implementation of WalletConnect URI format |
| Invalid URI | Pairing URI structure is incorrect | Get new URI from DApp | Check URI format matches WalletConnect spec |
3. Session Proposal Handling
What is a Session Proposal?
A session proposal is a handshake sent by a DApp that defines the rules and permissions for the connection. The wallet must approve or reject this proposal to establish a session.Sample Session Proposal Object
Approving a Session
- Web
- React Native
- iOS
- Android
Rejecting a Session
- Web
- React Native
- iOS
- Android
4. Mobile Linking
What is Mobile Linking?
Mobile linking allows seamless transitions between DApps and wallets on mobile devices, ensuring users can complete actions without manually switching applications.Deep Links vs Universal Links
Deep links (e.g.,yourwallet://) provide a more reliable user experience than universal links. Deep links:
- Launch the target app directly
- Support passing parameters in the URL
- Work consistently across platforms
Why use Mobile Linking?
Mobile Linking uses the mobile device’s native OS to automatically redirect between the native wallet app and a native app. This results in few user actions a better UX.Establishing Communication Between Mobile Wallets and Apps
When integrating a wallet with a mobile application, it’s essential to understand how they communicate. The process involves two main steps:- QR Code Handshake: The mobile app (Dapp) generates a unique URI (Uniform Resource Identifier) and displays it as a QR code. This URI acts like a secret handshake. When the user scans the QR code or copy/pastes the URI using their wallet app, they establish a connection. It’s like saying, “Hey, let’s chat!”
- Deep Links and Universal Links: The URI from the QR code allows the wallet app to create a deep link or universal link. These links work on both Android and iOS. They enable seamless communication between the wallet and the app.
Key Behavior to Address
In some scenarios, wallets use redirect metadata provided in session proposals to open applications. This can cause unintended behavior, such as:- Redirecting to the wrong app when multiple apps share the same redirect metadata (e.g., a desktop and mobile version of the same Dapp).
- Opening an unrelated application if a QR code is scanned on a different device than where the wallet is installed.
Recommended Approach
To avoid this behavior, wallets should:- Restrict Redirect Metadata to Deep Link Use Cases: Redirect metadata should only be used when the session proposal is initiated through a deep link. QR code scans should not trigger app redirects using session proposal metadata.
Connection Flow
- Dapp prompts user: The Dapp asks the user to connect.
- User chooses wallet: The user selects a wallet from a list of compatible wallets.
- Redirect to wallet: The user is redirected to their chosen wallet.
- Wallet approval: The wallet prompts the user to approve or reject the session (similar to granting permission).
- Return to dapp:
- Manual return: The wallet asks the user to manually return to the Dapp.
- Automatic return: Alternatively, the wallet automatically takes the user back to the Dapp.
- User reunites with dapp: After all the interactions, the user ends up back in the Dapp.

Sign Request Flow
When the Dapp needs the user to sign something (like a transaction), a similar pattern occurs:- Automatic redirect: The Dapp automatically sends the user to their previously chosen wallet.
- Approval prompt: The wallet asks the user to approve or reject the request.
- Return to dapp:
- Manual return: The wallet asks the user to manually return to the Dapp.
- Automatic return: Alternatively, the wallet automatically takes the user back to the Dapp.
- User reconnects: Eventually, the user returns to the Dapp.

Platform Specific Preparation
- iOS
- Android
- Flutter
- React Native
Read the specific steps for iOS here: Platform preparations
How to Test
To experience the desired behavior, try our Sample Wallet and Dapps which use our Mobile linking best practices. These are available on all platforms. Once you have completed your integration, you can test it against our sample apps to see if it is working as expected. Download the app and try your mobile linking integration on your device.- iOS
- Android
- Flutter
- React Native
- Sample Wallet - on TestFlight
- Sample DApp - on TestFlight
Implementing Mobile Linking
- iOS
- Android
Redirecting Back to DApp
After completing an action, ensure your wallet redirects the user back to the DApp:- iOS
- Android
5. Session Request
A session request represents the request sent by a DApp to a wallet. Whenever user approves or rejects a session request, a wallet should show a loading indicator the moment the button is pressed, until Relay acknowledgement is received for any of these actions.- Web
- React Native
- iOS
- Android
Session Request Expiry
A session request expiry is defined by a DApp. Its value must be betweennow() + 5mins and now() + 7 days. After the session request expires, the below event is emitted and session request modal should be removed from the app’s UI.
- Web
- React Native
- iOS
- Android
Expected Session Request Errors
| Error Type | Description | User Action | DApp Action |
|---|---|---|---|
| Invalid Session | Request made on expired/invalid session | Reconnect to the DApp | Detect session expiry and prompt for reconnection |
| Session Request Expired | Approval/rejection after request timeout | Handle new requests only | Set appropriate timeout periods |
| Timeout | No relay acknowledgement within 10 seconds | Retry the action | Implement proper timeout handling |
| Network Error | Connection issues during request | Check network and retry | Display network status indicators |
6. Connection State
The Web Socket connection state tracks the connection with the Relay server. An event is emitted whenever a connection state changes.- Web
- React Native
- iOS
- Android
Connection State Messages
When the connection state changes, show a message in the UI. For example, display a message when the connection is lost or re-established.7. Latency
Our SDK’s position in the boot chain can lead to up to 15 seconds in throttled network conditions. Lack of loading indicators exacerbates the perceived latency issues, impacting user experience negatively. Additionally, users often do not receive error messages or codes when issues occur or timeouts happen.Target Latency
For connecting, the target latency is:- Under 5 seconds in normal conditions
- Under 15 seconds when throttled (3G network speed)
- Under 5 seconds in normal conditions
- Under 10 seconds when throttled (3G network speed)
How to Test
To test latency under suboptimal network conditions, you can enable throttling on your mobile phone. You can simulate different network conditions to see how your app behaves in various scenarios. For example, on iOS you need to enable Developer Mode and then go to Settings > Developer > Network Link Conditioner. You can then select the network condition you want to simulate. For 3G, you can select 3G from the list, for no network or timeout simulations, choose 100% Loss. Check this article for how to simulate slow internet connection on iOS & Android, with multiple options for both platforms: How to simulate slow internet connection on iOS & Android.8. Verify API
Verify API is a security-focused feature that allows wallets to notify end-users when they may be connecting to a suspicious or malicious domain, helping to prevent phishing attacks across the industry. Once a wallet knows whether an end-user is on uniswap.com or eviluniswap.com, it can help them to detect potentially harmful connections through Verify’s combined offering of Reown’s domain registry. When a user initiates a connection with an application, Verify API enables wallets to present their users with four key states that can help them determine whether the domain they’re about to connect to might be malicious. Possible states:- Domain match
- Unverified
- Mismatch
- Threat


Verify API is not designed to be bulletproof but to make the impersonation attack harder and require a somewhat sophisticated attacker. We are working on a new standard with various partners to close those gaps and make it bulletproof.
Domain Risk Detection
The Verify security system will discriminate session proposals & session requests with distinct validations that can be eitherVALID, INVALID or UNKNOWN.
- Domain match: The domain linked to this request has been verified as this application’s domain.
- This interface appears when the domain a user is attempting to connect to has been ‘verified’ in our domain registry as the registered domain of the application the user is trying to connect to, and the domain has not returned as suspicious from either of the security tools we work with. The
verifyContextincluded in the request will have a validation ofVALID.
- This interface appears when the domain a user is attempting to connect to has been ‘verified’ in our domain registry as the registered domain of the application the user is trying to connect to, and the domain has not returned as suspicious from either of the security tools we work with. The
- Unverified: The domain sending the request cannot be verified.
- This interface appears when the domain a user is attempting to connect to has not been verified in our domain registry, but the domain has not returned as suspicious from either of the security tools we work with. The
verifyContextincluded in the request will have a validation ofUNKNOWN.
- This interface appears when the domain a user is attempting to connect to has not been verified in our domain registry, but the domain has not returned as suspicious from either of the security tools we work with. The
- Mismatch: The application’s domain doesn’t match the sender of this request.
- This interface appears when the domain a user is attempting to connect to has been flagged as a different domain to the one this application has verified in our domain registry, but the domain has not returned as suspicious from either of the security tools we work with. The
verifyContextincluded in the request will have a validation ofINVALID
- This interface appears when the domain a user is attempting to connect to has been flagged as a different domain to the one this application has verified in our domain registry, but the domain has not returned as suspicious from either of the security tools we work with. The
- Threat: This domain is flagged as malicious and potentially harmful.
- This interface appears when the domain a user is attempting to connect to has been flagged as malicious on one or more of the security tools we work with. The
verifyContextincluded in the request will contain parameterisScamwith valuetrue.
- This interface appears when the domain a user is attempting to connect to has been flagged as malicious on one or more of the security tools we work with. The
Verify API Implementation
To see how to implement Verify API for your framework, see Verify API page and select your platform to see code examples.How to Test
To test Verify API with a malicious domain, you can check out the Malicious React dapp, created specifically for testing. This app is flagged as malicious and will have theisScam parameter set to true in the verifyContext of the request. You can use this app to test how your wallet behaves when connecting to a malicious domain.
Error Messages

9. Latest SDK Version
Numerous features have been introduced, bugs have been identified and fixed over time, stability has improved, but many DApps and wallets continue to use older SDK versions with known issues, affecting overall reliability. Make sure you are using the latest version of the SDK for your platform- iOS
- Android
- Flutter
- React Native
- WalletConnectSwiftV2: Latest release
Subscribe to Updates
To stay up to date with the latest SDK releases, you can use GitHub’s native feature to subscribe to releases. This way, you will be notified whenever a new release is published. You can find the “Watch” button on the top right of the repository page. Click on it, then select “Custom” and “Releases only”. You’ll get a helpful ping whenever a new release is out.
10. Testing WalletKit Features
Test Scenarios
| Feature | Test Scenario | Expected Outcome |
|---|---|---|
| Pairing | Scan QR with no internet | Error message shown + retry option |
| Scan expired QR code | Error with refresh suggestion | |
| Scan valid QR code | Successful pairing, proposal shown | |
| Session Proposal | Approve with selected accounts | Success message, session active |
| Reject proposal | Success message, back to home screen | |
| App killed during approval | Proper error handling when reopened | |
| Mobile Linking | Open deep link from DApp | Wallet opens with correct context |
| Complete action in wallet | Redirects back to DApp | |
| Performance | Measure connection time | < 5s in normal conditions |
| Measure signing time | < 5s in normal conditions | |
| Multiple Connections | Connect to multiple DApps | All connections work independently |
| WebSocket Connection | Turn off Wi-Fi during session | Reconnection attempt + user notification |
11. Troubleshooting
Common Issues
| Issue | Possible Causes | Solution |
|---|---|---|
| Session proposal not received | Network issues, pairing expired | Check network, refresh QR code |
| Cannot approve session | Invalid namespace configuration | Ensure accounts match required chains |
| Slow connection | Poor network, obsolete SDK | Check network, update SDK |
| Deep link not working | Improper URL scheme registration | Verify URL scheme in app manifest/Info.plist |
| Session disconnects frequently | Background process limitations | Implement proper reconnection logic |
Resources
- React Wallet - for testing DApps, features, Verify API messages, etc.
- React DApp - for testing wallets
- Malicious React DApp - for testing Verify API with malicious domain