Skip to main content
These events are designed for B2B SaaS and subscription-based businesses. If you’re running an e-commerce store, see Standard Events instead.

When to Use SaaS Events

Use these events when your business model includes:
  • Subscription billing (monthly/annual plans)
  • Free trials with conversion tracking
  • Seat-based pricing with expansion revenue
  • Multi-user accounts with role-based access
  • Product-led growth with feature usage tracking

Account Lifecycle

Track account creation and deletion to measure growth and churn.

account_created

Fires when a new account (organization/workspace) is created.

JavaScript

window._upstack('track', 'account_created', {
  accountId: 'acct_abc123',
  accountName: 'Acme Corporation',
  planId: 'plan_starter_monthly',
  planName: 'Starter',
  userId: 'usr_xyz789',
  userEmail: 'jane@acme.com'
});

Properties

PropertyTypeRequiredDescription
accountIdstringYesUnique account identifier
accountNamestringNoAccount/organization name
planIdstringNoInitial plan identifier
planNamestringNoInitial plan name
userIdstringNoCreating user’s ID
userEmailstringNoCreating user’s email

When to Fire

  • After account registration completes
  • After organization setup wizard finishes
  • After SSO provisioning creates a new workspace

account_deleted

Fires when an account is permanently deleted.

JavaScript

window._upstack('track', 'account_deleted', {
  accountId: 'acct_abc123',
  accountName: 'Acme Corporation',
  cancelReason: 'no_longer_needed',
  cancelFeedback: 'Switching to a different solution',
  mrr: 9900
});

Properties

PropertyTypeRequiredDescription
accountIdstringYesDeleted account identifier
accountNamestringNoAccount name
cancelReasonstringNoReason code for deletion
cancelFeedbackstringNoUser-provided feedback
mrrnumberNoLost MRR in cents

When to Fire

  • After account deletion confirmation
  • After workspace removal completes
  • After data retention period expires

Acquisition

Track the lead-to-signup funnel to measure conversion rates.

signup_started

Fires when a user begins the signup flow.

JavaScript

window._upstack('track', 'signup_started', {
  planId: 'plan_pro_monthly',
  source: 'pricing_page'
});

Properties

PropertyTypeRequiredDescription
planIdstringNoPre-selected plan (if applicable)
sourcestringNoWhere signup was initiated

When to Fire

  • When signup form is opened
  • When registration page loads
  • When “Start Free Trial” button is clicked

signup_completed

Fires when a user completes signup and creates an account.

JavaScript

window._upstack('track', 'signup_completed', {
  userId: 'usr_xyz789',
  accountId: 'acct_abc123',
  userEmail: 'jane@acme.com',
  planId: 'plan_pro_monthly',
  planName: 'Pro Plan'
});

Properties

PropertyTypeRequiredDescription
userIdstringYesNew user identifier
accountIdstringYesNew account identifier
userEmailstringNoUser email address
planIdstringNoSelected plan
planNamestringNoPlan display name

When to Fire

  • After signup form submission succeeds
  • After email verification completes
  • After OAuth signup flow finishes

demo_requested

Fires when a user requests a product demo.

JavaScript

window._upstack('track', 'demo_requested', {
  userEmail: 'buyer@enterprise.com',
  companyName: 'Enterprise Corp',
  companySize: '500-1000',
  useCase: 'marketing_analytics'
});

Properties

PropertyTypeRequiredDescription
userEmailstringNoRequester email
companyNamestringNoCompany name
companySizestringNoCompany size range
useCasestringNoPrimary use case

When to Fire

  • After demo request form submission
  • After sales call booking confirmation
  • After Calendly/HubSpot meeting scheduled

Trial Events

Track the trial lifecycle from start to conversion or expiry.

trial_started

Fires when a user begins a free trial.

JavaScript

window._upstack('track', 'trial_started', {
  accountId: 'acct_abc123',
  planId: 'plan_pro_monthly',
  planName: 'Pro Plan',
  trialEndDate: '2026-03-04T14:30:00.000Z',
  trialDaysRemaining: 14
});

