Google Pay API for Web 101: Basics

1. Introduction

What you'll build

At the completion of this codelab, you will have a minimum viable website with a working Google Pay integration. This project retrieves a payment token which may sent to a payment service provider for processing.

What you'll learn

  • How to load and configure the Google Pay API
  • How to display the Google Pay button and handle clicks
  • How to request a payment token from Google Pay

What you'll need

  • A text editor of your choice to edit HTML and JavaScript files.
  • The Google Chrome web browser, or another way to test a local website.
  • For production, you will need a Google Pay merchantId. It only takes a minute to register at Google Pay & Wallet Console so might as well take care of it now.

Follow along using Project IDX

Open this codelab in IDX

2. Create the HTML page

Create project files

  1. Create a folder on your computer named gpay-web-101 and inside that folder create two empty text files named index.html and main.js.Your directory structure should look like this:
    gpay-web-101/
      index.html
      main.js
    
  2. Open index.html in your IDE of choice and add the following code:
    <!doctype html>
    <html lang="en">
    
    <head>
      <meta charset="UTF-8" />
      <meta name="viewport" content="width=device-width, initial-scale=1.0" />
      <title>Google Pay API for Web 101</title>
    </head>
    
    <body>
      <div id="gpay-container"></div>
      <p>Transaction info and errors will be logged to the console.</p>
      <script type="text/javascript" src="main.js"></script>
      <script
        async src="https://pay.google.com/gp/p/js/pay.js"
        onload="onGooglePayLoaded()">
      </script>
    </body>
    
    </html>
    

Code explanation

  1. An empty DIV is added to the page with the ID gpay-container. This DOM element will be the parent element in which the Google Pay button is added. You may position this element in your website's layout where appropriate.
  2. The main.js script tag is placed in the DOM after the gpay-container element. This is necessary to ensure the container DIV is present in the DOM before the main.js queries for it. Additionally, the script is synchronous to ensure it is loaded before pay.js loads as onGooglePayLoaded() method must exist prior to load completion. There are other ways to achieve the same effect but they won't be discussed here.
  3. Finally, pay.js is loaded asynchronously and configures onGooglePayLoaded() as it's onload handler. This method will be defined in main.js.

3. Configure Google Pay

A Google Pay payment request requires a request object. The object defined here as baseGooglePayRequest contains the minimum common settings for all requests. Additional settings will be added depending on the request made which we'll review in this codelab.

Add the Google Pay configuration constants to the empty main.js file:

//=============================================================================
// Configuration
//=============================================================================

// The DOM element that the Google Pay button will be rendered into
const GPAY_BUTTON_CONTAINER_ID = 'gpay-container';

// Update the `merchantId` and `merchantName` properties with your own values.
// Your real info is required when the environment is `PRODUCTION`.
const merchantInfo = {
  merchantId: '12345678901234567890',
  merchantName: 'Example Merchant'
};

// This is the base configuration for all Google Pay payment data requests.
const baseGooglePayRequest = {
  apiVersion: 2,
  apiVersionMinor: 0,
  allowedPaymentMethods: [
    {
      type: 'CARD',
      parameters: {
        allowedAuthMethods: [
          "PAN_ONLY", "CRYPTOGRAM_3DS"
        ],
        allowedCardNetworks: [
          "AMEX", "DISCOVER", "INTERAC", "JCB", "MASTERCARD", "VISA"
        ]
      },
      tokenizationSpecification: {
        type: 'PAYMENT_GATEWAY',
        parameters: {
          gateway: 'example',
          gatewayMerchantId: 'exampleGatewayMerchantId'
        }
      }
    }
  ],
  merchantInfo
};

// Prevent accidental edits to the base configuration. Mutations will be
// handled by cloning the config using deepCopy() and modifying the copy.
Object.freeze(baseGooglePayRequest);

Code explanation

  1. Set the constant variable GPAY_BUTTON_CONTAINER_ID to the Id of the DOM element used on the HTML page as the parent container for the Google Pay button.
  2. Create the configuration object baseGooglePayRequest with relevant settings for your application. Each of the properties and values can be found in the reference documentation. The values shown in this example may or may not perfectly match your needs, so review carefully.
  3. Update the merchantId and merchantName properties with your own values. These fields are optional when the environment is TEST.

Resources

4. Add payments client

A payments client is used to make payment requests and register callbacks. In this codelab we will only make payment requests. Additionally, you may configure PaymentDataCallbacks to handle when payment data has changed or authorization has changed. However, these advanced topics are not covered in this codelab.

Append this client code to the bottom of main.js:

