Learn how to use the Google Pay component for Web in your project.
Every component follows the same basic three-step lifecycle:
- Create the component and optionally add your own configuration.
- Mount the component. This is what makes the component visible and interactive.
- Unmount the component. This is a clean-up step that clears up resources.
To use the Google Pay component, you first need to:
- Install Components for Web.
- Complete the Google Pay onboarding process in the Unity Portal. See Onboarding for details.
- Ensure your website is served over HTTPS (required for Google Pay).
- Configure your Google Pay merchant account and link it to the Unity Portal.
Google Pay for Web has specific requirements for optimal functionality.
- Chrome 61+ on all platforms
- Safari 12.1+ on macOS and iOS
- Firefox 62+ on all platforms
- Edge 79+ on Windows and macOS
- Android devices: Android 5.0 (Lollipop) or later
- iOS devices: iOS 12.1 or later
- Desktop: Windows 7+, macOS 10.11+, or Linux
- The customer must have a supported payment method saved in their Google account.
- For biometric authentication, the device must support fingerprint or face recognition.
To get started, initialise the Checkout SDK with Google Pay support.
import { PxpCheckout } from '@pxpio/web-components-sdk';
const pxpSdk = PxpCheckout.initialize({
environment: 'test', // or 'live' for production
session: {
sessionId: 'your-session-id',
hmacKey: 'your-hmac-key',
encryptionKey: 'your-encryption-key'
},
ownerId: 'your-owner-id',
ownerType: 'MerchantGroup',
kountDisabled: false, // OPTIONAL: Set to true to disable Kount fraud detection
transactionData: {
currency: 'EUR',
amount: 25.00,
merchantTransactionId: crypto.randomUUID(),
merchantTransactionDate: () => new Date().toISOString(),
entryType: 'Ecom',
intent: {
card: 'Authorisation'
}
},
onGetShopper: () => {
// Return current shopper data dynamically
return Promise.resolve({
id: 'shopper-' + Date.now(),
email: 'customer@example.com',
firstName: 'John',
lastName: 'Doe'
});
}
});| Property | Description |
|---|---|
environmentstring required | The environment type. Possible values:
|
sessionsessionData required | Details about the checkout session. |
session.sessionIdstring required | The unique session identifier. |
session.hmacKeystring required | The HMAC key for session validation. |
session.encryptionKeystring required | The encryption key for secure data transmission. |
ownerIdstring required | The identifier of the owner related to the ownerType. |
ownerTypestring required | The type of owner. Possible values:
|
onGetShopperfunction | Callback function to provide shopper data dynamically. Returns a Promise with shopper information including ID, email, name, and contact details. |
transactionDataobject required | Details about the transaction. |
transactionData.currencystring (3 characters) required | The currency code associated with the transaction, in ISO 4217 format. |
transactionData.amountnumber required | The transaction amount. |
transactionData.entryTypestring required | The entry type. Possible values:
|
transactionData.intentobject required | The transaction intent. Possible values for card:
|
transactionData.merchantTransactionIdstring required | A unique identifier for this transaction. |
transactionData.merchantTransactionDatefunction required | A function that returns the date and time of the transaction, in ISO 8601 format. |
Next, you're going to create the Google Pay component configuration.
The SDK automatically configures tokenizationSpecification with the correct gateway and merchant ID from your session. You only need to provide allowedPaymentMethods with the card parameters.
const config = {
paymentDataRequest: {
allowedPaymentMethods: [{
type: 'CARD',
parameters: {
allowedCardNetworks: ['VISA', 'MASTERCARD', 'AMEX'],
allowedAuthMethods: ['PAN_ONLY', 'CRYPTOGRAM_3DS']
}
}],
transactionInfo: {
currencyCode: 'EUR',
totalPriceStatus: 'FINAL',
totalPrice: '25.00',
totalPriceLabel: 'Total',
displayItems: [
{
label: 'Product',
type: 'LINE_ITEM',
price: '20.00',
status: 'FINAL'
},
{
label: 'Tax',
type: 'TAX',
price: '5.00',
status: 'FINAL'
}
]
}
},
style: {
type: 'buy',
color: 'default',
height: '48px',
borderRadius: 4
},
onPreAuthorisation: async (data) => {
console.log('Pre-authorisation started');
return {
// Transaction initialisation data
};
},
onPostAuthorisation: async (result, paymentData) => {
console.log('Payment completed');
console.log('Merchant Transaction ID:', result.merchantTransactionId);
console.log('System Transaction ID:', result.systemTransactionId);
if (result && 'merchantTransactionId' in result) {
// Success - MerchantSubmitResult
// Use merchantTransactionId & systemTransactionId to get transaction details from Unity
window.location.href = '/payment-success';
}
},
onError: (error) => {
console.error('Google Pay error:', error);
}
};| Parameter | Description |
|---|---|
paymentDataRequestobject required | Google Pay payment request configuration. |
paymentDataRequest.allowedPaymentMethodsarray of objects required | Specifies support for one or more payment methods. |
paymentDataRequest.allowedPaymentMethods.typestring required | The payment method type. Currently only CARD is supported. |
paymentDataRequest.allowedPaymentMethods.parameters.allowedCardNetworksarray of strings required | Supported card networks. Possible values:
|
paymentDataRequest.allowedPaymentMethods.parameters.allowedAuthMethodsarray of strings required | Supported authentication methods. Possible values:
|
paymentDataRequest.allowedPaymentMethods.parameters.billingAddressRequiredboolean | Whether to request billing address. Default is false. |
paymentDataRequest.allowedPaymentMethods.parameters.billingAddressParametersobject | Billing address parameters when required. |
paymentDataRequest.allowedPaymentMethods.parameters.billingAddressParameters.formatstring | Address format. Possible values:
|
paymentDataRequest.allowedPaymentMethods.parameters.billingAddressParameters.phoneNumberRequiredboolean | Whether phone number is required with billing address. Default is false. |
paymentDataRequest.transactionInfoobject | Transaction details. |
paymentDataRequest.transactionInfo.currencyCodestring (3 characters) required | The currency code, in ISO 4217 format. |
paymentDataRequest.transactionInfo.countryCodestring (2 characters) | The country code, in ISO 3166-1 alpha-2 format. |
paymentDataRequest.transactionInfo.totalPriceStatusstring required | The status of the total price. Possible values:
|
paymentDataRequest.transactionInfo.totalPricestring required | The total amount as a string with decimal precision. |
paymentDataRequest.transactionInfo.totalPriceLabelstring | A label for the total price. |
paymentDataRequest.transactionInfo.displayItemsarray of objects | Individual line items for the transaction. |
paymentDataRequest.transactionInfo.displayItems.labelstring required | The display name for the line item. |
paymentDataRequest.transactionInfo.displayItems.typestring required | The line item type. Possible values:
|
paymentDataRequest.transactionInfo.displayItems.pricestring required | The line item amount as a string. |
paymentDataRequest.transactionInfo.displayItems.statusstring | The line item status. Possible values:
|
paymentDataRequest.emailRequiredboolean | Whether to request email address. Default is false. |
paymentDataRequest.shippingAddressRequiredboolean | Whether to request shipping address. Default is false. |
paymentDataRequest.shippingAddressParametersobject | Shipping address parameters when required. |
paymentDataRequest.shippingAddressParameters.allowedCountryCodesarray of strings | Allowed country codes for shipping. |
paymentDataRequest.shippingAddressParameters.phoneNumberRequiredboolean | Whether phone number is required with shipping address. |
paymentDataRequest.shippingOptionRequiredboolean | Whether to request shipping option selection. Default is false. |
paymentDataRequest.shippingOptionParametersobject | Shipping option parameters when required. |
paymentDataRequest.shippingOptionParameters.defaultSelectedOptionIdstring | The default selected shipping option ID. |
paymentDataRequest.shippingOptionParameters.shippingOptionsarray of objects | Available shipping options. |
paymentDataRequest.shippingOptionParameters.shippingOptions.idstring required | Unique identifier for the shipping option. |
paymentDataRequest.shippingOptionParameters.shippingOptions.labelstring required | The display name for the shipping option. |
paymentDataRequest.shippingOptionParameters.shippingOptions.descriptionstring | Additional details about the shipping option. |
paymentDataRequest.callbackIntentsarray of strings | Callback intents for dynamic updates. Possible values:
Note: PAYMENT_AUTHORIZATION is automatically added by the SDK and does not need to be specified. |
styleobject | Button styling configuration. |
style.typestring | The button type. Possible values:
|
style.colorstring | The button color. Possible values:
|
style.heightstring | The button height (e.g., '44px', '48px'). |
style.widthstring | The button width (e.g., '100%', '240px'). |
style.borderRadiusnumber | The button border radius in pixels. |
style.sizeModestring | The button size mode. Possible values:
|
existingPaymentMethodRequiredboolean | Whether to require the user to have an existing payment method. Default is false. |
collectCvcstring | CVC collection mode. Possible values:
|
For a complete configuration reference with all available options, see Configuration.
Create an HTML container where the Google Pay button will be mounted.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Google Pay Checkout</title>
</head>
<body>
<div class="checkout-container">
<h2>Complete your purchase</h2>
<div class="payment-summary">
<div class="item">
<span>Product</span>
<span>€20.00</span>
</div>
<div class="item">
<span>Tax</span>
<span>€5.00</span>
</div>
<hr>
<div class="total">
<span>Total</span>
<span>€25.00</span>
</div>
</div>
<!-- Google Pay button container -->
<div id="google-pay-container" style="margin: 20px 0;"></div>
<div class="alternative-payments">
<p>Or pay with card</p>
<!-- Other payment methods -->
</div>
</div>
</body>
</html>For the component to be visible and functional, you need to mount it. Make sure to supply both the component configuration and the container ID.
const googlePayButton = pxpSdk.create('google-pay-button', config);
googlePayButton.mount('google-pay-container');At this point, your Google Pay button is ready to use and will appear in the specified container.
The component will automatically handle the payment flow. You can listen for payment results through the callback functions. For complete event handler reference and callback data structures, see Events.
const config = {
// ... other configuration
onPreAuthorisation: async (data) => {
// Called before payment authorisation
console.log('Pre-authorisation started');
return {
// Optional: Add risk screening data, PSD2 exemptions, etc.
riskScreeningData: {
// Kount risk screening data
},
psd2Data: {
scaExemption: 'LowValue' // Optional PSD2 SCA exemption
}
};
},
onPostAuthorisation: async (result, paymentData) => {
console.log('Payment completed');
console.log('Merchant Transaction ID:', result.merchantTransactionId);
console.log('System Transaction ID:', result.systemTransactionId);
if (result && 'merchantTransactionId' in result) {
// Success - MerchantSubmitResult
// Use merchantTransactionId & systemTransactionId to get transaction details from Unity
console.log('Payment authorised successfully');
// Redirect to success page or show success message
window.location.href = '/payment-success';
} else {
// Payment was declined or error occurred
console.log('Payment failed:', result.errorReason);
// Show error message to user
}
},
onError: (error) => {
console.error('Google Pay error:', error);
// Handle and display error to user
// For error handling patterns, see Troubleshooting guide
},
onCancel: () => {
console.log('Payment cancelled by user');
// Handle cancellation
}
};For detailed information about all available event handlers and their callback data, see Events. For error handling best practices, see Troubleshooting.
Lastly, remember to unmount the component when it's no longer needed to free up resources.
googlePayButton.unmount();For enhanced security, integrate 3DS authentication with your Google Pay implementation. See 3D Secure for complete details.
const config = {
// ... other configuration
onPreInitiateAuthentication: () => {
// Configure 3DS pre-initiation
return {
providerId: 'your-provider-id',
requestorAuthenticationIndicator: '01',
timeout: 30 // Fingerprint timeout in seconds
};
},
onPostInitiateAuthentication: (data) => {
console.log('3DS pre-initiation complete:', data.authenticationId);
},
onPreAuthentication: async () => {
// Configure full 3DS authentication
return {
merchantCountryNumericCode: '276', // Germany
merchantLegalName: 'Your Store',
challengeWindowSize: 2,
requestorChallengeIndicator: '02' // No preference
};
},
onPostAuthentication: (data) => {
console.log('3DS authentication complete:', data);
}
};Learn more about 3DS authentication flows in the 3D Secure and Non-3DS guides.
Enable one-click repeat purchases by storing payment tokens with customer consent. See Recurring payments for complete implementation details.
// Create consent component
const googlePayConsent = pxpSdk.create('google-pay-consent');
// Create button with consent
const googlePayButton = pxpSdk.create('google-pay-button', {
// ... other configuration
googlePayConsentComponent: googlePayConsent,
onGetConsent: () => {
// Return whether consent was given
return document.getElementById('consent-checkbox').checked;
}
});
// Mount both components
googlePayConsent.mount('consent-container');
googlePayButton.mount('google-pay-container');Learn more about recurring payments and consent management in the Recurring payments guide.
Implement dynamic price updates based on shipping selections. See Configuration for comprehensive implementation examples.
const config = {
// ... other configuration
paymentDataRequest: {
// ... other payment data request config
callbackIntents: ['SHIPPING_ADDRESS', 'SHIPPING_OPTION'],
emailRequired: true,
shippingAddressRequired: true,
shippingOptionRequired: true,
shippingAddressParameters: {
allowedCountryCodes: ['US', 'CA', 'DE', 'FR', 'GB'],
phoneNumberRequired: true
},
shippingOptionParameters: {
defaultSelectedOptionId: 'standard',
shippingOptions: [
{
id: 'standard',
label: 'Standard Shipping',
description: '5-7 business days'
},
{
id: 'express',
label: 'Express Shipping',
description: '2-3 business days'
}
]
}
},
onPaymentDataChanged: async (intermediatePaymentData) => {
console.log('Payment data changed:', intermediatePaymentData);
// Calculate new total based on shipping
const baseAmount = 20.00;
const tax = 5.00;
const shippingCost = calculateShipping(intermediatePaymentData.shippingAddress);
const newTotal = baseAmount + tax + shippingCost;
// Update the SDK amount
pxpSdk.updateAmount(newTotal);
// Return updated transaction info
return {
newTransactionInfo: {
totalPriceStatus: 'FINAL',
totalPrice: newTotal.toFixed(2),
totalPriceLabel: 'Total',
displayItems: [
{
label: 'Product',
type: 'LINE_ITEM',
price: '20.00'
},
{
label: 'Tax',
type: 'TAX',
price: '5.00'
},
{
label: 'Shipping',
type: 'SHIPPING_OPTION',
price: shippingCost.toFixed(2)
}
]
}
};
}
};For detailed implementation patterns, validation logic, and best practices, see the Payment sheet interactions section in Configuration.
Implement custom validation before opening the Google Pay payment sheet. See Events for all available event handlers.
const config = {
// ... other configuration
onCustomValidation: async () => {
// Validate other form fields
const isValid = validateCheckoutForm();
if (!isValid) {
showValidationErrors();
return false; // Prevent Google Pay sheet from opening
}
return true; // Allow Google Pay sheet to open
},
onGooglePaymentButtonClicked: async (event) => {
// Handle button click
console.log('Google Pay button clicked');
// Optionally perform actions before payment sheet opens
}
};Implement retry logic for soft decline scenarios. For complete 3DS retry patterns, see 3D Secure.
const config = {
// ... other configuration
onPreRetrySoftDecline: (data) => {
console.log('Soft decline detected', data);
console.log('merchantTransactionId', data.merchantTransactionId);
console.log('systemTransactionId', data.systemTransactionId);
// Return updated authentication configuration for retry, return null for not retry
return {
retry: true,
updatedConfigs: {
onPreInitiateAuthentication: (): PreInitiateIntegratedAuthenticationData => {
return {
providerId: "pxpfinancial",
timeout: 12
};
},
onPreAuthentication: async () => {
return {
merchantCountryNumericCode: "840",
merchantLegalName: "Your Store name",
challengeWindowSize: 4,
requestorChallengeIndicator: "02",
};
},
}
};
}
};Here's a complete React implementation showing how to integrate the Google Pay button component:
import { useEffect, useState } from "react";
import { PxpCheckout, GooglePayTransactionInitData, BaseSubmitResult } from "@pxpio/web-components-sdk";
export default function GooglePayCheckout() {
const [payAmount] = useState<number>(25);
const [currencyCode] = useState<string>("EUR");
const [sessionData, setSessionData] = useState<any>();
const [errorMessage, setErrorMessage] = useState<string>("");
const [successMessage, setSuccessMessage] = useState<string>("");
// 1. Create the session data from your backend
useEffect(() => {
const createSession = async () => {
try {
// Fetch session data from your backend API
const response = await fetch('/api/create-session', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
amount: payAmount,
currency: currencyCode
})
});
const data = await response.json();
setSessionData(data);
} catch (error) {
console.error('Failed to create session:', error);
setErrorMessage('Failed to initialize payment');
}
};
createSession();
}, [payAmount, currencyCode]);
// 2. Initialize the SDK, create and mount component
useEffect(() => {
if (!sessionData) return;
// 2.1 Initialize the SDK
const paymentSDK = PxpCheckout.initialize({
environment: 'test',
session: sessionData,
ownerId: 'your-owner-id',
ownerType: 'MerchantGroup',
kountDisabled: false, // OPTIONAL: Set to true to disable Kount fraud detection
transactionData: {
currency: currencyCode,
amount: payAmount,
entryType: 'Ecom',
intent: {
card: 'Authorisation',
},
merchantTransactionId: crypto.randomUUID(),
merchantTransactionDate: () => new Date().toISOString(),
},
onGetShopper: async () => {
return {
id: 'shopper-' + Date.now(),
email: 'customer@example.com',
firstName: 'John',
lastName: 'Doe'
};
}
});
// 2.2 Create the Google Pay button component
const googlePayButton = paymentSDK.create('google-pay-button', {
paymentDataRequest: {
allowedPaymentMethods: [{
type: 'CARD',
parameters: {
allowedCardNetworks: ['VISA', 'MASTERCARD', 'AMEX'],
allowedAuthMethods: ['PAN_ONLY', 'CRYPTOGRAM_3DS'],
}
}],
transactionInfo: {
currencyCode: currencyCode,
totalPriceStatus: 'FINAL',
totalPrice: payAmount.toFixed(2),
totalPriceLabel: 'Total',
displayItems: [
{
label: 'Product',
type: 'LINE_ITEM',
price: '20.00',
status: 'FINAL'
},
{
label: 'Tax',
type: 'TAX',
price: '5.00',
status: 'FINAL'
}
],
},
},
style: {
type: 'buy',
color: 'default',
height: '48px',
borderRadius: 4,
sizeMode: 'fill'
},
onPreAuthorisation: async (): Promise<GooglePayTransactionInitData> => {
console.log('Pre-authorisation started');
setErrorMessage('');
setSuccessMessage('Processing payment...');
return {
riskScreeningData: {
performRiskScreening: true
}
};
},
onPostAuthorisation: async (result: BaseSubmitResult | null) => {
console.log('Payment completed:', result);
if (result && 'merchantTransactionId' in result) {
// Success - MerchantSubmitResult
console.log('Merchant Transaction ID:', result.merchantTransactionId);
console.log('System Transaction ID:', result.systemTransactionId);
setSuccessMessage('Payment successful! Redirecting...');
setErrorMessage('');
// Use merchantTransactionId & systemTransactionId to get transaction details from Unity
setTimeout(() => {
window.location.href = '/payment-success?txn=' + result.merchantTransactionId;
}, 2000);
} else {
setErrorMessage('Payment failed: ' + (result?.errorReason || 'Please try again'));
setSuccessMessage('');
}
},
onError: (error) => {
console.error('Google Pay error:', error);
setErrorMessage('Payment error: ' + error.message);
setSuccessMessage('');
},
onCancel: () => {
console.log('Payment cancelled by user');
setErrorMessage('Payment was cancelled');
setSuccessMessage('');
}
});
// 2.3 Mount the component
googlePayButton.mount('google-pay-container');
// 2.4 Cleanup on unmount
return () => {
googlePayButton.unmount();
};
}, [sessionData, payAmount, currencyCode]);
return (
<div style={{ maxWidth: '400px', margin: '50px auto', padding: '20px', fontFamily: 'sans-serif' }}>
<h2>Complete your purchase</h2>
<div style={{ background: '#f8f9fa', padding: '20px', borderRadius: '8px', marginBottom: '20px' }}>
<div style={{ display: 'flex', justifyContent: 'space-between', marginBottom: '10px' }}>
<span>Product</span>
<span>€20.00</span>
</div>
<div style={{ display: 'flex', justifyContent: 'space-between', marginBottom: '10px' }}>
<span>Tax</span>
<span>€5.00</span>
</div>
<hr style={{ border: 'none', borderTop: '1px solid #ddd', margin: '15px 0' }} />
<div style={{ display: 'flex', justifyContent: 'space-between', fontWeight: 600, fontSize: '18px' }}>
<span>Total</span>
<span>€25.00</span>
</div>
</div>
{errorMessage && (
<div style={{ background: '#ffebee', color: '#c62828', padding: '12px', borderRadius: '4px', marginBottom: '10px' }}>
{errorMessage}
</div>
)}
{successMessage && (
<div style={{ background: '#e8f5e8', color: '#2e7d32', padding: '12px', borderRadius: '4px', marginBottom: '10px' }}>
{successMessage}
</div>
)}
{/* Google Pay button will be mounted here */}
<div id="google-pay-container" style={{ margin: '20px 0' }}></div>
<div style={{ textAlign: 'center', color: '#666', margin: '20px 0' }}>
<p>Or pay with credit card</p>
</div>
</div>
);
}