Properties

PropertyTypeRequiredDescription
accountIdstringYesAccount identifier
planIdstringYesTrial plan identifier
planNamestringNoHuman-readable plan name
trialEndDatestringNoISO 8601 trial expiration date
trialDaysRemainingnumberNoDays until trial expires

When to Fire

  • After trial signup confirmation
  • After trial activation in billing system
  • After Stripe customer.subscription.created with trial

trial_activated

Fires when a trial user reaches a meaningful activation milestone.

JavaScript

window._upstack('track', 'trial_activated', {
  accountId: 'acct_abc123',
  planId: 'plan_pro_monthly',
  trialDaysRemaining: 12,
  activationMilestone: 'first_integration_connected'
});

Properties

PropertyTypeRequiredDescription
accountIdstringYesAccount identifier
planIdstringNoTrial plan identifier
trialDaysRemainingnumberNoDays remaining in trial
activationMilestonestringNoWhich milestone was reached

When to Fire

  • After first key feature is used
  • After onboarding checklist is completed
  • After first data import succeeds

trial_extended

Fires when a trial period is extended.

JavaScript

window._upstack('track', 'trial_extended', {
  accountId: 'acct_abc123',
  trialEndDate: '2026-03-11T14:30:00.000Z',
  trialDaysRemaining: 7,
  extensionReason: 'support_request'
});

Properties

PropertyTypeRequiredDescription
accountIdstringYesAccount identifier
trialEndDatestringNoNew trial end date
trialDaysRemainingnumberNoNew days remaining
extensionReasonstringNoWhy trial was extended

When to Fire

  • After support manually extends trial
  • After promotional extension is applied
  • After win-back campaign grants extension

trial_ending_soon

Fires when a trial is about to expire (typically 3 days before).

JavaScript

window._upstack('track', 'trial_ending_soon', {
  accountId: 'acct_abc123',
  trialDaysRemaining: 3,
  planId: 'plan_pro_monthly',
  trialEndDate: '2026-03-04T14:30:00.000Z'
});

Properties

PropertyTypeRequiredDescription
accountIdstringYesAccount identifier
trialDaysRemainingnumberYesDays until expiry
planIdstringNoTrial plan identifier
trialEndDatestringNoTrial expiration date

When to Fire

  • 3 days before trial expires (common)
  • When Stripe sends customer.subscription.trial_will_end
  • When automated warning email triggers

trial_expired

Fires when a trial ends without conversion.

JavaScript

window._upstack('track', 'trial_expired', {
  accountId: 'acct_abc123',
  planId: 'plan_pro_monthly',
  planName: 'Pro Plan',
  trialDays: 14
});

Properties

PropertyTypeRequiredDescription
accountIdstringYesAccount identifier
planIdstringNoExpired trial plan
planNamestringNoPlan display name
trialDaysnumberNoTotal trial length

When to Fire

  • When trial end date is reached without payment
  • When account is downgraded to free tier
  • When access is revoked after grace period

trial_converted

Fires when a trial converts to a paid subscription. This is a key conversion event.

JavaScript

window._upstack('track', 'trial_converted', {
  accountId: 'acct_abc123',
  subscriptionId: 'sub_def456',
  planId: 'plan_pro_monthly',
  planName: 'Pro Plan',
  mrr: 9900,
  billingInterval: 'month'
});

Properties

PropertyTypeRequiredDescription
accountIdstringYesAccount identifier
subscriptionIdstringYesNew subscription ID
planIdstringYesConverted plan identifier
planNamestringNoPlan display name
mrrnumberNoMonthly recurring revenue in cents
billingIntervalstringNomonth or year

When to Fire

  • After first successful payment
  • When Stripe subscription status changes from trialing to active
  • After payment method is charged successfully
Track mrr to measure trial-to-paid conversion value and calculate average revenue per converted trial.

Subscription Lifecycle

Track the complete subscription journey from creation through churn or reactivation.

subscription_created

Fires when a subscription record is created in your billing system.

JavaScript

