Stripe is the payment processor behind thousands of coaches, SaaS products, course creators and small online shops. It is excellent at taking payments, but it creates a tracking blind spot: the moment a customer clicks Buy, they leave your website for Stripe's checkout page, and your tags cannot follow them there. I regularly see Stripe businesses running Google Ads or Meta with purchase tracking that is missing, doubled or credited to the wrong source. This guide explains how to fix that properly.
For a done-for-you version of this setup, see my Stripe payment tracking page.
Why is Stripe hard to track?
Stripe is hard to track because the payment happens on a page you do not control. Stripe-hosted Checkout and Payment Links run on Stripe's domain, and Stripe does not let you add Google Tag Manager, the Meta Pixel or other scripts there. Your tracking only sees the visitor before they leave and, sometimes, when they come back.
That leaves three gaps:
- No purchase event on Stripe's page. Nothing fires while the customer pays.
- Not everyone comes back. Some customers pay and close the tab, so your success page never loads.
- Renewals happen inside Stripe. A subscription payment in month two never touches your website at all.
Which Stripe setup do you have?
The right tracking method depends on how you take payments with Stripe.
| Stripe setup | Where the payment happens | How to track the purchase |
|---|---|---|
| Stripe Checkout (hosted) | Stripe's checkout page | Verified success page + webhook |
| Payment Links | Stripe's hosted page | Redirect after payment + webhook |
| Embedded Checkout or Elements | Inside your website | Browser event on your site + webhook |
| Subscriptions | First payment in Checkout, renewals in Stripe | Checkout Session for the first payment, invoice.paid for renewals |
| A platform using Stripe (course or funnel tools) | The platform's checkout | The platform's own purchase event or webhooks |
In every case, a server-side confirmation from Stripe is what makes the numbers reliable.
Method 1: Track purchases on a verified success page
The success page method works, but only if you verify the payment rather than counting page views.
- Set the Checkout Session's success URL, or the Payment Link's "After the payment" setting, to redirect to your own page, and include
{CHECKOUT_SESSION_ID}so Stripe adds the session ID to the URL. - On that page, check the session on your server (or through a server-side GTM client) and only continue if its payment status is paid.
- Push a
purchaseevent with the session ID astransaction_id, plusvalueandcurrencyfrom the session. - Remove the session ID from the address bar after sending, so a refresh does not fire again.
dataLayer.push({
event: 'purchase',
ecommerce: {
transaction_id: 'cs_live_a1B2c3', // Stripe Checkout Session ID
value: 199,
currency: 'USD'
}
})
Why verification matters: a success URL can be opened, bookmarked or shared. Counting it without checking the session records purchases that never happened.
Method 2: Send purchases from Stripe webhooks
Webhooks are Stripe's way of telling your server that something happened, and they are the most reliable purchase signal you can get.
The events that matter for tracking:
checkout.session.completed— a Checkout Session finished. For card payments, the payment is done.checkout.session.async_payment_succeeded— a delayed payment method (such as some bank debits) succeeded later. Count the purchase here, not at completion.invoice.paid— a subscription invoice, including renewals, was paid.charge.refunded— optional, if you want refunds in GA4.
A typical setup:
- In the Stripe Dashboard, add a webhook endpoint that points to your server-side GTM container (or a small backend that forwards to it).
- Select the events above.
- In the server container, turn each event into a
purchasewith the Stripe ID astransaction_id, then send it to GA4, Google Ads and Meta. - Verify the webhook signature, so only genuine Stripe events are accepted.
If you are new to server containers, read what Stape and server-side GTM are.
How do you avoid counting a Stripe payment twice?
Most Stripe double counting comes from overlapping signals. Follow three rules:
- One ID everywhere. The success page event and the webhook event for the same payment must share the same transaction ID (and the same Meta
event_id). - One webhook per sale. Stripe can send both
checkout.session.completedandpayment_intent.succeededfor one Checkout payment. Pick one for purchases. - One owner per platform. If a Stripe-connected app already sends purchases to Meta, do not send them again from GTM.
How do you credit Stripe sales to the right ad?
A webhook knows who paid, but not which ad they clicked. To connect the two, save the visitor's identifiers before they leave for Stripe and pass them along with the payment:
- the GA4 client ID (from the
_gacookie) and session ID, - the Google Ads gclid,
- the Meta _fbc and _fbp values.
With Stripe Checkout created by your server, these go into the session metadata. With Payment Links, add a short internal ID as client_reference_id in the link URL and keep the identifiers on your side under that ID. Note that client_reference_id only accepts letters, numbers, dashes and underscores, so do not put an email address in it. I cover this technique in detail in how to keep click IDs through a third-party checkout.
What should you set in GA4?
Two GA4 settings prevent Stripe from stealing credit:
- Add
stripe.comunder Admin → Data streams → Configure tag settings → List unwanted referrals, so customers returning from Stripe do not start a new session credited to Stripe. My GA4 cross-domain guide walks through this screen. - Mark
purchaseas a key event, and import it into Google Ads only if you are not already sending purchases to Google Ads with a conversion tag.
How do you test Stripe tracking?
- Use Stripe test mode and a test card to complete a Checkout payment
- Check that the webhook was delivered (Stripe Dashboard → Webhooks → event log)
- Confirm one
purchasein server GTM Preview with the right value, currency and ID - Refresh the success page and confirm nothing fires again
- Check GA4 DebugView, Google Ads diagnostics and Meta Test events
- After a week of live sales, compare purchases with Stripe's payments list
Final thoughts
Stripe tracking works when you stop relying on the browser alone. Verify the success page, let Stripe's webhooks confirm every payment, and use one ID everywhere. If you want it set up for you, see my Stripe payment tracking service or my wider conversion tracking service.