Revenue

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

  1. Go to your website in the Databuddy dashboard
  2. Navigate to Revenue in the sidebar
  3. Click the Configure button in the top right
  4. 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_hash

Click the copy button next to the URL to copy it to your clipboard.

Create a Webhook in Stripe

  1. Go to dashboard.stripe.com/webhooks/create
  2. In the Endpoint URL field, paste your Databuddy webhook URL
  3. Under Select events to listen to, click Select events
  4. 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 attempts
  • payment_intent.payment_failed - Tracks failed one-time payment attempts
  • payment_intent.canceled - Tracks canceled payment attempts

Subscription lifecycle events (for tracking subscriber state):

  • customer.subscription.created - When a new subscription starts
  • customer.subscription.updated - Plan changes, status transitions
  • customer.subscription.deleted - When a subscription ends
  • customer.subscription.paused - When a subscription is paused
  • customer.subscription.resumed - When a paused subscription resumes
  1. Click Add endpoint

Copy the Signing Secret

After creating the webhook:

  1. Click on your newly created webhook endpoint
  2. In the Signing secret section, click Reveal
  3. Copy the secret (it starts with whsec_)

Paste the Secret in Databuddy

  1. Return to the Revenue settings sheet in Databuddy
  2. In the Signing secret field under Stripe, paste your webhook secret
  3. 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:

  1. payment_intent.succeeded - Fires when the PaymentIntent on a subscription invoice succeeds. Databuddy detects it as a subscription by checking for the invoice field on the PaymentIntent.
  2. 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:

EventWhat It Captures
createdNew subscription started (status may be active, trialing, or incomplete)
updatedPlan changes, status transitions (e.g. active to past_due)
deletedSubscription fully ended
pausedSubscription paused (no invoices generated)
resumedPaused 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.

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 sessionStorage as did_session
  • Session Format: sess_{timestamp}_{random_string} (e.g., sess_lm8k9x_abc123def456)
  • Anonymous ID: Automatically generated and stored in localStorage as did
  • 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

javascript
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)

javascript
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)

javascript
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,
  },
},
});

Server-Side: Python

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

tsx
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

FieldRequiredDescription
databuddy_client_idYesYour Databuddy Client ID for webhook processing
databuddy_session_idYesCurrent session ID from getSessionId() or sessionStorage.getItem('did_session')
databuddy_anonymous_idNoAnonymous user ID from getAnonymousId() or localStorage.getItem('did')

Testing

Test Mode Setup

  1. Use Stripe Test Mode: Ensure your webhook is configured for test mode
  2. Use Test Cards: Use Stripe's test card numbers
  3. 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

  1. Create a test purchase using a test card
  2. Check Stripe Dashboard: Verify the webhook was called successfully
  3. Check Databuddy Dashboard: Confirm payment data appears in your analytics
  4. 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_id in payment_intent_data.metadata
  • For subscriptions: set databuddy_client_id in subscription_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_id in metadata contains the correct session ID
  • Use getSessionId() from @databuddy/sdk or sessionStorage.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

How is this guide?