window._upstack('track', 'subscription_created', {
  subscriptionId: 'sub_def456',
  accountId: 'acct_abc123',
  planId: 'plan_pro_monthly',
  planName: 'Pro Plan',
  billingInterval: 'month'
});

Properties

PropertyTypeRequiredDescription
subscriptionIdstringYesSubscription identifier
accountIdstringYesAccount identifier
planIdstringYesPlan identifier
planNamestringNoPlan display name
billingIntervalstringNoday, week, month, or year

When to Fire

  • When subscription object is created in Stripe
  • May precede first payment (for trials)
  • After checkout session completes

subscription_started

Fires when a new subscription begins (first billing period starts).

JavaScript

window._upstack('track', 'subscription_started', {
  subscriptionId: 'sub_def456',
  accountId: 'acct_abc123',
  planId: 'plan_pro_monthly',
  planName: 'Pro Plan',
  mrr: 9900,
  billingInterval: 'month'
});

Properties

PropertyTypeRequiredDescription
subscriptionIdstringYesSubscription identifier
accountIdstringYesAccount identifier
planIdstringYesPlan identifier
planNamestringNoPlan display name
mrrnumberNoMonthly recurring revenue in cents
billingIntervalstringNoBilling frequency

When to Fire

  • After first successful charge
  • When subscription status becomes active
  • After trial converts to paid

subscription_upgraded

Fires when a customer upgrades to a higher-tier plan.

JavaScript

window._upstack('track', 'subscription_upgraded', {
  subscriptionId: 'sub_def456',
  accountId: 'acct_abc123',
  planId: 'plan_business_monthly',
  planName: 'Business',
  previousPlanId: 'plan_pro_monthly',
  mrr: 19900,
  mrrDelta: 10000
});

Properties

PropertyTypeRequiredDescription
subscriptionIdstringYesSubscription identifier
accountIdstringYesAccount identifier
planIdstringNoNew plan identifier
planNamestringNoNew plan name
previousPlanIdstringNoPrevious plan identifier
mrrnumberNoNew MRR after upgrade in cents
mrrDeltanumberNoMRR increase in cents (positive)

When to Fire

  • When plan changes from lower to higher tier
  • When Stripe subscription item is updated with higher-priced plan
  • After upgrade checkout completes
Track mrrDelta alongside subscription_downgraded to calculate net revenue retention.

subscription_downgraded

Fires when a customer downgrades to a lower-tier plan.

JavaScript

window._upstack('track', 'subscription_downgraded', {
  subscriptionId: 'sub_def456',
  accountId: 'acct_abc123',
  planId: 'plan_starter_monthly',
  planName: 'Starter',
  previousPlanId: 'plan_pro_monthly',
  mrr: 4900,
  mrrDelta: -5000
});

Properties

PropertyTypeRequiredDescription
subscriptionIdstringYesSubscription identifier
accountIdstringYesAccount identifier
planIdstringNoNew plan identifier
planNamestringNoNew plan name
previousPlanIdstringNoPrevious plan identifier
mrrnumberNoNew MRR after downgrade in cents
mrrDeltanumberNoMRR decrease in cents (negative)

When to Fire

  • When plan changes from higher to lower tier
  • When features are removed from subscription
  • When scheduled downgrade takes effect at period end

subscription_renewed

This is a custom event name. For standard renewal tracking, consider using payment_succeeded or invoice_paid events instead.
Fires when a subscription successfully renews for another billing period.

JavaScript

window._upstack('track', 'subscription_renewed', {
  subscriptionId: 'sub_def456',
  accountId: 'acct_abc123',
  planId: 'plan_pro_monthly',
  mrr: 9900,
  renewalCount: 6
});

Properties

PropertyTypeRequiredDescription
subscriptionIdstringYesSubscription identifier
accountIdstringYesAccount identifier
planIdstringNoCurrent plan identifier
mrrnumberNoRenewed MRR in cents
renewalCountnumberNoNumber of times renewed

When to Fire

  • When recurring payment succeeds
  • When billing period advances
  • When Stripe invoice.paid fires for subscription

