Build a fast checkout experience on the web with Google Pay

The Google Pay API gives users the opportunity to pay everywhere, using the payment information stored in their Google Accounts. In this lab, you make use of Google Pay's client library for web to improve the checkout experience of a simplified sample online store, by creating a faster, more convenient, and safer experience, which in turn leads to more conversions and happier customers.

Auto T-Shirt Shop is an innovative store that leverages the latest advances in artificial intelligence and uses information like style preferences, weather, time of the year, and fashion trends to suggest the most appropriate item for you to purchase.

Metrics on engagement for this store are through the roof. Unfortunately, the metrics also reflect a large number of abandonments during the checkout process. Determined to tackle that, one of the owners of the project recalls having seen a video showing the promising results that Google Pay yielded for similar sites, so they decide to give it a go and trust you to take care of the integration.

What you will build

This codelab walks you through integrating Google Pay into an existing site, including determining whether a user is able to pay using a payment method supported by Google Pay, the placement and design of the payment button, and the execution of the transaction.

What you'll learn

  • How to integrate Google Pay into an existing checkout page
  • How to choose among your preferred payment methods
  • How to determine whether a user is ready to pay with Google Pay

What you will need

  • A computer with internet access
  • Basic knowledge of JavaScript

Run the sample site on glitch.com

In order to get up and running as quickly as possible, this codelab has been made available on glitch.com. Glitch is a free web-based environment that provides a code editor and hosting and deployment features that you can use to build and serve web applications.

To get started, use the button below to provision a new development environment on Glitch already set up with a copy of this codelab.

Start development environment on Glitch.com

From here on, you can use the code editor on Glitch to modify your files. Start serving your application by using the Show menu at the top, and choose In a New Window.

Skim through the sample site

As you can see, the repository features an uncomplicated file structure. The primary objective of this codelab is to give you the ability to adapt this integration to your existing and future applications, independent of the framework, libraries, or tools you choose to work with.

Explore the site

This demo marketplace has been built in such a way that it humbly resembles how your existing or potential application might look today, before you add a means of purchase. In fact, even though we recommend that you work on top of this demo application, you are free to go ahead and use this codelab to integrate Google Pay into your existing applications.

Now, if you have not already done so, open the demo site as it currently stands. To do that, click the Show button if you are using Glitch or open the URL where your local web server is running.

The demo site is nothing surprising, right? A product detail page, with a picture, the price, a description, some selectors, and a button to take you to an imaginary and ordinary payment form.

The objective of this lab is to replace this flow with a two-click experience powered by Google Pay.

Let's plan this!

To better understand this integration, the process is broken into the following fundamental steps:

  1. Load the library
  2. Determine ability to pay with Google Pay
  3. Show the button to pay with Google Pay
  4. Create and send the request for payment
  5. Collect the results

Add the script tag

The first thing you need to do in order to start using the Google Pay API is load the JavaScript library. To do that, include a script tag in the HTML file from where you are intending to call the API, including a src attribute that points to the external JavaScript library.

For this codelab, open the index.html file. You should see that the script tag has already been included for you:

<script async
  src="https://pay.google.com/gp/p/js/pay.js"
  onload="onGooglePayLoaded()">
</script>

In addition to src, you have added two other attributes.

  • async allows your script to be loaded and executed asynchronously alongside the rest of the page, so that the first load time of your document is unaffected.
  • onload helps you to defer the execution of code that depends on this library until your script has been loaded. After this is done, the function you specify in this attribute is run. In this case, the function is onGooglePayLoaded.

Instantiate the API client

Once your script has loaded, everything is set for you to start using this library. Start by instantiating the client object, which you will use to make calls to the Google Pay API later on.

Edit the index.js file, which is already part of the file structure in this project. Replace the onGooglePayLoaded function with the following code.

let googlePayClient;
function onGooglePayLoaded() {
  googlePayClient = new google.payments.api.PaymentsClient({
    environment: 'TEST'
  });
}

