How to track Stripe purchases as conversions in Usermaven
Accurately tracking Stripe purchases in Usermaven allows you to measure sales, attribute revenue to marketing efforts, and understand your customer’s journey to conversion. This guide details several methods to ensure every Stripe purchase is captured, regardless of your checkout flow.
Choosing your tracking method
Select the method(s) that best fit your Stripe integration and technical comfort level:
- Redirect to custom success page (for Stripe Checkout): Ideal if you use Stripe-hosted Checkout pages.
- Client-side event tracking (for Stripe Elements/Payment Element): Best for on-site payment forms where you want rich data and immediate feedback.
- Server-side webhook tracking (most reliable): Guarantees every purchase is tracked, even if the user closes their browser early.
- Google Tag Manager (GTM) integration: Suitable if you manage your website tags through GTM.
Option 1: Redirect to a custom success page (via success_url
)
Why this method?
Stripe Checkout pages (hosted by Stripe) don’t allow third-party scripts. Redirecting users to a custom “Thank You” page on your site after payment allows the Usermaven pixel to fire and record the conversion.
Best for: Users of Stripe Checkout.
Step-by-step instructions
- Set the
success_url
in your Stripe Checkout Session:
When creating your Stripe Checkout Session on your server, include the success_url
parameter, pointing to a page on your domain. You can include {CHECKOUT_SESSION_ID}
to pass the session ID.
const session = await stripe.checkout.sessions.create({
payment_method_types: ['card'],
line_items: [/* ...your line items... */],
mode: 'payment',
success_url: 'https://yourdomain.com/stripe-payment-success?session_id={CHECKOUT_SESSION_ID}&utm_source=your_source',
cancel_url: 'https://yourdomain.com/cart'
});
- Create your custom success page:
Build a “Thank You” or “Order Confirmation” page on your site (e.g., yourdomain.com/stripe-payment-success
).
Ensure the Usermaven tracking pixel is installed and active on this page.
- Create a conversion goal in Usermaven:
In Usermaven, navigate to Configure > Conversion Goals.
Create a new conversion goal based on Page URL condition.
Enter the URL of your success page (e.g., /stripe-payment-success
) and name it (e.g., “Purchase”).
Option 2: Client-side event tracking (with Stripe Elements / Payment Element)
Why this method?
If you build your payment form directly on your domain using Stripe Elements, particularly the modern Payment Element, you can track conversions client-side. This usually involves redirecting to a return URL where payment status is confirmed.
Best for: On-site payment forms built with Stripe Elements or the Payment Element.
Initialize Stripe.js and mount the Payment Element
Ensure Stripe.js is loaded and you’ve created and mounted the Payment Element on your checkout page.
Handle payment submission and redirection
const form = document.getElementById('payment-form');
form.addEventListener('submit', async (event) => {
event.preventDefault();
const {error} = await stripe.confirmPayment({
elements,
confirmParams: {
return_url: 'https://yourdomain.com/order-confirmation',
},
});
if (error) {
console.error("Stripe Payment Error:", error.message);
}
});
Confirm payment status on your return_url
page and fire Usermaven event
document.addEventListener('DOMContentLoaded', async () => {
const urlParams = new URLSearchParams(window.location.search);
const clientSecret = urlParams.get('payment_intent_client_secret');
if (!clientSecret) {
console.log("No client secret found. User may have navigated directly.");
return;
}
const {paymentIntent, error} = await stripe.retrievePaymentIntent(clientSecret);
if (error) {
console.error("Error retrieving PaymentIntent:", error.message);
} else if (paymentIntent && paymentIntent.status === 'succeeded') {
const amountInMajorUnits = paymentIntent.amount / 100;
const currencyCode = paymentIntent.currency.toUpperCase();
usermaven("track", "stripe_purchase_elements", {
value: amountInMajorUnits,
currency: currencyCode,
orderId: paymentIntent.id,
});
} else if (paymentIntent) {
console.log("PaymentIntent status:", paymentIntent.status);
}
});
Note on older Card Element: If using the older single Card Element and stripe.confirmCardPayment
, the logic can be more direct if no redirect is needed, but handling the return_url
is still a robust pattern.
Option 3: Server-side tracking via Stripe webhooks (most reliable)
Why this method?
Client-side tracking can sometimes be missed. Webhooks from Stripe to your server provide a guaranteed way to capture every completed purchase.
Best for: Ensuring 100% data capture accuracy. Requires server-side development.
Step-by-step instructions
-
Create a webhook endpoint on your server.
-
Register the webhook endpoint in Stripe:
In your Stripe Dashboard (Developers > Webhooks), add an endpoint. Listen for:
checkout.session.completed
payment_intent.succeeded
- (optional)
checkout.session.async_payment_succeeded
- Verify webhook signatures & handle the event:
const fetch = require('node-fetch');
app.post('/stripe-webhook', express.raw({type: 'application/json'}), async (request, response) => {
const sig = request.headers['stripe-signature'];
let event;
try {
event = stripe.webhooks.constructEvent(request.body, sig, endpointSecret);
} catch (err) {
return response.sendStatus(400);
}
let sessionOrPaymentIntent;
let eventNameSuffix = '';
let eventTimestamp;
if (event.type === 'checkout.session.completed' || event.type === 'checkout.session.async_payment_succeeded') {
sessionOrPaymentIntent = event.data.object;
eventNameSuffix = '_checkout';
eventTimestamp = sessionOrPaymentIntent.created;
} else if (event.type === 'payment_intent.succeeded') {
sessionOrPaymentIntent = event.data.object;
eventNameSuffix = '_pi';
eventTimestamp = sessionOrPaymentIntent.created;
} else {
return response.sendStatus(200);
}
const amount = sessionOrPaymentIntent.amount_total || sessionOrPaymentIntent.amount;
const amountInMajorUnits = amount / 100;
const currencyCode = sessionOrPaymentIntent.currency.toUpperCase();
const usermavenCombinedAuthToken = `${USERMAVEN_API_KEY_PART}.${USERMAVEN_SERVER_TOKEN_PART}`;
const usermavenPayload = {
event_type: `stripe_purchase_webhook${eventNameSuffix}`,
user_id: sessionOrPaymentIntent.customer || `stripe_guest_${sessionOrPaymentIntent.id}`,
created_at: new Date(eventTimestamp * 1000).toISOString(),
event_properties: {
value: amountInMajorUnits,
currency: currencyCode,
orderId: sessionOrPaymentIntent.id,
stripe_event_type: event.type
}
};
try {
const usermavenResponse = await fetch('https://events.usermaven.com/api/v1/event', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${usermavenCombinedAuthToken}`
},
body: JSON.stringify(usermavenPayload)
});
if (!usermavenResponse.ok) {
const errorBody = await usermavenResponse.text();
console.error(`Error sending event to Usermaven: ${usermavenResponse.status} ${usermavenResponse.statusText}`, errorBody);
}
} catch (apiError) {
console.error('Exception when calling Usermaven API:', apiError);
}
response.sendStatus(200);
});
Option 4: Google Tag Manager (GTM) integration
Why this method?
If you manage tags through GTM, push a dataLayer
event on purchase success (from your success page or client-side callback) and use GTM to fire your Usermaven tracking.
Best for: Users already leveraging GTM.
Step-by-step instructions
- Push data to the
dataLayer
on purchase success:
const amountInMajorUnits = paymentIntent.amount / 100;
const currencyCode = paymentIntent.currency.toUpperCase();
window.dataLayer = window.dataLayer || [];
dataLayer.push({
'event': 'stripe_purchase_successful',
'transactionValue': amountInMajorUnits,
'transactionCurrency': currencyCode,
'transactionId': paymentIntent.id
});
- Configure GTM:
- Create Data Layer Variables:
transactionValue
,transactionCurrency
,transactionId
- Create a Custom Event Trigger: Event name
stripe_purchase_successful
- Create a Usermaven Tag (Custom HTML):
<script>
usermaven("track", "Purchase", {
value: {{transactionValue}},
currency: {{transactionCurrency}},
orderId: {{transactionId}}
});
</script>
Fire it on the custom event trigger. Then publish your GTM container.