subscription_paused

Fires when a subscription is paused.

JavaScript

window._upstack('track', 'subscription_paused', {
  subscriptionId: 'sub_def456',
  accountId: 'acct_abc123',
  planId: 'plan_pro_monthly',
  mrr: 9900,
  pauseReason: 'seasonal_business'
});

Properties

PropertyTypeRequiredDescription
subscriptionIdstringYesSubscription identifier
accountIdstringYesAccount identifier
planIdstringNoPlan identifier
mrrnumberNoPaused MRR in cents
pauseReasonstringNoWhy subscription was paused

When to Fire

  • When customer requests pause
  • When seasonal pause is activated
  • When Stripe subscription pause feature triggers

subscription_resumed

Fires when a paused subscription is resumed.

JavaScript

window._upstack('track', 'subscription_resumed', {
  subscriptionId: 'sub_def456',
  accountId: 'acct_abc123',
  planId: 'plan_pro_monthly',
  mrr: 9900,
  pausedDays: 30
});

Properties

PropertyTypeRequiredDescription
subscriptionIdstringYesSubscription identifier
accountIdstringYesAccount identifier
planIdstringNoPlan identifier
mrrnumberNoResumed MRR in cents
pausedDaysnumberNoHow long subscription was paused

When to Fire

  • When customer manually resumes
  • When pause period ends automatically
  • When billing restarts

subscription_cancelled

Fires when a cancellation is requested (may still be active until period end).

JavaScript

window._upstack('track', 'subscription_cancelled', {
  subscriptionId: 'sub_def456',
  accountId: 'acct_abc123',
  planId: 'plan_pro_monthly',
  cancelReason: 'too_expensive',
  cancelFeedback: 'Budget constraints this quarter',
  mrr: 9900,
  cancelAtPeriodEnd: true
});

Properties

PropertyTypeRequiredDescription
subscriptionIdstringYesSubscription identifier
accountIdstringYesAccount identifier
planIdstringNoCancelled plan
cancelReasonstringNoCancellation reason code
cancelFeedbackstringNoUser-provided feedback
mrrnumberNoMRR being cancelled in cents
cancelAtPeriodEndbooleanNoIf true, cancels at end of billing period

When to Fire

  • When customer clicks cancel button
  • When cancellation request is submitted
  • When Stripe subscription is set to cancel at period end

subscription_churned

Fires when a subscription ends completely (no longer billing). This is the final churn event.

JavaScript

window._upstack('track', 'subscription_churned', {
  subscriptionId: 'sub_def456',
  accountId: 'acct_abc123',
  planId: 'plan_pro_monthly',
  cancelReason: 'switched_competitor',
  mrr: 9900,
  ltv: 118800,
  subscriptionMonths: 12
});

Properties

PropertyTypeRequiredDescription
subscriptionIdstringYesSubscription identifier
accountIdstringYesAccount identifier
planIdstringNoChurned plan
cancelReasonstringNoChurn reason
mrrnumberNoLost MRR in cents
ltvnumberNoCustomer lifetime value in cents
subscriptionMonthsnumberNoHow long they were subscribed

When to Fire

  • When final billing period ends
  • When subscription is deactivated
  • When Stripe customer.subscription.deleted fires
Use this event to calculate churn rate and analyze churn reasons. Track ltv to understand which customer segments have the highest lifetime value.

subscription_initial_purchase

Fires when a customer’s first subscription payment is processed (distinct from trial conversion).

JavaScript

window._upstack('track', 'subscription_initial_purchase', {
  subscriptionId: 'sub_def456',
  accountId: 'acct_abc123',
  planId: 'plan_pro_monthly',
  planName: 'Pro Plan',
  value: 9900,
  currency: 'USD',
  billingInterval: 'month'
});

Properties

PropertyTypeRequiredDescription
subscriptionIdstringYesSubscription identifier
accountIdstringYesAccount identifier
planIdstringNoPlan identifier
planNamestringNoPlan display name
valuenumberNoPayment amount in cents
currencystringNoISO 4217 currency code
billingIntervalstringNomonth or year