The payment client is initialized with a PaymentOptions object. Setting the environment to TEST allows you to experiment with dummy payment information across the entire integration. When you are ready to create operations that support real transactions, you can update the environment property to PRODUCTION.

Overview

We have now loaded the Google Pay API Javascript Client Library. Now, let's configure it to make API calls for us.

All of the following code changes for the rest of the codelab, will be made to the index.js file.

The skeleton

Every time you communicate with the Google Pay API, there are a number of configuration parameters that you need to include in your requests, such as the version of the API you are targeting. For the purpose of this codelab, this object also contains information about the payment methods accepted in your application. The final structure looks like the following:

{
  apiVersion: number,
  apiVersionMinor: number,
  allowedPaymentMethods: Array
}

The property allowedPaymentMethods takes a list of payment methods. For every payment method, you are required to include the following properties:

{
  type: 'CARD',
  parameters: {
    allowedCardNetworks: Array.<string>,
    allowedAuthMethods: Array.<string>
  }
}

Only the properties type and parameters are required to determine whether the user in question is able to pay with Google Pay.

The payment method configuration

In this example, you are only going to accept one configuration, allowing card payments for Mastercard and Visa, both in a tokenized and primary account number (PAN) forms.

This is how your configuration should be set up in index.js:

const baseCardPaymentMethod = {
  type: 'CARD',
  parameters: {
    allowedCardNetworks: ['VISA','MASTERCARD'],
    allowedAuthMethods: ['PAN_ONLY','CRYPTOGRAM_3DS']
  }
};

Putting it all together

Let's recap.

You have defined one payment method to be accepted in your website, and you are going to work with version 2.0 of the API. This is how the resulting configuration should look:

const baseCardPaymentMethod = {
  type: 'CARD',
  parameters: {
    allowedCardNetworks: ['VISA','MASTERCARD'],
    allowedAuthMethods: ['PAN_ONLY','CRYPTOGRAM_3DS']
  }
};

const googlePayBaseConfiguration = {
  apiVersion: 2,
  apiVersionMinor: 0,
  allowedPaymentMethods: [baseCardPaymentMethod]
};

Now that you have your base configuration ready, let's get to the fun part.

One of the main objectives of Google Pay is to provide a faster and more convenient checkout experience to your users. This not only applies to situations in which a person is able to use Google Pay, but also in situations where they are not able to do so. Using the isReadyToPay request allows you to determine readiness to pay with Google Pay and an opportunity for you to modify the experience in your site accordingly.

Is your user able to pay with Google Pay?

The first thing that you need to do is check whether a specific user who is about to pay on your site is able to use Google Pay to do so. This request requires you to specify the version of the Google Pay API and allowed payment methods for your site. This is exactly what the base configuration object defined in the previous step contains.

In index.js inside the onGooglePayLoaded() function, paste the following:

googlePayClient.isReadyToPay(googlePayBaseConfiguration)
  .then(function(response) {
    if(response.result) {
      createAndAddButton();
    } else {
      alert("Unable to pay using Google Pay");
    }
  }).catch(function(err) {
    console.error("Error determining readiness to use Google Pay: ", err);
  });

If the call fails or returns with an unsuccessful response, there is no further action to be taken in the context of Google Pay. In this situation, the most appropriate next step would be to show additional UI that supports other means of payment.

On the other hand, if the response is successful, you are now ready to allow your users to benefit from using Google Pay, and thus, you can go ahead and add a button to initiate the payment process on user activation (for example, button click).

Add a button to pay with Google Pay

Even though you can use any button that follows the Google Pay brand guidelines to start the payment process, we recommend that you generate one using the Google Pay API. This way, you not only ensure an accurate use of the brand guidelines, but you also benefit from other improvements built directly into the button, such as localization.

To generate a button, use the createButton method in the PaymentsClient object, including ButtonOptions to configure the button.

In index.js inside the createAndAddButton() function, paste the following:

function createAndAddButton() {

  const googlePayButton = googlePayClient.createButton({

    // currently defaults to black if default or omitted
    buttonColor: 'default',

    // defaults to long if omitted
    buttonType: 'long',

    onClick: onGooglePaymentsButtonClicked
  });

  document.getElementById('buy-now').appendChild(googlePayButton);
}

function onGooglePaymentsButtonClicked() {
  // TODO: Perform transaction
}

The only required property when using createButton is onClick, which is necessary to determine the callback object or function to trigger every time your users activate the button. buttonColor and buttonType allow you to customize how your button looks. Tweak them accordingly based on the theme and UI requirements of your application.

Once the button is created, all you need to do is add it to an appropriate node within the DOM. In this example, a div node identified with buy-now is used for this purpose.

See that you also defined a function to handle button click events. In the next section, you use this function to request a payment method.

Prepare the payment request

At this point, you have loaded the Google Pay API and determined that the user of your site is able to use Google Pay to make a payment. As a result, you have shown the Google Pay payment button in the UI and now your user is ready to initiate the transaction. It is now time to load the final payments sheet containing the forms of payment available for the different logged-in users.

Just like you did before, during the definition of the isReadyToPay request, this call also requires the properties in the base configuration object defined earlier (apiVersion, apiVersionMinor and allowedPaymentMethods) in addition to some new ones. This time, there is a new property, tokenizationSpecification, and additional parameters in your payment methods that are relevant for the purpose of this request. In addition, transactionInfo and merchantInfo need to be added.

Include additional required information in your payment methods

Start by creating a copy of the base card payment method used before. This card payment method now requires a tokenizationSpecification property to define how to handle the data related to the payment method selected, as well as further data requirements needed for the actual transaction: in this example, a full billing address and phone number.

The tokenizationSpecification property

The tokenization specification determines how the payment method selected by your customers is handled and used to complete a transaction.

There are two different types of handling strategies supported. If you are processing the payment transaction from within your PCI DSS compliant servers, use the DIRECT specification type. In this example, you use a payment gateway to process the payment, hence, you set the PAYMENT_GATEWAY specification type.

In index.js inside the onGooglePaymentsButtonClicked() function, paste the following:

const tokenizationSpecification = {
  type: 'PAYMENT_GATEWAY',
  parameters: {
    gateway: 'example',
    gatewayMerchantId: 'gatewayMerchantId'
  }
};

In the parameters section, you can specify a gateway from the list of providers supported by the Google Pay API, along with additional configuration required by each gateway. For the purpose of this lab, it is sufficient to use the example gateway, which yields test results for the transactions executed.

Additional parameters

Similarly, you can now provide more details about the information that you need to request in order to successfully place the transaction. See how in this example, you need to add the properties billingAddressRequired and billingAddressParameters, to indicate that for this transaction the billing address of the user is required in full format, including a phone number.

In index.js inside the onGooglePaymentsButtonClicked() function, paste the following:

const cardPaymentMethod = {
  type: 'CARD',
  tokenizationSpecification: tokenizationSpecification,
  parameters: {
    allowedCardNetworks: ['VISA','MASTERCARD'],
    allowedAuthMethods: ['PAN_ONLY','CRYPTOGRAM_3DS'],
    billingAddressRequired: true,
    billingAddressParameters: {
      format: 'FULL',
      phoneNumberRequired: true
    }
  }
};

Adding information about the transaction

The transactionInfo property contains an object with financial details about the transaction, namely the price and currency code (ISO 4217 alpha format) along with the status of the price, which can be either final or estimated depending on the nature of the transaction (for example, the price may vary depending on the shipping address specified).

In index.js inside the onGooglePaymentsButtonClicked() function, paste the following:

const transactionInfo = {
  totalPriceStatus: 'FINAL',
  totalPrice: '123.45',
  currencyCode: 'USD'
};

Adding information about the merchant