//=============================================================================
// Google Payments client singleton
//=============================================================================

let paymentsClient = null;

function getGooglePaymentsClient() {
  if (paymentsClient === null) {
    paymentsClient = new google.payments.api.PaymentsClient({
      environment: 'TEST',
      merchantInfo,
      // todo: paymentDataCallbacks (codelab pay-web-201)
    });
  }

  return paymentsClient;
}

Code explanation

  1. The paymentsClient variable will hold the instance to the client once its been created. The variable is not accessed directly by our code, but instead always by the getGooglePaymentsClient() method.
  2. The getGooglePaymentsClient() method checks to see if a client was already instantiated and returns that instance. If one was not previously instantiated then one is created, saved and returned. This method ensures that only one instance is created and used throughout the lifespan of this script.
  3. To instantiate a client, the PaymentsClient() method is invoked. In this example, we're telling the client that we are in a TEST environment. The alternative is PRODUCTION. However, TEST is default and may be omitted.

5. Add helpers

The following helper functions are used later in the script and have been added for the sole purpose of improved code readability and maintainability.

Append the helper functions to the bottom of main.js:

//=============================================================================
// Helpers
//=============================================================================

const deepCopy = (obj) => JSON.parse(JSON.stringify(obj));

function renderGooglePayButton() {
  const button = getGooglePaymentsClient().createButton({
    onClick: onGooglePaymentButtonClicked
  });

  document.getElementById(GPAY_BUTTON_CONTAINER_ID).appendChild(button);
}

Code explanation

  1. deepCopy() is a utility that uses JSON serialization and deserialization to create a deep copy of the provided object. It's a convenient way to clone objects without worrying about shared references.
  2. renderGooglePayButton() is a utility that invokes the createButton() library method to display the Google Pay button. The passed argument is a set of options that define how the button should behave such as registering onGooglePaymentButtonClicked() function to handle button clicks.

6. Add event handlers

In this script we're configuring two event handlers. The first is called when the pay.js library finishes loading and the other is called when the Google Pay button is clicked.

Append the event handlers to the bottom of main.js:

//=============================================================================
// Event Handlers
//=============================================================================

function onGooglePayLoaded() {
  const req = deepCopy(baseGooglePayRequest);

  getGooglePaymentsClient()
    .isReadyToPay(req)
    .then(function(res) {
      if (res.result) {
        renderGooglePayButton();
      } else {
        console.log("Google Pay is not ready for this user.");
      }
    })
    .catch(console.error);
}

function onGooglePaymentButtonClicked() {
  // Create a new request data object for this request
  const req = {
    ...deepCopy(baseGooglePayRequest),
    transactionInfo: {
      countryCode: 'US',
      currencyCode: 'USD',
      totalPriceStatus: 'FINAL',
      totalPrice: (Math.random() * 999 + 1).toFixed(2),
    },
    // todo: callbackIntents (codelab gpay-web-201)
  };

  // Write request object to console for debugging
  console.log(req);

  getGooglePaymentsClient()
    .loadPaymentData(req)
    .then(function (res) {
      // Write response object to console for debugging
      console.log(res);
      // @todo pass payment token to your gateway to process payment
      // @note DO NOT save the payment credentials for future transactions
      paymentToken = res.paymentMethodData.tokenizationData.token;
    })
    .catch(console.error);
}

Code explanation

  1. onGooglePayLoaded() is invoked when pay.js script has completed loading as defined in the HTML file. isReadyToPay() method is invoked to determine whether or not to show the Google Pay button. If the consumer is ready to pay (meaning they have added a form of payment to their Google Wallet) then the Google Pay button is rendered.
  2. onGooglePaymentButtonClicked() is invoked when the Google Pay button is clicked. This method invokes loadPaymentData() library method which is used to retrieve a payment token. Once you have the payment token you would send it to your payment gateway for processing the transaction. transactionInfo describes the transaction that should be processed with this button click.

7. Conclusion

Congratulations on completing this Codelab! You have learned how to integrate the Google Pay APi into a website.

Run the project

Test with Google Chrome

Using the Google Chrome web browser, open index.html using File > Open File... from Chrome's main menu. Chrome will execute main.js when the project is opened this way. Other web browsers might not allow JavaScript execution.

– or –

Test with a local web server

If you have Python installed, run python3 -m http.server from a terminal prompt in the root pay-web-101 folder.

$ cd /your/path/to/pay-web-101
$ python3 -m http.server
Serving HTTP on :: port 8000 (http://[::]:8000/) ...

Then, visit your site at http://localhost:8000.

Where to go from here

Additional resources