When to Fire

  • First subscription charge succeeds
  • After trial converts (first paid billing period)
  • When new customer’s initial payment processes

subscription_recurring_purchase

Fires when a recurring subscription payment is processed (not the initial purchase).

JavaScript

window._upstack('track', 'subscription_recurring_purchase', {
  subscriptionId: 'sub_def456',
  accountId: 'acct_abc123',
  planId: 'plan_pro_monthly',
  planName: 'Pro Plan',
  value: 9900,
  currency: 'USD',
  billingInterval: 'month',
  renewalNumber: 6
});

Properties

PropertyTypeRequiredDescription
subscriptionIdstringYesSubscription identifier
accountIdstringYesAccount identifier
planIdstringNoPlan identifier
planNamestringNoPlan display name
valuenumberNoPayment amount in cents
currencystringNoISO 4217 currency code
billingIntervalstringNomonth or year
renewalNumbernumberNoWhich renewal this is (2nd, 3rd, etc.)

When to Fire

  • Each recurring billing cycle
  • When Stripe invoice.paid fires for an existing subscription
  • Monthly/annual renewal charge succeeds
Use subscription_initial_purchase for acquisition metrics and subscription_recurring_purchase for retention/LTV analysis. Together they give a complete picture of subscription revenue.

subscription_reactivated

Fires when a previously churned customer resubscribes.

JavaScript

window._upstack('track', 'subscription_reactivated', {
  subscriptionId: 'sub_ghi789',
  accountId: 'acct_abc123',
  planId: 'plan_pro_monthly',
  planName: 'Pro Plan',
  mrr: 9900,
  daysSinceChurn: 45
});

Properties

PropertyTypeRequiredDescription
subscriptionIdstringYesNew subscription identifier
accountIdstringYesAccount identifier
planIdstringNoNew plan identifier
planNamestringNoPlan display name
mrrnumberNoRecovered MRR in cents
daysSinceChurnnumberNoDays between churn and reactivation

When to Fire

  • When former customer signs up again
  • When win-back campaign converts
  • When churned account starts new subscription

Order Fulfillment Events

Track order fulfillment and shipping for e-commerce subscription boxes, physical product deliveries, and Klaviyo flow triggers.

order_fulfilled

Fires when an order has been completely fulfilled (all items prepared for shipment).

JavaScript

window._upstack('track', 'order_fulfilled', {
  orderId: 'ORD_12345',
  orderName: '#1042',
  value: 149.99,
  currency: 'USD',
  fulfillmentStatus: 'fulfilled',
  items: [
    {
      id: 'SKU_001',
      name: 'Monthly Snack Box',
      price: 39.99,
      quantity: 1
    }
  ],
  email: 'customer@example.com'
});

Properties

PropertyTypeRequiredDescription
orderIdstringYesOrder identifier
orderNamestringNoHuman-readable order name
valuenumberNoOrder value
currencystringNoISO 4217 currency code
fulfillmentStatusstringNoFulfillment status (e.g., 'fulfilled', 'partial')
itemsarrayNoProducts fulfilled
emailstringNoCustomer email

When to Fire

  • When warehouse marks order as packed/ready
  • When Shopify fulfillment is created
  • When all items in an order are fulfilled

order_shipped

Fires when an order has been shipped and tracking information is available.

JavaScript

window._upstack('track', 'order_shipped', {
  orderId: 'ORD_12345',
  orderName: '#1042',
  value: 149.99,
  currency: 'USD',
  trackingNumber: '1Z999AA10123456784',
  trackingCompany: 'UPS',
  trackingUrl: 'https://www.ups.com/track?tracknum=1Z999AA10123456784',
  estimatedDelivery: '2026-02-25T00:00:00.000Z',
  items: [
    {
      id: 'SKU_001',
      name: 'Monthly Snack Box',
      price: 39.99,
      quantity: 1
    }
  ],
  email: 'customer@example.com'
});

Properties

