Stripe
Connect Stripe payments to Databuddy's analytics to track revenue, conversion funnels, and customer behavior. This integration links payment events to your website analytics for complete revenue attribution.
Overview
The Stripe integration captures:
- One-Time Payments: Track payment attempts, successes, and failures via PaymentIntents
- Subscription Payments: Track recurring invoice payments, renewals, and failures
- Refunds: Track refund events and amounts via charge events
- Revenue Attribution: Link payments to specific user sessions and marketing campaigns
Quick Setup (Webhooks Only)
For basic revenue tracking without session attribution:
Open Revenue Settings in Databuddy
- Go to your website in the Databuddy dashboard
- Navigate to Revenue in the sidebar
- Click the Configure button in the top right
- The Stripe section will be expanded by default
Copy the Webhook URL
In the Revenue settings sheet, you'll see a unique webhook URL for your website:
https://basket.databuddy.cc/webhooks/stripe/your_unique_hashClick the copy button next to the URL to copy it to your clipboard.
Create a Webhook in Stripe
- Go to dashboard.stripe.com/webhooks/create
- In the Endpoint URL field, paste your Databuddy webhook URL
- Under Select events to listen to, click Select events
- Search for and select the following events:
Required events (must be selected):
payment_intent.succeeded- Captures all successful payments (one-time and subscription)charge.refunded- Captures refund events
Recommended events (for subscription and failure tracking):
invoice.paid- Catches subscription payments without a PaymentIntent (credit balance, 100% coupons)invoice.payment_failed- Tracks failed subscription payment attemptspayment_intent.payment_failed- Tracks failed one-time payment attemptspayment_intent.canceled- Tracks canceled payment attempts
Subscription lifecycle events (for tracking subscriber state):
customer.subscription.created- When a new subscription startscustomer.subscription.updated- Plan changes, status transitionscustomer.subscription.deleted- When a subscription endscustomer.subscription.paused- When a subscription is pausedcustomer.subscription.resumed- When a paused subscription resumes
- Click Add endpoint
Copy the Signing Secret
After creating the webhook:
- Click on your newly created webhook endpoint
- In the Signing secret section, click Reveal
- Copy the secret (it starts with
whsec_)
Keep your signing secret secure. Never commit it to version control or share it publicly.
Paste the Secret in Databuddy
- Return to the Revenue settings sheet in Databuddy
- In the Signing secret field under Stripe, paste your webhook secret
- Click Save
The Stripe section will now show a checkmark indicating it's configured.
How Subscriptions Work
When a customer subscribes via Stripe Checkout, the payment chain is:
Checkout Session → Subscription → Invoice → PaymentIntent
Databuddy handles this automatically through two event paths:
payment_intent.succeeded- Fires when the PaymentIntent on a subscription invoice succeeds. Databuddy detects it as a subscription by checking for theinvoicefield on the PaymentIntent.invoice.paid- Catches edge cases where an invoice is paid without a PaymentIntent (credit balance, 100% coupon, free trials). If the invoice has a PaymentIntent, Databuddy skips it to avoid duplicate tracking.
For failed subscription payments, invoice.payment_failed provides richer context including the subscription ID and billing reason.
Subscription Lifecycle Tracking
When you enable the customer.subscription.* events, Databuddy tracks the full subscription lifecycle:
| Event | What It Captures |
|---|---|
created | New subscription started (status may be active, trialing, or incomplete) |
updated | Plan changes, status transitions (e.g. active to past_due) |
deleted | Subscription fully ended |
paused | Subscription paused (no invoices generated) |
resumed | Paused subscription resumed |
Lifecycle events are stored separately from revenue transactions, so they do not affect revenue totals. Each event records the subscription status, billing interval, customer ID, and period metadata.
You do not need to use Stripe's expand parameter. Webhook payloads include the full object, not just IDs. The expand parameter is only needed when fetching data from the Stripe API directly.
Advanced: Session Attribution
For full revenue attribution that links payments to user sessions, you need to pass Databuddy tracking IDs in your Stripe checkout metadata.
How Session Tracking Works
Databuddy automatically handles session and user IDs:
- Session ID: Automatically generated and stored in
sessionStorageasdid_session - Session Format:
sess_{timestamp}_{random_string}(e.g.,sess_lm8k9x_abc123def456) - Anonymous ID: Automatically generated and stored in
localStorageasdid - Anonymous Format:
anon_{uuid}(e.g.,anon_123e4567-e89b-12d3-a456-426614174000)
When you pass these IDs to Stripe via metadata, Databuddy can:
- Link payment events to specific user sessions
- Track the complete customer journey from first visit to purchase
- Attribute revenue to marketing campaigns and traffic sources
- Calculate conversion rates and customer lifetime value
Implementation
Using the Databuddy SDK (Recommended)
import { getTrackingIds } from '@databuddy/sdk';
// Get both session ID and anonymous ID
const { anonId, sessionId } = getTrackingIds();
// Send to your backend when creating checkout
await fetch('/create-checkout-session', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
sessionId,
anonymousId: anonId,
clientId: 'your_databuddy_client_id',
// ... other checkout data
}),
});Server-Side: One-Time Payment (Node.js)
const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY);
const session = await stripe.checkout.sessions.create({
payment_method_types: ['card'],
mode: 'payment',
line_items: [
{
price: 'price_1234567890',
quantity: 1,
},
],
success_url: 'https://yoursite.com/success?session_id={CHECKOUT_SESSION_ID}',
cancel_url: 'https://yoursite.com/cancel',
// REQUIRED: Set metadata on payment intent (this propagates to all webhook events)
payment_intent_data: {
metadata: {
databuddy_client_id: 'your_databuddy_client_id',
databuddy_session_id: sessionId,
databuddy_anonymous_id: anonymousId,
},
},
});Server-Side: Subscription (Node.js)
const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY);
const session = await stripe.checkout.sessions.create({
payment_method_types: ['card'],
mode: 'subscription',
line_items: [
{
price: 'price_monthly_1234567890',
quantity: 1,
},
],
success_url: 'https://yoursite.com/success?session_id={CHECKOUT_SESSION_ID}',
cancel_url: 'https://yoursite.com/cancel',
// For subscriptions, use subscription_data.metadata
// This metadata persists on the subscription and its invoices
subscription_data: {
metadata: {
databuddy_client_id: 'your_databuddy_client_id',
databuddy_session_id: sessionId,
databuddy_anonymous_id: anonymousId,
},
},
});For one-time payments, use `payment_intent_data.metadata`. For subscriptions, use `subscription_data.metadata`. Using the wrong one means metadata will not propagate to webhook events.
Server-Side: Python
import stripe
stripe.api_key = os.environ['STRIPE_SECRET_KEY']
# One-time payment
session = stripe.checkout.Session.create(
payment_method_types=['card'],
mode='payment',
line_items=[{
'price': 'price_1234567890',
'quantity': 1,
}],
success_url='https://yoursite.com/success?session_id={CHECKOUT_SESSION_ID}',
cancel_url='https://yoursite.com/cancel',
payment_intent_data={
'metadata': {
'databuddy_client_id': 'your_databuddy_client_id',
'databuddy_session_id': session_id,
'databuddy_anonymous_id': anonymous_id,
},
},
)
# Subscription
session = stripe.checkout.Session.create(
payment_method_types=['card'],
mode='subscription',
line_items=[{
'price': 'price_monthly_1234567890',
'quantity': 1,
}],
success_url='https://yoursite.com/success?session_id={CHECKOUT_SESSION_ID}',
cancel_url='https://yoursite.com/cancel',
subscription_data={
'metadata': {
'databuddy_client_id': 'your_databuddy_client_id',
'databuddy_session_id': session_id,
'databuddy_anonymous_id': anonymous_id,
},
},
)React/Next.js Example
import { getTrackingIds } from '@databuddy/sdk';
import { useState } from 'react';
function CheckoutButton({ priceId, productName }) {
const [isLoading, setIsLoading] = useState(false);
const handleCheckout = async () => {
setIsLoading(true);
try {
// Get tracking IDs from Databuddy SDK
const { anonId, sessionId } = getTrackingIds();
const response = await fetch('/api/create-checkout-session', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
priceId,
sessionId,
anonymousId: anonId,
clientId: process.env.NEXT_PUBLIC_DATABUDDY_CLIENT_ID,
}),
});
const { url } = await response.json();
window.location.href = url;
} catch (error) {
console.error('Checkout error:', error);
setIsLoading(false);
}
};
return (
<button onClick={handleCheckout} disabled={isLoading}>
{isLoading ? 'Processing...' : `Buy ${productName}`}
</button>
);
}Metadata Fields Reference
| Field | Required | Description |
|---|---|---|
databuddy_client_id | Yes | Your Databuddy Client ID for webhook processing |
databuddy_session_id | Yes | Current session ID from getSessionId() or sessionStorage.getItem('did_session') |
databuddy_anonymous_id | No | Anonymous user ID from getAnonymousId() or localStorage.getItem('did') |
For one-time payments, use payment_intent_data.metadata which propagates to PaymentIntent webhook events. For subscriptions, use subscription_data.metadata which persists on the subscription and its invoices.
Testing
Test Mode Setup
- Use Stripe Test Mode: Ensure your webhook is configured for test mode
- Use Test Cards: Use Stripe's test card numbers
- Monitor Webhook Events: Check your Databuddy dashboard for incoming events
Test Card Numbers
- Successful Payment:
4242424242424242 - Payment Requires Authentication:
4000002500003155 - Payment Fails:
4000000000000002 - Insufficient Funds:
4000000000009995
Verify Data Flow
- Create a test purchase using a test card
- Check Stripe Dashboard: Verify the webhook was called successfully
- Check Databuddy Dashboard: Confirm payment data appears in your analytics
- Verify Attribution: Ensure payment is linked to the correct session
Troubleshooting
Missing databuddy_client_id Error
Problem: Webhook receives events but shows "Missing required client_id" error
Solutions:
- For one-time payments: set
databuddy_client_idinpayment_intent_data.metadata - For subscriptions: set
databuddy_client_idinsubscription_data.metadata - Verify the databuddy_client_id matches your Databuddy Client ID exactly
- Don't set metadata directly on the checkout session object
Session ID Not Linking
Problem: Payments appear in Databuddy but aren't linked to user sessions
Solutions:
- Verify
databuddy_session_idin metadata contains the correct session ID - Use
getSessionId()from@databuddy/sdkorsessionStorage.getItem('did_session') - Ensure Databuddy has initialized before creating the checkout session
- Make sure the session hasn't expired (30-minute timeout)
Webhook Signature Verification Failed
Problem: Webhook returns "Invalid signature" error
Solutions:
- Verify webhook secret is correct (starts with
whsec_) - Ensure webhook secret matches between Stripe and Databuddy
- Check that webhook endpoint URL is exactly as configured
Related Resources
How is this guide?