User experience tailoring and analytics
Up until recently, the Invoice was a fairly robust but rigid interface. It only needed to handle 2 currencies + a Payment Protocol link or QR code. Adding ETH and ERC20 token capability became the first time we had to support another payment method (Web3) where there was clear preference based on wallet.
If the user is paying with a BitPay or Copay wallet, then the only way to pay is with a PayPro link. However, if the user is paying with MetaMask, then we need to connect to their wallet via Web3 to pay. Without any upfront selection, we initially handled this by detecting the presence of Web3 and providing a manual toggle (less than ideal).
It became clear after the launch of ETH that we needed a robust but elegant way to handle rapidly diverging feature sets.
In response to these problems, I created the Wallet Selection flow over the course of 2019, drawing inspiration from companies like Plaid, Mollie, and more. I finally had a chance to build and launch it in the beginning of 2020 as the company made P2P support a major initiative.
The solution was a relatively obvious one because of the following requirements:
- 1Use Payment Protocol if supported
- 2Use Web3 for all other ETH wallets
- 3Display Address + Amount for P2P payments
However, because we now could now display custom behavior for any particular payment method selected, the design ended up unlocking a lot more capability than we initially set out to solve.
V4 Reference Implementation
Instant, zero fee payments
As soon as we enabled P2P payments via Wallet Selection, we finally had some insight into what was really going on with users' payment experiences. Pretty quickly, Coinbase rose to our 4th most popular payment method but with a ~30% error rate.
Basically, around 30% of Coinbase users were making some kind of error when paying due to the decoupled nature of P2P payments (push vs. pull). Common errors included mistakenly entering in a USD amount when withdrawing or a delayed transfer.
Coinbase's Connect API seemed like the perfect solution to address all our problems. By directly connecting to a user's account, we can initiate an exact withdrawal while still requiring manual authorization by the user (secure & precise).
The end result is an instant, errorless payment experience that bypasses the usual issues of dealing with crypto addresses and exact decimal amounts.
V4 Reference Implementation
Guiding the experience with helpful info
To handle the common pitfalls with payments, the Info state is a simple way to chuck in helpful information. Even Payment Protocol enabled wallets like Bitcoin Core / ABC are a bit tricky to use when it comes to pasting in links.
In the case of Coinbase Wallet, the best way to ensure an accurate P2P payment experience is to scan the BIP21 URI. We often saw users manually entering into the wallet's send flow rather than scanning the QR code.
For other providers like Cash App, we use this state to prevent common errors we see. The graph above is demonstration of the effectiveness of this state. The inflection point around February 2020 is when we implemented an enhanced Payment Instructions state for Cash App. You can clearly see the uptrend in conversions (actually paying the Invoice) and an overall downtrend in payment errors (sending less or more money than needed).
Looking back on the data over the last year, it is definitely amazing what a simple change like this can do!
Figuring out what users want
As I mentioned previously, a large focus of ours was making sure we were capturing as much as we could about what our users wanted. If you can't find your wallet, I included a bailout option; clicking on "I don't see my wallet" let's the user submit a response.
We also keep track of what people are searching so we can preemptively investigate a payment method before a request.
More Wallet Connections
Bringing seamless payments to others
The screens above are a sneak peak of more direct integrations coming soon to the invoice. MetaMask is already a supported wallet but the above is an example of the in-browser "connection pending" UI.