The payment request takes information about the merchant performing the request under the merchantInfo property. In this codelab, you will focus on two of them:

  • merchantId expects the identifier associated to your account once your site is approved to operate in production by Google. Note that this not evaluated while using the TEST environment.
  • merchantName is a user-visible name of your site or organization. This may be shown inside of the Google Pay payment sheet to provide users with more information about who is requesting the operation.

In index.js inside the onGooglePaymentsButtonClicked() function, paste the following:

const merchantInfo = {
  // merchantId: '01234567890123456789', Only in PRODUCTION
  merchantName: 'Example Merchant Name'
};

Request payment information and process the result

Now, merge the previously defined configuration into the final paymentDataRequest object.

In index.js inside the onGooglePaymentsButtonClicked() function, paste the following:

const paymentDataRequest = Object.assign({}, googlePayBaseConfiguration, {
  allowedPaymentMethods: [cardPaymentMethod],
  transactionInfo: transactionInfo,
  merchantInfo: merchantInfo   
});

At this point, you have everything you need to ask the Google Pay API for a valid form of payment. To do that, use the loadPaymentData method in the PaymentsClient object, passing in the configuration that you just defined.

In index.js inside the onGooglePaymentsButtonClicked() function, paste the following:

googlePayClient
  .loadPaymentData(paymentDataRequest)
  .then(function(paymentData) {
    processPayment(paymentData);
  }).catch(function(err) {
    // Log error: { statusCode: CANCELED || DEVELOPER_ERROR }
  });

Calling the loadPaymentData method triggers the presentation of the Google Pay payment sheet. If there are no configuration errors, you can see a list of valid payment methods associated with the currently logged-in account.

Upon selection, the sheet closes and the Promise is fulfilled with a PaymentData object including relevant information about the payment method selected:

{
  "apiVersionMinor": 0,
  "apiVersion": 2,
  "paymentMethodData": {
    "description": "Visa •••• 1234",
    "tokenizationData": {
      "type": "PAYMENT_GATEWAY",
      "token": "examplePaymentMethodToken"
    },
    "type": "CARD",
    "info": {
      "cardNetwork": "VISA",
      "cardDetails": "1234",
      "billingAddress": {
        "phoneNumber": ...,
        ...
      }
    }
  }
}

You can now use this payment method information to perform the actual transaction.

function processPayment(paymentData) {
  // TODO: Send a POST request to your processor with the payload
  // https://us-central1-devrel-payments.cloudfunctions.net/google-pay-server 
  // Sorry, this is out-of-scope for this codelab.
  return new Promise(function(resolve, reject) {
    // @todo pass payment token to your gateway to process payment
    const paymentToken = paymentData.paymentMethodData.tokenizationData.token;
    console.log('mock send token ' + paymentToken + ' to payment processor');
    setTimeout(function() {
      console.log('mock response from processor');
      alert('done');
      resolve({});
    }, 800);
  });
}

So far, we've looked at transactions with fixed payment amounts. But suppose that you want to update the price based on the selection of certain properties of the transaction (for example, the shipping details). You can achieve this by supplying the paymentDataCallback parameter when constructing the client. This callback is used for you to handle changes on the transaction and to apply modifications accordingly. You can listen to changes on the shipping address, shipping option, and payment method selected. In this example, you are going to listen for changes to the shipping option selected. First up, define the variables containing all of the shipping information, and modify paymentDataRequest to include them:

const shippingOptionParameters = {
  shippingOptions: [
    {
      id: 'shipping-001',
      label: '$1.99: Standard shipping',
      description: 'Delivered on May 15.'
    },
    {
      id: 'shipping-002',
      label: '$3.99: Expedited shipping',
      description: 'Delivered on May 12.'
    },
    {
      id: 'shipping-003',
      label: '$10: Express shipping',
      description: 'Delivered tomorrow.'
    }
  ]
};

// Shipping surcharges mapped to the IDs above.
const shippingSurcharges = {
  'shipping-001': 1.99,
  'shipping-002': 3.99,
  'shipping-003': 10
};