PropertyTypeRequiredDescription
orderIdstringYesOrder identifier
orderNamestringNoHuman-readable order name
valuenumberNoOrder value
currencystringNoISO 4217 currency code
trackingNumberstringNoCarrier tracking number
trackingCompanystringNoShipping carrier (e.g., 'UPS', 'FedEx', 'USPS')
trackingUrlstringNoDirect link to tracking page
estimatedDeliverystringNoISO 8601 estimated delivery date
itemsarrayNoProducts shipped
emailstringNoCustomer email

When to Fire

  • When shipping label is created with tracking
  • When carrier picks up package
  • When Shopify fulfillment_events/create webhook fires
Klaviyo integration: order_shipped is commonly used to trigger post-purchase flows like “Your order is on the way” emails with tracking information.

User Events

Track team growth and user engagement within accounts.

user_invited

Fires when a user is invited to join an account.

JavaScript

window._upstack('track', 'user_invited', {
  accountId: 'acct_abc123',
  inviteeEmail: 'newmember@acme.com',
  inviteeRole: 'member',
  invitedByUserId: 'usr_xyz789'
});

Properties

PropertyTypeRequiredDescription
accountIdstringYesAccount identifier
inviteeEmailstringNoInvitee email address
inviteeRolestringNoAssigned role
invitedByUserIdstringNoInviter’s user ID

When to Fire

  • When team invite is sent
  • When collaboration request is initiated
  • After invite email is dispatched

user_joined

Fires when an invited user accepts and joins the account.

JavaScript

window._upstack('track', 'user_joined', {
  userId: 'usr_newmember',
  accountId: 'acct_abc123',
  userEmail: 'newmember@acme.com',
  userRole: 'member'
});

Properties

PropertyTypeRequiredDescription
userIdstringYesNew user identifier
accountIdstringYesAccount identifier
userEmailstringNoUser email address
userRolestringNoUser’s assigned role

When to Fire

  • When invite is accepted
  • When account access is granted
  • After user completes join flow

user_role_changed

This is a custom event name. Track it using the Custom Events pattern if you need role change analytics.
Fires when a user’s role is changed within an account.

JavaScript

window._upstack('track', 'user_role_changed', {
  userId: 'usr_xyz789',
  accountId: 'acct_abc123',
  previousRole: 'member',
  newRole: 'admin',
  changedByUserId: 'usr_admin123'
});

Properties

PropertyTypeRequiredDescription
userIdstringYesUser whose role changed
accountIdstringYesAccount identifier
previousRolestringNoPrevious role
newRolestringNoNew role
changedByUserIdstringNoAdmin who made the change

When to Fire

  • When user is promoted to admin
  • When permissions are modified
  • After role update is saved

Billing Events

Track payment activity for revenue analytics and dunning workflows.

payment_succeeded

Fires when a payment is processed successfully.

JavaScript

window._upstack('track', 'payment_succeeded', {
  accountId: 'acct_abc123',
  invoiceId: 'inv_ghi012',
  subscriptionId: 'sub_def456',
  amount: 9900,
  currency: 'USD'
});

Properties

PropertyTypeRequiredDescription
accountIdstringYesAccount identifier
amountnumberYesPayment amount in cents
invoiceIdstringNoInvoice identifier
subscriptionIdstringNoSubscription identifier
currencystringNoISO 4217 currency code

When to Fire

  • When charge succeeds
  • When invoice is paid
  • When Stripe invoice.paid webhook fires

payment_failed

Fires when a payment attempt fails.

JavaScript

window._upstack('track', 'payment_failed', {
  accountId: 'acct_abc123',
  invoiceId: 'inv_ghi012',
  subscriptionId: 'sub_def456',
  amount: 9900,
  failureReason: 'card_declined',
  failureCode: 'insufficient_funds',
  currency: 'USD'
});

Properties

PropertyTypeRequiredDescription
accountIdstringYesAccount identifier
amountnumberYesFailed payment amount in cents
invoiceIdstringNoInvoice identifier
subscriptionIdstringNoSubscription identifier
failureReasonstringNoFailure reason code
failureCodestringNoDetailed failure code
currencystringNoISO 4217 currency code

