Client-side implementation
This guide shows you how to add Venmo to your checkout using a custom integration. For compliance purposes, you must present the customer with an order summary before and after purchase.
The pre-purchase summary should include:
The items ordered.
The total order price.
An indication of Venmo as the payment method.
You can show the post-purchase summary in your UI or send it by email. It should include:
The items purchased.
The total purchase price.
The customer's name.
The customer's Venmo username.
Failing to comply with these guidelines can lead to an interruption of your Venmo service.
Download Venmo's brand guidelines and follow them when you configure the Venmo button or reference Venmo anywhere in your app.
Display the customer's Venmo username alongside their Venmo payment method in your checkout UI, the same way you'd display the last four digits of a credit card number.
Prerequisites
Before you start this integration, make sure you have:
A tokenization key or a client token from your server.
A button element in your checkout page to trigger the Venmo flow. The samples in this guide use an element with the id
venmo-button.
Support Venmo on mobile and desktop browsers
Customers pay with Venmo differently on mobile and desktop browsers. Enable the flows that match how your customers check out.
Set up the mobile flow
On mobile, customers authorize payment in the Venmo app. If the app isn't installed, they can log in on the web.
Authenticate with the Venmo app
On mobile, the default payment flow starts in the mobile web browser and switches to the Venmo app to authorize payment. After authorization, the app returns the customer to the browser and the SDK returns a payment method nonce. If the customer doesn't have the Venmo app installed, the flow directs them to the Venmo website to download the app.
Fall back to a mobile web login
This flow currently requires a full page redirect. To use it, make sure your page can handle the checkout session across different pages.
This configuration provides a web-based login experience for customers who don't have the Venmo app installed on their mobile device. When tokenization starts and the Venmo app isn't installed, customers see a popup where they log in to their Venmo account to authenticate.
To enable this flow, add the following parameter when you create the Venmo component:
mobileWebFallBack: true
Set up the desktop flow
Venmo offers two ways for customers to pay from a desktop browser: a QR code flow and a web login flow.
Use the desktop QR code flow
We recommend the desktop QR code flow over the desktop web login flow. It offers a better customer experience and improves conversion rates.
This configuration lets customers pay with Venmo from a desktop browser. A QR code displays in a modal over the website, and the customer scans it with their mobile device. After the customer authorizes the payment in the Venmo app on their mobile device, the browser receives a nonce on the desktop and dismisses the QR code.
To enable this flow, add the following parameter when you create the Venmo component:
allowDesktop: true
The allowDesktopWebLogin: true configuration takes precedence over allowDesktop: true. When you set both, customers see the desktop web login flow instead of the desktop QR code flow.
Use the desktop web login flow
This configuration lets customers pay with Venmo from a desktop browser by logging in to their Venmo account directly on the web and authorizing the payment.
The tokenize call starts the flow. It opens a browser popup with the Venmo web login page, where the customer logs in to Venmo and authorizes payment. After authorization, the popup closes and the SDK retrieves the nonce payload.
To enable this flow, add the following parameters when you create the Venmo component:
allowDesktopWebLogin: true
If you switch from the desktop QR code flow to the web login flow, remove the following parameter. The SDK ignores it in this flow:
allowDesktop: true
Install the SDK
To set up the Braintree JavaScript SDK, see the installation guide.
Then, load the venmo and data-collector components. If you're using script tags to load files, include at least:
- HTML
<script src="https://js.braintreegateway.com/web/4.0.0-alpha.0/js/client.min.js"></script>
<script src="https://js.braintreegateway.com/web/4.0.0-alpha.0/js/venmo.min.js"></script>
<script src="https://js.braintreegateway.com/web/4.0.0-alpha.0/js/data-collector.min.js"></script>Initialize the SDK
Initialize a
clientusing either a tokenization key or a client token from your server.Create a Venmo component.
- Async/Await
// Create a client.
async function setupVenmo() {
try {
const clientInstance = await braintree.client.create({
authorization: CLIENT-AUTHORIZATION
});
// Create a Venmo component.
const venmoInstance = await braintree.venmo.create({
client: clientInstance,
allowDesktop: true,
mobileWebFallBack: true,
allowDesktopWebLogin: true,
paymentMethodUsage: 'multi_use'
});
// ...
} catch (err) {
// Handle component creation error
}
}If setup succeeds, venmoInstance is ready to use for the flows described in the rest of this guide.
Verify mobile browser support
Verifying browser support includes steps to detect webviews that could be problematic depending on your use case. See Detect webviews for more details.
Venmo is compatible with most mobile browsers on Android and iOS, including webviews.
When customers return from the Venmo app, some mobile browsers return them to the same tab, while others relaunch your checkout page in a new tab. Each flow has tradeoffs:
Returning to the same tab is a more seamless customer experience, but only iOS Safari and Android Chrome support it.
Returning to a new tab works with most iOS and Android browsers, but it can break the checkout flow for some integrations, such as single-page applications.
To see which browsers and versions are supported, see the overview.
To verify browser support:
Determine if your checkout page supports returning to a new tab:
If it supports new tabs, call
hasTokenizationResult. If it returnstrue, calltokenizeto get the tokenization result immediately.If it doesn't support new tabs, pass
allowNewBrowserTabasfalsewhen you call Venmocreate.
Call
isBrowserSupportedto verify that the customer's browser supports Venmo.For desktop flow support, set
allowDesktop: truefor the QR code flow, orallowDesktopWebLogin: truefor the desktop web login flow.Show Venmo as a payment option if the browser is supported.
- Async/Await
const venmoButton = document.getElementById('venmo-button');
async function setupVenmo() {
try {
const venmoInstance = await braintree.venmo.create({
client: clientInstance,
allowDesktop: true,
mobileWebFallBack: true,
allowDesktopWebLogin: true,
paymentMethodUsage: 'multi_use'
// Add allowNewBrowserTab: false if your checkout page does not support
// relaunching in a new tab when returning from the Venmo app. This can
// be omitted otherwise.
// allowNewBrowserTab: false
});
// Verify browser support before proceeding.
if (!venmoInstance.isBrowserSupported()) {
console.log('Browser does not support Venmo');
return;
}
displayVenmoButton(venmoInstance);
// Check if tokenization results already exist. This occurs when your
// checkout page is relaunched in a new tab. This step can be omitted
// if allowNewBrowserTab is false.
if (venmoInstance.hasTokenizationResult()) {
try {
const payload = await venmoInstance.tokenize();
handleVenmoSuccess(payload);
} catch (err) {
handleVenmoError(err);
}
}
} catch (venmoErr) {
console.error('Error creating Venmo:', venmoErr);
}
}
function displayVenmoButton(venmoInstance) {
// Assumes that venmoButton is initially display: none.
venmoButton.style.display = 'block';
venmoButton.addEventListener('click', async function () {
venmoButton.disabled = true;
const payload = await venmoInstance.tokenize();
venmoButton.removeAttribute('disabled');
// ...
});
}
function handleVenmoError(err) {
// ...
}
function handleVenmoSuccess(payload) {
// ...
}If the browser doesn't support Venmo, isBrowserSupported returns false and the code logs Browser does not support Venmo to the console instead of displaying the button.
Download Venmo's brand guidelines and follow them when you configure the Venmo button or reference Venmo anywhere in your app.
Detect webviews
Current browser detection methods can't detect certain mobile browser configurations in every scenario.
The SDK uses user agents to detect which browsers support Pay with Venmo. In some scenarios, the SDK can't definitively determine whether an iOS browser environment is supported.
On iOS, the browser environments are:
iOS Safari.
Safari webviews, including third-party browsers such as Chrome and Firefox.
In-app browsers, also known as Safari View Controller.
If a web page is loaded from a third-party native iOS application, and that third-party app uses an in-app browser to load your page, the SDK can't currently distinguish this from a native browser.
This is a problem because when your page is loaded within one of these webviews from a third-party app, and the Venmo app opens automatically to authorize payment, the Venmo app can't return to your page within that third-party app. Instead, the Venmo native app launches, the customer authorizes payment, and the customer returns to your page in a new tab in their default native browser.
The checkout context that started the flow stays in the third-party app's webview. If your checkout page can handle the session changing contexts, this still works because you still have the nonce and customer details, but it moves the customer to the native browser from where they started.
This also creates an issue if you want to avoid webviews entirely. If you set allowWebviews: false when you create the Venmo component, isBrowserSupported can return false positives for browser support. For example:
- Async/Await
async function setupVenmo() {
const venmoInstance = await braintree.venmo.create({
client: clientInstance,
allowWebviews: false,
});
// ...
}Launch the Venmo payment flow
When the customer clicks the Venmo button, tokenize starts the flow. What the customer sees depends on their device and your configuration.
Launch the mobile flow
Add a
clickevent listener to the Venmo button that callstokenizeto start the payment flow.The customer must have the Venmo app installed to authorize payment. If it isn't installed,
tokenizeopens a new browser tab with a Venmo landing page.
If the app is installed, the customer is prompted to authorize the payment.
After authorization, the app returns the customer to the checkout page in the browser.
Launch the desktop QR code flow
Add a
clickevent listener to the Venmo button that callstokenizeto start the payment flow.The device scanning the QR code must have the Venmo app installed. If it isn't installed, scanning the QR code opens a new browser tab with a Venmo landing page.
If the app is installed, the customer is prompted to authorize the payment.
Launch the desktop web login flow
Add a
clickevent listener to the Venmo button that callstokenizeto start the payment flow. This opens a browser popup to the Venmo login page.The customer is prompted to log in and authorize payment.
After completion, the popup closes.
- Async/Await
function displayVenmoButton(venmoInstance) {
venmoButton.style.display = 'block';
venmoButton.addEventListener('click', async function () {
venmoButton.disabled = true;
try {
const payload = await venmoInstance.tokenize();
handleVenmoSuccess(payload);
} catch (err) {
handleVenmoError(err);
} finally {
venmoButton.removeAttribute('disabled');
}
});
}
function handleVenmoError(err) {
if (err.code === 'VENMO_CUSTOMER_CANCELED') {
console.log('User canceled payment flow');
} else {
console.error('An error occurred:', err.message);
}
}
function handleVenmoSuccess(payload) {
// Send payload.nonce to your server.
console.log('Got a payment method nonce:', payload.nonce);
// Display the Venmo username in your checkout UI.
console.log('Venmo user:', payload.details.username);
}On success, handleVenmoSuccess logs the payment method nonce and the customer's Venmo username to the console.
Specify payment method usage
You must specify how you'll use the customer's Venmo account by passing paymentMethodUsage in the create call:
multi_use: Request authorization for future payments. Vaulting is allowed.single_use: Request authorization for a one-time payment. Vaulting isn't allowed.
Payment method usage affects the customer flow. It:
Displays different phrases to the customer on the transaction consent page. For example, "Authorize
Business Nameto pay with Venmo" compared with "AuthorizeBusiness Nameto pay with Venmo for future purchases," whereBusiness Nameis the business name you submitted in the Venmo application form.Doesn't display a merchant connection on the Connected Businesses page in the Venmo app when
paymentMethodUsageissingle_use.Lets customers update their funding instrument on the Connected Businesses page in the Venmo app when
paymentMethodUsageismulti_use.
If paymentMethodUsage is single_use:
PayPal returns a validation error if you attempt to vault through PaymentMethod.create or Customer.create.
The transaction processes normally, but PayPal doesn't vault the nonce if you pass
store-in-vaultorstore-in-vault-on-successduring transaction.sale.
- Async/Await
async function setupVenmo() {
const venmoInstance = await braintree.venmo.create({
client: clientInstance,
paymentMethodUsage: 'multi_use'
});
// ...
}Handle multiple profiles
If you have a custom integration and you've onboarded multiple websites for Venmo processing with a single Braintree gateway, pass profile_id to specify which Venmo profile to present during the payment flow.
Also pass profile_id when you create the transaction on the server side.
- Async/Await
async function setupVenmo() {
const venmoInstance = await braintree.venmo.create({
client: clientInstance,
profileId: 'YOUR-VENMO-PROFILE-ID',
paymentMethodUsage: 'multi_use'
});
// ...
}If you have multiple business profiles, find the profile_id for each profile by logging in to the Control Panel. Click the gear icon in the top right corner, select Processing from the drop-down menu, scroll to Venmo, and click Options.
Collect device data
Collect information about the customer's device before you create each transaction.
- Async/Await
async function collectDeviceData() {
try {
const dataCollectorInstance = await braintree.dataCollector.create({
client: clientInstance,
});
// At this point, you should access the dataCollectorInstance.deviceData value and provide it
// to your server, for example by injecting it into your form as a hidden input.
const deviceData = dataCollectorInstance.deviceData;
} catch (err) {
// Handle component creation error
}
}dataCollectorInstance.deviceData now holds the value to send to your server.
Pass this deviceData when you create the Venmo transaction from your server.
Pass device data as close to transaction creation as possible. Doing so helps reduce decline rates.
Collect shipping and billing addresses
You can specify whether you want to receive a customer's Venmo shipping and billing address by passing the collectCustomerBillingAddress and collectCustomerShippingAddress flags during the create call. When you enable these flags, Venmo collects the required addresses from the customer and returns them in the response object.
To receive the shipping address, add the following parameter when you create the Venmo component:
collectCustomerShippingAddress: true
To receive the billing address, add the following parameter when you create the Venmo component:
collectCustomerBillingAddress: true
- Async/Await
async function setupVenmo() {
const venmoInstance = await braintree.venmo.create({
client: clientInstance,
paymentMethodUsage: 'multi_use',
collectCustomerBillingAddress: true,
collectCustomerShippingAddress: true
});
// ...
}You can only collect customer addresses if you have Enriched Customer Data (ECD) enabled in the Control Panel. For details on enabling ECD, see Venmo's Enriched Customer Data. PayPal returns a validation error if you attempt to collect customer addresses without enabling ECD.
After a successful create call, the response payload returns the shipping and billing addresses under a payerInfo object.
- JavaScript
function handleVenmoSuccess(payload) {
console.log('Got a payment method nonce:', payload.nonce);
// Display the shipping address:
// payload.details.payerInfo.shippingAddress = {
// addressLine1: "",
// addressLine2: "",
// adminArea2: "",
// adminArea1: "",
// postalCode: ""
// }
console.log("Venmo user shippingAddress:", payload.details.payerInfo.shippingAddress);
// Display the billing address:
// payload.details.payerInfo.billingAddress = {
// addressLine1: "",
// addressLine2: "",
// adminArea2: "",
// adminArea1: "",
// postalCode: ""
// }
console.log("Venmo user billingAddress:", payload.details.payerInfo.billingAddress);
}The code logs the shipping and billing addresses returned in payload.details.payerInfo to the console.
Add amounts and line items
If you make the create call in the context of a purchase, pass the total amount of the transaction. Venmo displays this amount to the customer on the Venmo paysheet.
You can also pass other transaction details to render to the customer, such as subtotal, discount, taxes, shipping amount, and line items.
- Async/Await
async function setupVenmo() {
const venmoInstance = await braintree.venmo.create({
client: clientInstance,
paymentMethodUsage: 'multi_use',
totalAmount: '10.00',
subTotalAmount: '8.00',
taxAmount: '1.00',
discountAmount: '1.00',
shippingAmount: '2.00',
lineItems: [
{
name: 'item-name',
quantity: 2,
unitAmount: '5.00',
type: 'DEBIT'
},
{
name: 'credited-item-name',
quantity: 1,
unitAmount: '2.00',
type: 'CREDIT'
}
]
});
// ...
}All amount and line-item fields are optional except totalAmount, which is required in the context of a purchase. If the create call is for vaulting only, you can omit totalAmount.
PayPal validates the transaction details you provide:
All amounts must be in USD.
All amounts must be non-negative.
All amounts must be strings containing either a whole number or a number with two decimal places.
Each line item must have four properties: item name, quantity, unit amount, and type.
Line-item
typemust be eitherCREDITorDEBIT.The amounts for all individual line items must add up to the total amount, or the subtotal when present.
All individual amounts, including discount, shipping, tax, and subtotal, must add up to the total amount.
Review the full example
This full example shows the integration between Braintree and Venmo. Use it as a starting point and a reference while you integrate into your existing codebase.
- Async/Await
const venmoButton = document.getElementById('venmo-button');
// Create a client.
async function setupVenmo() {
const clientInstance = await braintree.client.create({
authorization: CLIENT-AUTHORIZATION
});
// You may need to polyfill Promise
// if used on older browsers that
// do not natively support it.
const results = await Promise.all([
braintree.dataCollector.create({
client: clientInstance,
}),
braintree.venmo.create({
client: clientInstance,
allowDesktop: true,
paymentMethodUsage: 'multi_use'
// Add allowNewBrowserTab: false if your checkout page does not support
// relaunching in a new tab when returning from the Venmo app. This can
// be omitted otherwise.
// allowNewBrowserTab: false
})
]);
const dataCollectorInstance = results[0];
const venmoInstance = results[1];
// At this point, you should access the deviceData value and provide it
// to your server, for example by injecting it into your form as a hidden input.
console.log('Got device data:', dataCollectorInstance.deviceData);
// Verify browser support before proceeding.
if (!venmoInstance.isBrowserSupported()) {
console.log('Browser does not support Venmo');
return;
}
displayVenmoButton(venmoInstance);
// Check if tokenization results already exist. This occurs when your
// checkout page is relaunched in a new tab. This step can be omitted
// if allowNewBrowserTab is false.
if (venmoInstance.hasTokenizationResult()) {
try {
const payload = await venmoInstance.tokenize();
handleVenmoSuccess(payload);
} catch (err) {
handleVenmoError(err);
}
}
}
function displayVenmoButton(venmoInstance) {
// Assumes that venmoButton is initially display: none.
venmoButton.style.display = 'block';
venmoButton.addEventListener('click', async function () {
venmoButton.disabled = true;
try {
const payload = await venmoInstance.tokenize();
handleVenmoSuccess(payload);
} catch (err) {
handleVenmoError(err);
} finally {
venmoButton.removeAttribute('disabled');
}
});
}
function handleVenmoError(err) {
if (err.code === 'VENMO_CUSTOMER_CANCELED') {
console.log('User canceled payment flow');
} else {
console.error('An error occurred:', err.message);
}
}
function handleVenmoSuccess(payload) {
// Send the payment method nonce to your server, for example by injecting
// it into your form as a hidden input.
console.log('Got a payment method nonce:', payload.nonce);
// Display the Venmo username in your checkout UI.
console.log('Venmo user:', payload.details.username);
}