...

// Place inside of onGooglePaymentsButtonClicked()
paymentDataRequest.shippingAddressRequired = true;
paymentDataRequest.shippingOptionRequired = true;
paymentDataRequest.callbackIntents = ['SHIPPING_OPTION'];
paymentDataRequest.shippingOptionParameters =  shippingOptionParameters;

Next, you modify the creation of the googlePayClient to include a paymentDataCallback, which is called whenever a modification included in the callbackIntents is made to the payment operation. This callback includes an object with the properties changed. You can use these changes to construct an updated payment transaction:

function onGooglePayLoaded() {
  googlePayClient = new google.payments.api.PaymentsClient({
    paymentDataCallbacks: { onPaymentDataChanged: paymentDataCallback },
    environment: 'TEST'
  });
  ...
}

function paymentDataCallback(callbackPayload) {

  const selectedShippingOptionId = callbackPayload.shippingOptionData.id;
  const shippingSurcharge = shippingSurcharges[selectedShippingOptionId];
  const priceWithSurcharges = 123.45 + shippingSurcharge;

  return {
    newTransactionInfo: {
      totalPriceStatus: 'FINAL',
      totalPrice: priceWithSurcharges.toFixed(2),
      totalPriceLabel: 'Total',
      currencyCode: 'USD',
      displayItems: [
        {
          label: 'Subtotal',
          type: 'SUBTOTAL',
          price: priceWithSurcharges.toFixed(2),
        },
        {
          label: 'Shipping',
          type: 'LINE_ITEM',
          price: shippingSurcharge.toFixed(2),
          status: 'FINAL'
        }]
    }
  }
};

Upon return of this new object in the callback, the information presented in the payment sheet is updated to reflect the modifications made to the transaction.

Now that you have tested that the integration works adequately, you can go one step further and prefetch your payment configuration as soon as you have determined that Google Pay can be used. This happens before the user would activate (click) the Google Pay payment button.

If you prefetch the payment data, by the time your user decides to pay, the information that the sheet needs in order to load will already be available, significantly reducing the load time, and therefore improving the overall experience.

This method expects the same input as loadPaymentData. That is, you can use the same paymentDataRequest object defined before. Now, all you need to do is include a call to the prefetch method as soon as you have determined that the user can use Google Pay, after isReadyToPay returns successfully:

googlePayClient.isReadyToPay(googlePayBaseConfiguration)
  .then(function(response) {
    if(response.result) {
      createAndAddButton();
      googlePayClient.prefetchPaymentData(paymentDataRequest);
    }
  });

Just like that, you have reduced load time by prefetching payment data before the user clicked the button. The improved responsiveness of your site should improve your conversion rate.

You have successfully integrated Google Pay API into the sample site in this codelab or your own application.

Now, to take this into production, do not forget to take a look at the integration checklist. Once completed and reviewed, you will receive a merchant identifier to add to your client configuration. Similarly, if you are planning to use (or are already using) a third-party payment processor or gateway, check out the list of supported providers on Google Pay and configure yours. If you are integrating with Google Pay directly, take a look at the documentation section on this topic.

What we've covered

  • Import and configure the Google API in your site.
  • Determine support for the API and react accordingly.
  • Add a button to allow users to pay using Google Pay.
  • Load and process previously stored user payment information.
  • Optimize load time by prefetching payment information.

Next steps

  • Learn more about Google Pay.
  • Review the integration checklist and obtain a merchant identifier.
  • Look at the two different types of integration and decide what suits you better: integrating directly or using a payment gateway or processor.
  • Set up Authorize Payments to start the payment process and acknowledge a payment's authorization status. (Auth or Decline)

Learn more

Did you find this useful?

Very useful! Just enough to meet expectations. Not really.

Would you like to see other codelabs to help you with other types of integration (Android, direct integration, loyalty APIs) ?

Yes please, that'd be grand! I'm happy with what I got.