When to Fire

  • When card is declined
  • When insufficient funds error occurs
  • When Stripe invoice.payment_failed webhook fires
Track payment failures to identify at-risk customers and trigger dunning workflows.

invoice_paid

Fires when an invoice is marked as paid.

JavaScript

window._upstack('track', 'invoice_paid', {
  accountId: 'acct_abc123',
  invoiceId: 'inv_ghi012',
  subscriptionId: 'sub_def456',
  amount: 9900,
  currency: 'USD'
});

Properties

PropertyTypeRequiredDescription
accountIdstringYesAccount identifier
invoiceIdstringYesInvoice identifier
amountnumberYesPaid amount in cents
subscriptionIdstringNoSubscription identifier
currencystringNoISO 4217 currency code

When to Fire

  • When payment is received
  • When manual reconciliation marks invoice paid
  • When Stripe invoice.paid webhook fires

Expansion Events

Track seat-based and add-on revenue expansion.

seat_added

Fires when additional seats are purchased.

JavaScript

window._upstack('track', 'seat_added', {
  accountId: 'acct_abc123',
  subscriptionId: 'sub_def456',
  seatCount: 15,
  seatDelta: 5,
  mrrDelta: 2500
});

Properties

PropertyTypeRequiredDescription
accountIdstringYesAccount identifier
seatCountnumberYesTotal seats after addition
subscriptionIdstringNoSubscription identifier
seatDeltanumberNoNumber of seats added
mrrDeltanumberNoMRR increase from seats in cents

When to Fire

  • When seats are purchased
  • When user is added beyond plan limit
  • When Stripe subscription quantity increases

seat_removed

Fires when seats are removed from the plan.

JavaScript

window._upstack('track', 'seat_removed', {
  accountId: 'acct_abc123',
  subscriptionId: 'sub_def456',
  seatCount: 10,
  seatDelta: -5,
  mrrDelta: -2500
});

Properties

PropertyTypeRequiredDescription
accountIdstringYesAccount identifier
seatCountnumberYesTotal seats after removal
subscriptionIdstringNoSubscription identifier
seatDeltanumberNoNumber of seats removed (negative)
mrrDeltanumberNoMRR decrease in cents (negative)

When to Fire

  • When seats are removed
  • When user is deactivated
  • When Stripe subscription quantity decreases

Engagement Events

Track user activity and product milestones.

feature_used

Fires when a specific feature is used. Track key features to understand product adoption.

JavaScript

window._upstack('track', 'feature_used', {
  accountId: 'acct_abc123',
  userId: 'usr_xyz789',
  featureId: 'feat_export',
  featureName: 'CSV Export',
  featureCategory: 'reporting'
});

Properties

PropertyTypeRequiredDescription
accountIdstringYesAccount identifier
featureIdstringYesFeature identifier
userIdstringNoUser who used the feature
featureNamestringNoFeature display name
featureCategorystringNoFeature category

When to Fire

  • When key features are used
  • When premium features are accessed
  • When usage-based actions are performed

milestone_reached

Fires when a key milestone is achieved.

JavaScript

window._upstack('track', 'milestone_reached', {
  accountId: 'acct_abc123',
  milestoneId: 'milestone_100_orders',
  milestoneName: '100 Orders Processed',
  milestoneValue: 100
});

Properties

PropertyTypeRequiredDescription
accountIdstringYesAccount identifier
milestoneIdstringYesMilestone identifier
milestoneNamestringNoMilestone display name
milestoneValuenumberNoNumeric value achieved

When to Fire

  • When usage threshold is crossed
  • When achievement is unlocked
  • When significant product milestone occurs

Stripe Webhook Integration

If you use Stripe for billing, handle webhooks to track events automatically.
Webhook handlers run server-side where window._upstack() is not available. Server-side event tracking requires the Upstack Server API. Contact support for early access, or use the patterns below to queue events for client-side tracking.

Server-Side Helper Pattern

