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.

PrerequisitesAnchorIcon

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 browsersAnchorIcon

Customers pay with Venmo differently on mobile and desktop browsers. Enable the flows that match how your customers check out.

Set up the mobile flowAnchorIcon

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 appAnchorIcon

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 loginAnchorIcon

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 flowAnchorIcon

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 flowAnchorIcon

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 flowAnchorIcon

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:

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 SDKAnchorIcon

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:

  1. 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 SDKAnchorIcon

  1. Initialize a client using either a tokenization key or a client token from your server.

  2. Create a Venmo component.

  1. 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 supportAnchorIcon

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:

  1. Determine if your checkout page supports returning to a new tab:

    • If it supports new tabs, call hasTokenizationResult. If it returns true, call tokenize to get the tokenization result immediately.

    • If it doesn't support new tabs, pass allowNewBrowserTab as false when you call Venmo create.

  2. Call isBrowserSupported to verify that the customer's browser supports Venmo.

  3. For desktop flow support, set allowDesktop: true for the QR code flow, or allowDesktopWebLogin: true for the desktop web login flow.

  4. Show Venmo as a payment option if the browser is supported.

  1. 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.

Detect webviewsAnchorIcon

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:

  1. Async/Await
async function setupVenmo() {
  const venmoInstance = await braintree.venmo.create({
    client: clientInstance,
    allowWebviews: false,
  });
  // ...
}

Launch the Venmo payment flowAnchorIcon

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 flowAnchorIcon

  1. Add a click event listener to the Venmo button that calls tokenize to start the payment flow.

    • The customer must have the Venmo app installed to authorize payment. If it isn't installed, tokenize opens a new browser tab with a Venmo landing page.

  2. If the app is installed, the customer is prompted to authorize the payment.

  3. After authorization, the app returns the customer to the checkout page in the browser.

Launch the desktop QR code flowAnchorIcon

  1. Add a click event listener to the Venmo button that calls tokenize to 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.

  2. If the app is installed, the customer is prompted to authorize the payment.

Launch the desktop web login flowAnchorIcon

  1. Add a click event listener to the Venmo button that calls tokenize to start the payment flow. This opens a browser popup to the Venmo login page.

  2. The customer is prompted to log in and authorize payment.

  3. After completion, the popup closes.

  1. 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 usageAnchorIcon

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 Name to pay with Venmo" compared with "Authorize Business Name to pay with Venmo for future purchases," where Business Name is 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 paymentMethodUsage is single_use.

  • Lets customers update their funding instrument on the Connected Businesses page in the Venmo app when paymentMethodUsage is multi_use.

  1. Async/Await
async function setupVenmo() {
  const venmoInstance = await braintree.venmo.create({
    client: clientInstance,
    paymentMethodUsage: 'multi_use'
  });
  // ...
}

Handle multiple profilesAnchorIcon

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.

  1. Async/Await
async function setupVenmo() {
  const venmoInstance = await braintree.venmo.create({
    client: clientInstance,
    profileId: 'YOUR-VENMO-PROFILE-ID',
    paymentMethodUsage: 'multi_use'
  });
  // ...
}

Collect device dataAnchorIcon

Collect information about the customer's device before you create each transaction.

  1. 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.

Collect shipping and billing addressesAnchorIcon

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

  1. Async/Await
async function setupVenmo() {
  const venmoInstance = await braintree.venmo.create({
    client: clientInstance,
    paymentMethodUsage: 'multi_use',
    collectCustomerBillingAddress: true,
    collectCustomerShippingAddress: true
  });
  // ...
}

After a successful create call, the response payload returns the shipping and billing addresses under a payerInfo object.

  1. 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 itemsAnchorIcon

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.

  1. 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'
      }
    ]
  });
  // ...
}

Review the full exampleAnchorIcon

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.

  1. 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);
}