Track analytics events in Embedded Checkout
Use analytics events from Embedded Checkout to monitor user behavior.
Private preview
Embedded Checkout analytics is in private preview. Request access to Embedded Checkout analytics.
Stripe Embedded Checkout supports real-time analytics events, allowing you to track user behavior, optimize conversion rates, and attribute sales to marketing campaigns.
Overview
With the analytics feature, you can:
- Receive real-time events during the checkout process
- Link events to specific funnels or campaigns using client metadata
- Integrate with popular analytics platforms or your own systems
Available events
Embedded Checkout send the following analytics events throughout the checkout lifecycle:
| Event | When we send it | Key data |
|---|---|---|
deviceData | When the checkout UI renders | Device category, language, platform, viewport |
checkoutRendered | When the checkout UI renders | Line items, currency, amount |
promotionCodeApplied | When a promotional code is successfully applied | Promotion code |
lineItemChange | When items, quantities, or currency change | Line items, currency, amount |
checkoutSubmitted | When a customer submits payment information | Payment method type, line items, currency, amount |
checkoutSubmitFailed | When a payment submission fails | Payment method type, failure reason, line items, currency, amount |
Event structure
All analytics events follow this structure:
{
eventType: string; // Event name (for example, 'checkoutRendered')
checkoutSession: string; // Checkout Session ID
details: object; // Event-specific data (see below)
clientMetadata: {[key: string]: string}; // Your custom metadata
timestamp: number; // Unix timestamp in seconds
}
Event details
Each event includes specific details in the details object:
deviceData
Sent when the checkout UI loads and renders to the customer. Provides information about the user’s device and browser.
{
device: {
category: 'mobile' | 'tablet' | 'desktop';
language?: string;
platform?: string;
viewport?: {width: number; height: number};
}
}
checkoutRendered
Sent when the checkout UI loads and renders to the customer.
{
items?: Array<{
quantity?: number; // metered items won't show quantity
product?: string;
amount?: number; // in smallest currency unit (for example, cents)
rateCard?: string;
pricingPlan?: string;
price?: string;
}>;
currency?: string;
amount?: number; // in smallest currency unit (for example, cents)
}
promotionCodeApplied
Sent when a promotion code is successfully applied.
{
code: string;
}
lineItemChange
Sent when line items, quantities, or currency are updated. This includes quantity changes, currency changes, optional items, cross-sells, and upsells.
{
items?: Array<{
quantity?: number;
product?: string;
amount?: number; // total (not unit amount)
rateCard?: string;
pricingPlan?: string;
price?: string;
}>;
currency?: string;
amount?: number; // total in smallest currency unit (for example, cents)
}
checkoutSubmitted
Sent when the customer submits their payment information.
{
items?: Array<{
quantity?: number;
product?: string;
amount?: number; // total (not unit amount)
rateCard?: string;
pricingPlan?: string;
price?: string;
}>;
currency?: string;
amount?: number; // total in smallest currency unit (for example, cents)
paymentMethodType: string; // for example, 'card', 'klarna', and so on.
}
Warning
All amounts are provided in the smallest currency unit (for example, cents for USD). Always use the amounts provided in the event details—don’t recalculate them on the client side. These analytics events are a best effort, and provide behavioral tracking and conversion analytics.
checkoutSubmitFailed
Sent when a valid payment submission fails.
{
items?: Array<{
quantity?: number;
product?: string;
amount?: number; // total (not unit amount)
rateCard?: string;
pricingPlan?: string;
price?: string;
}>;
currency?: string;
amount?: number; // total in smallest currency unit (for example, cents)
paymentMethodType: string; // for example, 'card', 'klarna', and so on.
failureReason: 'api_error' | 'user_cancelled' | 'reverification' | 'unexpected';
}
The failureReason field indicates why the payment submission failed:
| Failure Reason | Description | Examples |
|---|---|---|
api_error | Network or API errors, card declines, 3DS authentication failures, or server validation errors after valid payment information has been submitted | Such as card_declined, expired_card, incorrect_cvc, insufficient_funds, processing_error, api_connection_error, or payment method provider errors |
user_cancelled | User canceled the payment flow after valid payment information has been submitted | Such as Link Klarna sign up flow dismissal |
reverification | Link reverification required after valid payment information has been submitted | Link session expired |
unexpected | Unknown or unexpected errors after valid payment information has been submitted | Unknown or unexpected errors |
Implementation
- Create a Checkout Session with client metadata When creating your Checkout Session, include
client_metadatato link events to specific funnels or campaigns:const session = await stripe.checkout.sessions.create({ ui_mode: 'embedded_page', line_items: [{ price: '{{the related setting}}', quantity: 1, }], mode: 'payment', return_url: 'https://example.com/return?session_id={CHECKOUT_SESSION_ID}', client_metadata: { funnel_id: 'summer_sale_2025', campaign: 'email_promo', variant: 'version_A' }, });Warning Any data included inclient_metadatais accessible on the client. Avoid sharing sensitive or confidential information through these fields. - Initialize Embedded Checkout with an analytics event handler When initializing Embedded Checkout, include the
onAnalyticsEventhandler:const checkout = await stripe.createEmbeddedCheckoutPage({ clientSecret: session.client_secret, onAnalyticsEvent: (event: StripeCheckoutAnalyticsEvent) => { // Handle the event here console.log('Received event:', event); }, }); - Handle analytics events In your
onAnalyticsEventhandler, you can process events and send them to your analytics platform. Here’s an example using Segment:const checkout = await stripe.createEmbeddedCheckoutPage({ clientSecret: session.client_secret, onAnalyticsEvent: (event) => { const { eventType, details, clientMetadata, checkoutSession, timestamp } = event; switch (eventType) { case 'deviceData': // Custom Segment e-commerce event analytics.track('Checkout Device Data Collected', { device_category: details.device.category, language: details.device.language, platform: details.device.platform, viewport_width: details.device.viewport?.width, viewport_height: details.device.viewport?.height, checkout_id: checkoutSession,...clientMetadata }); break; case 'checkoutRendered': // Standard Segment e-commerce event analytics.track('Checkout Started', { checkout_id: checkoutSession, currency: details.currency?.toUpperCase(), value: details.amount? details.amount / 100: 0, products: details.items?.map(item => ({ product_id: item.product, price: item.amount? item.amount / 100: 0, quantity: item.quantity })),...clientMetadata }); break; case 'promotionCodeApplied': // Standard Segment e-commerce event analytics.track('Coupon Applied', { checkout_id: checkoutSession, coupon_id: details.code,...clientMetadata }); break; case 'lineItemChange': // Custom Segment event analytics.track('Checkout Items Updated', { checkout_id: checkoutSession, currency: details.currency?.toUpperCase(), value: details.amount? details.amount / 100: 0, products: details.items?.map(item => ({ product_id: item.product, price: item.amount? item.amount / 100: 0, quantity: item.quantity,...(item.price && { sku: item.price }) })),...clientMetadata }); break; case 'checkoutSubmitted': // Standard Segment e-commerce event analytics.track('Payment Information Entered', { checkout_id: checkoutSession, payment_method: details.paymentMethodType, currency: details.currency?.toUpperCase(), value: details.amount? details.amount / 100: 0, products: details.items?.map(item => ({ product_id: item.product, price: item.amount? item.amount / 100: 0, quantity: item.quantity,...(item.price && { sku: item.price }) })),...clientMetadata }); break; case 'checkoutSubmitFailed': // Custom Segment event for failed submissions analytics.track('Payment Submission Failed', { checkout_id: checkoutSession, payment_method: details.paymentMethodType, failure_reason: details.failureReason, currency: details.currency?.toUpperCase(), value: details.amount? details.amount / 100: 0, products: details.items?.map(item => ({ product_id: item.product, price: item.amount? item.amount / 100: 0, quantity: item.quantity,...(item.price && { sku: item.price }) })),...clientMetadata }); break; } }, });You can also send events to your own back end for processing:const checkout = await stripe.createEmbeddedCheckoutPage({ clientSecret: session.client_secret, onAnalyticsEvent: async (event) => { const { eventType, details, clientMetadata, checkoutSession, timestamp } = event; // Send to your backend analytics endpoint await fetch('/api/analytics', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ event_type: eventType, checkout_session: checkoutSession, details, client_metadata: clientMetadata, timestamp }) }); }, });
Use webhooks for conversion tracking
Use the checkout.session.completed webhook event to record successful payments:
// Server-side webhook handler
app.post("/webhook", express.raw({ type: "application/json" }), (req, res) => {
const payload = req.body;
const sig = req.headers["stripe-signature"];
let event;
try {
event = stripe.webhooks.constructEvent(
payload,
sig,
process.env.STRIPE_WEBHOOK_SECRET
);
} catch (err) {
return res.status(400).send(`Webhook Error: ${err.message}`);
}
if (event.type === 'checkout.session.completed') {
const session = event.data.object;
// Track successful conversion with Segment
analytics.track({
userId: session.customer,
event: 'Purchase Completed',
properties: {
checkout_id: session.id,
amount: session.amount_total / 100,
currency: session.currency,
funnel_id: session.client_metadata?.funnel_id,
campaign: session.client_metadata?.campaign,
}
});
}
res.status(200);
});
This approach gives you both real-time behavioral tracking (through analytics events) and accurate conversion data (through webhooks) to understand your checkout funnel performance.
TypeScript Types
If you’re using TypeScript, you can import the event types:
import type {StripeCheckoutAnalyticsEvent} from '@stripe/stripe-js';
const checkout = await stripe.createEmbeddedCheckoutPage({
clientSecret: session.client_secret,
onAnalyticsEvent: (event: StripeCheckoutAnalyticsEvent) => {
// TypeScript will provide full type checking
},
});
