Stripe | Financial Infrastructure to Grow Your Revenue

Stripe | Financial Infrastructure to Grow Your Revenue

4466 articles

Track analytics events in Embedded Checkout


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:

EventWhen we send itKey data
deviceDataWhen the checkout UI rendersDevice category, language, platform, viewport
checkoutRenderedWhen the checkout UI rendersLine items, currency, amount
promotionCodeAppliedWhen a promotional code is successfully appliedPromotion code
lineItemChangeWhen items, quantities, or currency changeLine items, currency, amount
checkoutSubmittedWhen a customer submits payment informationPayment method type, line items, currency, amount
checkoutSubmitFailedWhen a payment submission failsPayment 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 ReasonDescriptionExamples
api_errorNetwork or API errors, card declines, 3DS authentication failures, or server validation errors after valid payment information has been submittedSuch as card_declined, expired_card, incorrect_cvc, insufficient_funds, processing_error, api_connection_error, or payment method provider errors
user_cancelledUser canceled the payment flow after valid payment information has been submittedSuch as Link Klarna sign up flow dismissal
reverificationLink reverification required after valid payment information has been submittedLink session expired
unexpectedUnknown or unexpected errors after valid payment information has been submittedUnknown or unexpected errors

Implementation

  1. Create a Checkout Session with client metadata When creating your Checkout Session, include client_metadata to 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 in client_metadata is accessible on the client. Avoid sharing sensitive or confidential information through these fields.
  2. Initialize Embedded Checkout with an analytics event handler When initializing Embedded Checkout, include the onAnalyticsEvent handler: const checkout = await stripe.createEmbeddedCheckoutPage({ clientSecret: session.client_secret, onAnalyticsEvent: (event: StripeCheckoutAnalyticsEvent) => { // Handle the event here console.log('Received event:', event); }, });
  3. Handle analytics events In your onAnalyticsEvent handler, 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
 },
});
Last verified 2026-09-24

Is this helpful?