PayPal payments leave your website twice: once when the customer goes to PayPal, and again in your analytics, where the purchase never shows up or appears as a referral from paypal.com with no value. This guide shows how to record completed PayPal payments as proper GA4 purchase events through Google Tag Manager, with transaction ID, value and currency, and without counting the same payment twice.
Two PayPal Flows
- JavaScript SDK Smart Buttons. The customer approves in a PayPal popup and returns control to a callback on your page. Best case for tracking.
- Redirect or hosted buttons. The customer goes to PayPal and comes back to a return URL. You track the return page and need the payment details from PayPal or from your own order record.
Method 1: Smart Buttons With the onApprove Callback
When you render PayPal buttons with the SDK, you provide an onApprove function. Capture the order there and push the purchase to the dataLayer:
<script>
paypal.Buttons({
createOrder: function (data, actions) {
return actions.order.create({
purchase_units: [{ amount: { value: '49.00', currency_code: 'USD' } }]
});
},
onApprove: function (data, actions) {
return actions.order.capture().then(function (details) {
var unit = details.purchase_units && details.purchase_units[0];
var amount = unit && unit.amount ? unit.amount : {};
var capture = unit && unit.payments && unit.payments.captures ? unit.payments.captures[0] : null;
var payer = details.payer || {};
window.dataLayer = window.dataLayer || [];
window.dataLayer.push({ ecommerce: null });
window.dataLayer.push({
event: 'purchase',
payment_method: 'paypal',
ecommerce: {
transaction_id: capture ? capture.id : details.id,
value: parseFloat(amount.value || 0),
currency: amount.currency_code || 'USD',
items: [{ item_id: 'SKU-1', item_name: 'Product name', price: parseFloat(amount.value || 0), quantity: 1 }]
},
user_email: payer.email_address ? payer.email_address.toLowerCase() : undefined
});
window.location.href = '/thank-you?order=' + details.id;
});
}
}).render('#paypal-button-container');
</script>
The capture ID is the transaction ID. The payer email is included for Enhanced Conversions and Advanced Matching if you add Google Ads and Meta tags. Replace the items array with your real product data.
One caution: if you redirect immediately after the push, give the tags a moment. Either delay the redirect by half a second or show the confirmation on the same page.
Method 2: Return Page
For redirect flows, PayPal returns the customer to your return URL with parameters that identify the order. On that page, your server should retrieve the order from PayPal's API or from your own database, then output the same purchase dataLayer push as in Method 1 before the GTM snippet, using the PayPal transaction ID as transaction_id.
If you cannot look up the order server-side, you can still push a purchase with the value you stored in a cookie or session before sending the customer to PayPal, and the PayPal transaction ID from the return URL. It is less robust, but far better than nothing.
Step 3: Deduplicate
Wrap the push in a check that stores the transaction ID in local storage and skips the push if it has been seen. Pass the transaction ID to every tag. GA4 ignores a second purchase with the same transaction ID in the same property.
Step 4: GTM Variables, Trigger and Tags
Data Layer Variables for ecommerce.transaction_id, ecommerce.value, ecommerce.currency, ecommerce.items, payment_method and user_email. A Custom Event trigger on purchase.
- GA4 Event
purchasereading ecommerce data from the dataLayer, withpayment_methodas an extra parameter so you can compare PayPal to card payments. - Google Ads Conversion Tracking with value, transaction ID and currency, and a User-Provided Data variable from the email for Enhanced Conversions. Conversion Linker on All Pages.
- Meta Pixel Purchase with value, currency, content IDs and an event ID equal to the transaction ID.
Step 5: Fix Attribution
In GA4 Admin, open the web data stream, then Configure tag settings, then List unwanted referrals, and add paypal.com. Without this, GA4 starts a new session when the customer returns and credits the purchase to PayPal instead of the ad or email that brought them.
Step 6: Test
- Use the PayPal sandbox with a sandbox buyer account. Complete a payment with GTM Preview open.
- Confirm one
purchaseevent with the capture ID, correct value and currency. - Confirm one fire each of GA4, Google Ads and Meta. Check GA4 DebugView for the purchase and items, and inspect the requests in a tag debugger such as the Insighter Debugger extension.
- Reload the thank-you page. Nothing should fire again.
- After a day, confirm the purchase appears in the GA4 Monetisation reports with the right revenue.
Common Problems
- Purchase shows value 0. The amount was read before capture completed, or the field path is wrong for your SDK version. Log the
detailsobject once to confirm. - Two purchases per payment. Both the callback and the return page push events. Keep one.
- Revenue attributed to paypal.com. Unwanted referral not configured.
- Renewals missing. Expected. Use PayPal webhooks to a server-side endpoint for recurring billing.
Outcome
PayPal payments appear in GA4 as purchases with real transaction IDs and values, attributed to the campaign that earned them, and the same event feeds Google Ads and Meta. You can finally compare PayPal revenue with card revenue by channel instead of reconciling two dashboards by hand.
