How to connect Stripe Checkout to Google Analytics 4
Connect Stripe Checkout to GA4 using client IDs, verified payment webhooks and Measurement Protocol. Handle purchases, renewals, refunds and duplicates.
Quick answer
Use your existing Google tag to collect the browser journey, save its GA4 client ID with the checkout record, and send purchase events from verified Stripe payment webhooks through Measurement Protocol. A success-page redirect alone does not confirm payment. Give each paid invoice or order one transaction ID, and send refunds against that same ID.
On this page
What you’ll learn
- Carry browser analytics context into a server-side checkout record
- Choose payment events without counting the first subscription charge twice
- Build and validate a GA4 purchase payload
- Understand why a renewal does not automatically inherit an old GA4 session
A Stripe and Google Analytics integration needs two connected records: the visit that led to checkout and the payment Stripe confirmed. This tutorial covers Stripe-hosted Checkout and a GA4 web data stream. It assumes your site already has a working Google tag and your backend creates Checkout Sessions.
The architecture is: website visit → server checkout record → Stripe Checkout → verified webhook → durable analytics queue → GA4. It supplements your existing website measurement. Google describes Measurement Protocol as a companion to browser tagging, so a server-only implementation cannot reconstruct an unobserved browser journey.
1. Prepare your GA4 web stream
Find the web stream's measurement ID, such as G-EXAMPLE123, and create a Measurement Protocol API secret in the stream settings. The measurement ID is public. Keep the API secret on your server, outside frontend bundles, source control and request logs.
Confirm that your own landing, pricing, success and cancel pages are measured. Review unwanted referrals for checkout.stripe.com so the hosted payment page does not become a misleading referral source. Stripe's Checkout analytics guide explains this configuration.
Use the same consent decisions for browser collection and server-side analytics. A backend event must not bypass a visitor's choice. Do not put names, email addresses, addresses or other personal details into GA4 event parameters.
2. Capture the browser IDs before redirecting
After analytics collection is permitted and the Google tag is initialized, read its client_id and session_id through the tag API. The following helper times out so an unavailable or blocked tag cannot delay checkout indefinitely.
async function readGa4Context(measurementId) {
if (typeof window.gtag !== "function") return null
const read = (field) => new Promise((resolve) => {
const timeout = setTimeout(() => resolve(null), 500)
window.gtag("get", measurementId, field, (value) => {
clearTimeout(timeout)
resolve(value ?? null)
})
})
const [clientId, sessionId] = await Promise.all([
read("client_id"),
read("session_id")
])
return clientId ? { clientId, sessionId } : null
}
Call this helper only from the branch of your checkout flow where analytics collection is permitted. Send its result with your checkout request. On the server, validate it and associate it with your own order or subscription record. Treat these IDs as analytics context, never as authentication or proof of payment.
Store the Checkout Session ID against that record. Keep the client ID, captured session context and collection permission available when subsequent payment events arrive. If context is unavailable, let checkout proceed; do not invent an identifier or manufacture attribution. The Google tag get reference documents the supported fields.
3. Select one payment event per transaction
Verify the Stripe signature against the raw request body before processing a webhook. Persist the event and queue analytics delivery, then acknowledge it promptly. Stripe can retry delivery and events may arrive out of order; follow its webhook handling guidance.
| Billing situation | Integration rule |
|---|---|
| One-time Checkout payment | Process a completed Checkout Session only when its payment status confirms payment; also handle delayed payment success |
| Subscription first charge | Use the paid invoice as the transaction; do not also count its Checkout Session as a second purchase |
| Subscription renewal | Give the newly paid invoice its own transaction ID |
| Trial or zero-value invoice | Apply an explicit policy; do not report it as money collected |
| Refund | Wait for a successful refund and reference the original purchase transaction ID |
Consult Stripe's Checkout fulfillment guide and subscription webhook guide for the relevant event types. If your billing system can mark invoices paid outside Stripe or use customer balances, distinguish those cases from newly collected cash before mapping them to analytics revenue.
Use two duplicate checks in persistent storage: the Stripe event ID for redeliveries, and the business transaction ID for two different events describing one payment. For refunds, deduplicate each refund ID separately. A customer or subscription ID alone is not a transaction ID because it can have many payments.
4. Send a purchase from your backend
Here is an illustrative payload for one €49 subscription payment, with no tax or shipping. Replace every example ID with the stored context and the actual billing record. Send it with a server-side HTTP POST to Google's Measurement Protocol endpoint.
POST https://www.google-analytics.com/mp/collect?measurement_id=G-EXAMPLE123&api_secret=SERVER_SECRET
Content-Type: application/json
{
"client_id": "123456789.1234567890",
"events": [{
"name": "purchase",
"params": {
"transaction_id": "in_example_paid_invoice",
"currency": "EUR",
"value": 49,
"items": [{
"item_id": "price_example_monthly",
"item_name": "Monthly subscription",
"price": 49,
"quantity": 1
}]
}
}]
}
Calculate value from the item amounts after discounts, excluding tax and shipping. Convert Stripe amounts using the currency's unit rules; dividing by 100 is wrong for zero-decimal currencies. Retain currencies separately, and do not treat one unit of EUR and one unit of USD as interchangeable revenue. Google's ecommerce documentation defines purchase, item and refund parameters; Stripe documents currency units and exceptions.
When delivery is delayed, preserve the actual event time with timestamp_micros, subject to Google's supported backdating window. Do not replace old payment timestamps with the current time to make an old import look like new revenue. Keep a durable record of queued, attempted and completed sends, with a deliberate retry policy.
5. Handle session attribution and renewals
For a purchase associated with an observed active session, include the captured session_id in event parameters when Google's session-attribution requirements are met. Google currently requires delivery within 24 hours of session start and an event timestamp inside that session. If you send engagement_time_msec, it must represent measured engagement; do not insert an arbitrary value to make Realtime display the event. See the Measurement Protocol use cases.
The example payload omits session parameters because it does not assume a current browser session. Do not reuse a months-old session ID for an automatic renewal or change the payment time to fit the original visit. A recorded purchase and correctly attributed acquisition revenue are separate outcomes to validate.
For recurring revenue by original acquisition campaign, retain that campaign and your chosen attribution model in your billing or attribution records. The Stripe revenue attribution guide explains how AttribIQ carries known visitor and session identifiers into subscription reporting.
6. Report refunds without creating a second purchase
Send a refund event with the original transaction_id, currency, and a positive refunded value. Include the affected items and quantities when item-level refund reporting is required. A €10 partial refund uses value: 10, not -10, and must not reuse the full €49 purchase amount. Your backend must distinguish successive partial refunds and failed or pending refunds. Check the actual outcome in Stripe's refund lifecycle.
7. Validate before using the revenue report
First send the payload to /debug/mp/collect with the same query parameters and inspect validationMessages. That endpoint checks structure; it does not add events to reports or verify that your API secret is valid. A successful HTTP response from /mp/collect alone also does not prove an event was valid. Follow Google's event validation instructions.
Use a separate GA4 test property and Stripe test mode to check the full path:
- Complete a tagged checkout and verify its client ID and stored transaction mapping.
- Confirm the correct purchase amount, currency and item details in GA4 after processing.
- Reload the success page and resend the webhook. Neither action should add a purchase.
- Test a delayed payment, a renewal and a partial refund.
- Test with analytics unavailable or declined. Checkout must still work, and your server must honor the collection decision.
- Reconcile against your billing records with the same date range, timezone, tax treatment and currency. Investigate reporting differences before using GA4 totals for decisions.
Choose the reporting workflow you need
Keep GA4 when its reports, Google Ads connections or BigQuery workflows are useful to your team. If you want a simpler website reporting workflow, compare the web analytics features and the Google Analytics alternative.
AttribIQ can start with traffic sources, landing pages, goals and funnels. Connecting Stripe is an additional step for matching those journeys to payments; it is not required to use web analytics.
Frequently asked questions
- Does Stripe Checkout automatically send purchases to GA4?
- Your integration must send the relevant GA4 ecommerce events. For Stripe-hosted Checkout, collect the journey on your own site and connect verified payments to that context on your backend.
- Can I track purchases only on the success page?
- A customer can pay without returning to your site, and a success page can be reloaded. Use verified payment events as the source for completed purchases.
- Will GA4 assign every renewal to the original campaign?
- Do not assume that it will. GA4 session attribution has timing and session-ID requirements. Keep the original acquisition context in your billing or attribution system when you need recurring revenue by acquisition source.
- Do I need AttribIQ to connect Stripe and GA4?
- No. This integration uses your application, Stripe and Google's Measurement Protocol. AttribIQ is an optional separate product for web analytics and payment attribution.
Continue learning
How to track Stripe revenue by source and campaign
Connect Stripe Checkout, subscriptions, invoices, refunds, and webhooks to source, campaign, landing page, and session reports.
Read guide Stripe & PaymentsWhat is a Stripe webhook?
A Stripe webhook is an HTTP notification Stripe sends to your backend when payments, subscriptions, invoices, refunds, and customer events happen.
Read guide Stripe & PaymentsWhat is checkout attribution?
Checkout attribution connects the visit, campaign, landing page, and session before checkout to the payment event that happens after checkout.
Read guide Stripe & PaymentsConnect Stripe to AttribIQ
Configure Stripe to send payment events to AttribIQ after your app has copied visitor and session identifiers into Stripe metadata.
Read guidePut it into practice
See traffic and revenue in the same dashboard
Explore traffic sources, campaigns, goals and matched payments in the demo, then connect your own site.