Integration of Google Pay on Website
Google Pay on a website is implemented via Google Pay API (web) — a JavaScript library that forms a payment token processed by the payment gateway. Supported in Chrome on Android and desktop, in Chromium-based browsers. Unlike Apple Pay, does not require domain verification.
How the Flow Works
- Site calls Google Pay API → browser shows native popup with card selection from Google Wallet
- User confirms payment (biometry / PIN)
- Google Pay returns encrypted
paymentData - Site sends
paymentDatato its server - Server passes token to payment gateway for debit
Connecting Google Pay API
<script async src="https://pay.google.com/gp/p/js/pay.js"
onload="onGooglePayLoaded()"></script>
Basic Implementation
const baseRequest = {
apiVersion: 2,
apiVersionMinor: 0,
};
const allowedCardNetworks = ['MASTERCARD', 'VISA', 'MIR'];
const allowedCardAuthMethods = ['PAN_ONLY', 'CRYPTOGRAM_3DS'];
const baseCardPaymentMethod = {
type: 'CARD',
parameters: {
allowedAuthMethods: allowedCardAuthMethods,
allowedCardNetworks,
},
};
// Tokenization via Stripe
const tokenizationSpecification = {
type: 'PAYMENT_GATEWAY',
parameters: {
gateway: 'stripe',
'stripe:version': '2023-10-16',
'stripe:publishableKey': STRIPE_PUBLIC_KEY,
},
};
const cardPaymentMethod = {
...baseCardPaymentMethod,
tokenizationSpecification,
};
let paymentsClient;
function getGooglePaymentsClient() {
if (!paymentsClient) {
paymentsClient = new google.payments.api.PaymentsClient({
environment: 'PRODUCTION', // or 'TEST'
});
}
return paymentsClient;
}
async function onGooglePayLoaded() {
const client = getGooglePaymentsClient();
const { result } = await client.isReadyToPay({
...baseRequest,
allowedPaymentMethods: [baseCardPaymentMethod],
});
if (result) {
renderGooglePayButton();
}
}
function renderGooglePayButton() {
const button = getGooglePaymentsClient().createButton({
onClick: onGooglePayButtonClicked,
buttonType: 'buy',
buttonColor: 'black',
buttonSizeMode: 'fill',
});
document.getElementById('gpay-container').appendChild(button);
}
async function onGooglePayButtonClicked() {
const paymentDataRequest = {
...baseRequest,
allowedPaymentMethods: [cardPaymentMethod],
transactionInfo: {
totalPriceStatus: 'FINAL',
totalPrice: '14.99',
currencyCode: 'USD',
countryCode: 'US',
},
merchantInfo: {
merchantId: 'BCR2DN4TXXXXXXXX', // from Google Pay Business Console
merchantName: 'My Store',
},
};
try {
const paymentData = await getGooglePaymentsClient().loadPaymentData(paymentDataRequest);
await processPayment(paymentData);
} catch (err) {
if (err.statusCode !== 'CANCELED') {
console.error('Google Pay error', err);
}
}
}
async function processPayment(paymentData) {
const token = paymentData.paymentMethodData.tokenizationData.token;
const response = await fetch('/api/payment/google-pay', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ token, orderId: currentOrderId }),
});
const result = await response.json();
if (result.success) {
window.location.href = '/payment/success';
}
}
Server-side Token Processing via Stripe
public function processGooglePay(Request $request): JsonResponse
{
$token = $request->input('token');
$orderId = $request->input('orderId');
$order = Order::findOrFail($orderId);
\Stripe\Stripe::setApiKey(config('services.stripe.secret'));
try {
$paymentIntent = \Stripe\PaymentIntent::create([
'amount' => (int)($order->total * 100),
'currency' => 'usd',
'payment_method_data' => [
'type' => 'card',
'card' => ['token' => json_decode($token)->id],
],
'confirm' => true,
'return_url' => 'https://example.com/payment/complete',
'metadata' => ['order_id' => $orderId],
]);
if ($paymentIntent->status === 'succeeded') {
$order->update(['status' => 'paid', 'transaction_id' => $paymentIntent->id]);
return response()->json(['success' => true]);
}
} catch (\Stripe\Exception\CardException $e) {
return response()->json(['success' => false, 'error' => $e->getMessage()]);
}
return response()->json(['success' => false]);
}
React Component with Google Pay
import { useEffect, useRef } from 'react';
declare const google: any;
export function GooglePayButton({ amount, currency, onSuccess }: {
amount: string;
currency: string;
onSuccess: () => void;
}) {
const containerRef = useRef<HTMLDivElement>(null);
useEffect(() => {
const script = document.createElement('script');
script.src = 'https://pay.google.com/gp/p/js/pay.js';
script.async = true;
script.onload = initGooglePay;
document.head.appendChild(script);
return () => { document.head.removeChild(script); };
}, []);
function initGooglePay() {
const client = new google.payments.api.PaymentsClient({ environment: 'PRODUCTION' });
const btn = client.createButton({ onClick: () => handlePayment(client, amount, currency, onSuccess) });
containerRef.current?.appendChild(btn);
}
return <div ref={containerRef} />;
}
Registration in Google Pay Business Console
For production use:
- Register site in Google Pay Business Console
- Pass integration checklist
- Obtain
merchantId(formatBCR2DN4T...)
In test mode (environment: 'TEST'), merchantId is not required, no real charges occur. Test cards are added to Google Pay Sandbox. Google review pass: 1–3 business days.