Create a helper to queue events for server-side tracking:
// utils/tracking.js
async function trackServerEvent(eventName, properties) {
  // Option 1: Direct API call (requires Server API access)
  await fetch('https://api.getupstack.com/v1/events', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'Authorization': `Bearer ${process.env.UPSTACK_API_KEY}`
    },
    body: JSON.stringify({
      event: eventName,
      properties,
      timestamp: new Date().toISOString()
    })
  });
  
  // Option 2: Store in database for later sync
  // await db.pendingEvents.create({ eventName, properties });
}

Example Webhook Handler

// Express.js webhook handler (server-side)
app.post('/webhooks/stripe', async (req, res) => {
  const event = stripe.webhooks.constructEvent(
    req.body,
    req.headers['stripe-signature'],
    process.env.STRIPE_WEBHOOK_SECRET
  );

  switch (event.type) {
    case 'customer.subscription.created':
      const sub = event.data.object;
      await trackServerEvent('subscription_created', {
        subscriptionId: sub.id,
        accountId: sub.metadata.account_id,
        planId: sub.items.data[0].price.id,
        billingInterval: sub.items.data[0].price.recurring.interval
      });
      break;

    case 'customer.subscription.updated':
      const updated = event.data.object;
      const previous = event.data.previous_attributes;
      
      if (previous.items) {
        const newPrice = updated.items.data[0].price.unit_amount;
        const oldPrice = previous.items.data[0].price.unit_amount;
        
        if (newPrice > oldPrice) {
          await trackServerEvent('subscription_upgraded', {
            subscriptionId: updated.id,
            accountId: updated.metadata.account_id,
            planId: updated.items.data[0].price.id,
            mrrDelta: newPrice - oldPrice
          });
        } else {
          await trackServerEvent('subscription_downgraded', {
            subscriptionId: updated.id,
            accountId: updated.metadata.account_id,
            planId: updated.items.data[0].price.id,
            mrrDelta: newPrice - oldPrice
          });
        }
      }
      break;

    case 'customer.subscription.deleted':
      const deleted = event.data.object;
      await trackServerEvent('subscription_churned', {
        subscriptionId: deleted.id,
        accountId: deleted.metadata.account_id,
        planId: deleted.items.data[0].price.id,
        mrr: deleted.items.data[0].price.unit_amount
      });
      break;

    case 'invoice.paid':
      const invoice = event.data.object;
      await trackServerEvent('payment_succeeded', {
        accountId: invoice.metadata.account_id,
        invoiceId: invoice.id,
        subscriptionId: invoice.subscription,
        amount: invoice.amount_paid,
        currency: invoice.currency.toUpperCase()
      });
      break;

    case 'invoice.payment_failed':
      const failed = event.data.object;
      await trackServerEvent('payment_failed', {
        accountId: failed.metadata.account_id,
        invoiceId: failed.id,
        subscriptionId: failed.subscription,
        amount: failed.amount_due,
        failureReason: failed.last_payment_error?.code
      });
      break;

    case 'customer.subscription.trial_will_end':
      const trial = event.data.object;
      await trackServerEvent('trial_ending_soon', {
        accountId: trial.metadata.account_id,
        trialDaysRemaining: 3,
        planId: trial.items.data[0].price.id,
        trialEndDate: new Date(trial.trial_end * 1000).toISOString()
      });
      break;
  }

  res.json({ received: true });
});

Stripe Webhook Mapping

Stripe WebhookUpstack Event
customer.subscription.createdsubscription_created
customer.subscription.updatedsubscription_upgraded / subscription_downgraded
customer.subscription.deletedsubscription_churned
customer.subscription.pausedsubscription_paused
customer.subscription.resumedsubscription_resumed
invoice.paidinvoice_paid, payment_succeeded
invoice.payment_failedpayment_failed
customer.subscription.trial_will_endtrial_ending_soon
charge.refundedpayment_refunded

What’s Next

Standard Events

E-commerce event reference for Shopify stores.

Custom Events

Define your own events beyond the standard taxonomy.

Properties & Context

Complete reference for all event fields.

Event Taxonomy

How events flow through the Upstack pipeline.