Getting Started with Multibuzz

Server-side multi-touch attribution tracking for your application.


Platform Integrations

Using a supported platform? Follow the dedicated guide:

Platform Integration Type Guide
Shopify Zero-code (App + Pixel) Shopify Integration →

For custom applications, continue with the SDK integration below.


The 4-Call Model

Multibuzz uses a simple 4-call SDK model:

Method Purpose When to Call
init Configure SDK App startup
event Track journey steps User interactions (page views, add to cart, etc.)
conversion Track revenue outcomes Purchases, signups, subscriptions
identify Link visitor to user Login, signup (enables cross-device attribution)

That's it. Four methods to complete multi-touch attribution.


Quick Start

1. Get Your API Key

  1. Log in to your dashboard
  2. Navigate to API Keys
  3. Click Create API Key
  4. Choose Test environment for development
  5. Copy your API key (starts with sk_test_...)

2. Install the Client Library

# Gemfile gem 'mbuzz' # Then run: bundle install
npm install mbuzz # or yarn add mbuzz
pip install mbuzz # or uv pip install mbuzz
No installation needed. Use any HTTP client.

3. Initialize (init)

# config/initializers/mbuzz.rb Mbuzz.init( api_key: ENV['MBUZZ_API_KEY'], debug: Rails.env.development? )
// app.js or server.js const mbuzz = require('mbuzz'); mbuzz.init({ apiKey: process.env.MBUZZ_API_KEY, debug: process.env.NODE_ENV === 'development' });
# app.py or settings.py import os import mbuzz mbuzz.init( api_key=os.environ['MBUZZ_API_KEY'], debug=os.environ.get('FLASK_ENV') == 'development' )
# Set your API key as environment variable export MBUZZ_API_KEY=sk_test_your_key_here # Use in Authorization header curl -H "Authorization: Bearer $MBUZZ_API_KEY" \ https://mbuzz.co/api/v1/events

⚠️ Security: Never commit API keys to git. Use environment variables.


4. Track Events (event)

Track steps in the customer journey:

# Track user interactions Mbuzz.event("page_view", url: "/pricing") Mbuzz.event("add_to_cart", product_id: "SKU-123", price: 49.99) Mbuzz.event("checkout_started", cart_total: 99.99) # Group events into funnels for focused analysis Mbuzz.event("signup_start", funnel: "signup", source: "homepage") Mbuzz.event("signup_complete", funnel: "signup")
// Track user interactions mbuzz.event('page_view', { url: '/pricing' }); mbuzz.event('add_to_cart', { productId: 'SKU-123', price: 49.99 }); mbuzz.event('checkout_started', { cartTotal: 99.99 }); // Group events into funnels for focused analysis mbuzz.event('signup_start', { funnel: 'signup', source: 'homepage' }); mbuzz.event('signup_complete', { funnel: 'signup' });
# Track user interactions mbuzz.event('page_view', url='/pricing') mbuzz.event('add_to_cart', product_id='SKU-123', price=49.99) mbuzz.event('checkout_started', cart_total=99.99) # Group events into funnels for focused analysis mbuzz.event('signup_start', funnel='signup', source='homepage') mbuzz.event('signup_complete', funnel='signup')
curl -X POST https://mbuzz.co/api/v1/events \ -H "Authorization: Bearer $MBUZZ_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "event_type": "add_to_cart", "visitor_id": "abc123...", "funnel": "purchase", "properties": { "product_id": "SKU-123", "price": 49.99 } }'

Core Concepts

Sessions (The Foundation of Attribution)

A session is a single visit to your site with acquisition context. Sessions are the touchpoints used for attribution.

What a session captures:
- UTM parameters (utm_source, utm_medium, utm_campaign, etc.)
- Referrer URL (for organic/referral traffic)
- Channel (derived from UTMs + referrer: paid_search, organic, email, etc.)
- Landing page

Session behavior:
- Auto-created: SDK middleware creates sessions automatically
- 30-minute timeout: New session after 30 min of inactivity
- Non-blocking: Session POST is async (doesn't slow your app)

Why sessions matter: Without sessions, you can't know how a visitor arrived. Sessions make multi-touch attribution possible.

Visitors

Anonymous users tracked via cookies.

  • Lifetime: 2 years
  • Auto-generated: By SDK (64-char hex, stored in _mbuzz_vid cookie)
  • Thread-safe: Works with multi-threaded servers
  • Privacy-first: No PII required

A single person may have multiple visitors (multiple devices/browsers).

Users

Known, identified users in your system.

  • Cross-device: One user identity across all devices
  • Permanent: Persists beyond cookies
  • Your ID: Use your application's user identifier

Link visitors to users with the identify() method.

Events

Actions users take in your application.

Required fields:
- event_type - Event name (e.g., "signup", "purchase", "add_to_cart")
- user_id OR visitor_id - At least one identifier required

Recommended fields:
- session_id - Links event to session for attribution
- funnel - Group events into funnels for focused analysis

Optional fields:
- properties - Custom metadata (JSON object)
- timestamp - When event occurred (defaults to now)

Funnels

Group related events into funnels for focused conversion analysis.

Why use funnels?
- Separate signup flow from purchase flow
- Analyze each conversion path independently
- Filter dashboard to specific customer journeys

Example funnels:

# Signup funnel Mbuzz.event("pricing_view", funnel: "signup") Mbuzz.event("signup_start", funnel: "signup") Mbuzz.event("signup_complete", funnel: "signup") # Purchase funnel Mbuzz.event("add_to_cart", funnel: "purchase") Mbuzz.event("checkout_started", funnel: "purchase") Mbuzz.event("purchase_complete", funnel: "purchase")
// Signup funnel mbuzz.event('pricing_view', { funnel: 'signup' }); mbuzz.event('signup_start', { funnel: 'signup' }); mbuzz.event('signup_complete', { funnel: 'signup' }); // Purchase funnel mbuzz.event('add_to_cart', { funnel: 'purchase' }); mbuzz.event('checkout_started', { funnel: 'purchase' }); mbuzz.event('purchase_complete', { funnel: 'purchase' });
# Signup funnel mbuzz.event('pricing_view', funnel='signup') mbuzz.event('signup_start', funnel='signup') mbuzz.event('signup_complete', funnel='signup') # Purchase funnel mbuzz.event('add_to_cart', funnel='purchase') mbuzz.event('checkout_started', funnel='purchase') mbuzz.event('purchase_complete', funnel='purchase')
# Include funnel in event properties curl -X POST https://mbuzz.co/api/v1/events \ -H "Authorization: Bearer $MBUZZ_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "events": [{ "event_type": "signup_start", "visitor_id": "abc123...", "funnel": "signup" }] }'

Dashboard filtering: Use the funnel dropdown to view specific funnels. "All Funnels" shows everything.


Automatic Session Tracking

The SDK includes middleware that automatically creates sessions when visitors land on your site.

What happens on each request:
1. SDK checks for existing visitor cookie (_mbuzz_vid)
2. SDK checks for existing session cookie (_mbuzz_sid)
3. If new session detected → POST to API with full context
4. Cookies refreshed

Session context captured automatically:
- Full URL (including UTM parameters)
- Referrer URL
- User-Agent
- IP address (for geo lookup)

Session detection:
- New visitor: No _mbuzz_vid cookie → new session
- Returning visitor, new session: _mbuzz_vid exists but _mbuzz_sid missing/expired (30+ min) → new session
- Same session: Both cookies valid → no new session

The API handles:
- UTM parameter extraction
- Referrer analysis
- Channel derivation (paid_search, organic, email, etc.)
- Visitor/Session record creation

Important: Session POSTs are async and non-blocking. Your page render is not slowed.

Disable if needed:

# config/initializers/mbuzz.rb Mbuzz.init( api_key: ENV['MBUZZ_API_KEY'], skip_paths: ["/health", "/admin"] # Skip specific paths )
// app.js or server.js mbuzz.init({ apiKey: process.env.MBUZZ_API_KEY, skipPaths: ['/health', '/admin'] // Skip specific paths });
# app.py mbuzz.init( api_key=os.environ['MBUZZ_API_KEY'], skip_paths=['/health', '/admin'] # Skip specific paths )
N/A - Session tracking is SDK-only. REST API users manage their own sessions.

User Identification (identify)

Link visitors to known users and store traits. This enables cross-device attribution.

# On signup or login - links visitor automatically Mbuzz.identify(current_user.id, traits: { email: current_user.email, name: current_user.name, plan: current_user.plan } )
// On signup or login - links visitor automatically mbuzz.identify(user.id, { traits: { email: user.email, name: user.name, plan: user.plan } });
# On signup or login - links visitor automatically mbuzz.identify(user.id, traits={ 'email': user.email, 'name': user.name, 'plan': user.plan })
curl -X POST https://mbuzz.co/api/v1/identify \ -H "Authorization: Bearer $MBUZZ_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "user_id": "123", "visitor_id": "abc123def456...", "traits": { "email": "user@example.com", "name": "Jane Doe", "plan": "pro" } }'

When to call:
- On signup (links first visitor to new user)
- On every login (links new devices to existing user)
- When user attributes change

What Identify Does

identify performs two actions in one call:

  1. Links visitor to user (if visitor_id provided or available from cookie)
  2. Stores user traits (email, name, plan, etc.)

When you link a visitor:

Backward attribution:
- All past sessions from this visitor are attributed to the user
- Sessions from before signup become part of their journey

Forward attribution:
- All future sessions from this visitor automatically attributed to the user

Retroactive recalculation:
- If the user has existing conversions, and the newly-linked visitor has sessions
within those conversions' lookback windows, attribution is automatically recalculated

Cross-Device Attribution

Users often visit on multiple devices. Each device has a different visitor ID:

ruby
Desktop visitor (abc) ─────┐ ├──→ User (usr_123) Mobile visitor (def) ──────┘

How it works:
1. User visits on desktop → visitor abc created
2. User visits on mobile → visitor def created
3. User signs up on mobile → identify() links mobile visitor
4. User logs in on desktop → identify() links desktop visitor
5. Now both visitors linked → full cross-device attribution

Call identify on every login, not just signup. This ensures visitors from new devices get linked.

Example: Full Journey Attribution

ruby
Day 1: Jane visits via Google Ads (desktop) Session A Day 3: Jane visits via Facebook (mobile) Session B Day 5: Jane signs up (mobile) identify() links mobile visitor Day 6: Jane logs in (desktop) identify() links desktop visitor Day 7: Jane purchases Attribution spans ALL sessions (A, B, etc.)

Without identify on each device, you'd only see mobile sessions.


Conversion Tracking

Conversions are the key metric for attribution. When a user converts (signup, purchase, etc.),
the system automatically calculates attribution across all your configured models.

Creating Conversions

You can create conversions in two ways:

Option A: Event-based (recommended for precise attribution)

# First track the conversion event result = Mbuzz::Client.track( visitor_id: mbuzz_visitor_id, event_type: 'checkout_completed', properties: { order_id: order.id } ) # Then create the conversion linked to that event if result[:success] conversion = Mbuzz::Client.conversion( event_id: result[:event_id], conversion_type: 'purchase', revenue: order.total ) # Access attribution data if conversion[:success] conversion[:attribution][:models].each do |model, credits| puts "#{model}: #{credits.map { |c| c[:channel] }.join(', ')}" end end end
// First track the conversion event const result = await mbuzz.event('checkout_completed', { orderId: order.id }); // Then create the conversion linked to that event if (result.success) { const conversion = await mbuzz.conversion('purchase', { eventId: result.eventId, revenue: order.total }); // Access attribution data if (conversion.success) { for (const [model, credits] of Object.entries(conversion.attribution.models)) { console.log(`${model}: ${credits.map(c => c.channel).join(', ')}`); } } }
# First track the conversion event result = mbuzz.event('checkout_completed', order_id=order.id) # Then create the conversion linked to that event if result.success: conversion = mbuzz.conversion('purchase', event_id=result.event_id, revenue=order.total ) # Access attribution data if conversion.success: for model, credits in conversion.attribution['models'].items(): channels = ', '.join(c['channel'] for c in credits) print(f"{model}: {channels}")
# Create conversion from event curl -X POST https://mbuzz.co/api/v1/conversions \ -H "Authorization: Bearer $MBUZZ_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "conversion": { "event_id": "evt_abc123", "conversion_type": "purchase", "revenue": 99.99 } }'

Option B: Visitor-based (simpler, for direct conversions)

# Create conversion directly from visitor ID # (uses visitor's most recent session) conversion = Mbuzz::Client.conversion( visitor_id: mbuzz_visitor_id, conversion_type: 'purchase', revenue: order.total, funnel: 'purchase', # Optional: group into funnel properties: { plan: 'pro' } )
// Create conversion directly from visitor ID // (uses visitor's most recent session) const conversion = await mbuzz.conversion('purchase', { visitorId: mbuzzVisitorId, revenue: order.total, funnel: 'purchase', // Optional: group into funnel properties: { plan: 'pro' } });
# Create conversion directly from visitor ID # (uses visitor's most recent session) conversion = mbuzz.conversion('purchase', revenue=order.total, funnel='purchase', # Optional: group into funnel properties={'plan': 'pro'} )
# Create conversion from visitor ID curl -X POST https://mbuzz.co/api/v1/conversions \ -H "Authorization: Bearer $MBUZZ_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "conversion": { "visitor_id": "65dabef8d611f332d5bb88f5d6870c733d89f962594575b66f0e1de1ede1ebf0", "conversion_type": "purchase", "funnel": "purchase", "revenue": 99.99 } }'

Conversion Response

Successful conversions return attribution data immediately:

json
{ "id": "conv_xyz789", "conversion_type": "purchase", "revenue": "99.99", "attribution": { "lookback_days": 30, "sessions_analyzed": 3, "models": { "first_touch": [ { "channel": "organic_search", "credit": 1.0, "revenue_credit": "99.99" } ], "last_touch": [ { "channel": "email", "credit": 1.0, "revenue_credit": "99.99" } ], "linear": [ { "channel": "organic_search", "credit": 0.333, "revenue_credit": "33.00" }, { "channel": "paid_social", "credit": 0.333, "revenue_credit": "33.00" }, { "channel": "email", "credit": 0.334, "revenue_credit": "33.99" } ] } } }

When to Use Each Approach

Approach Use Case
Event-based (event_id) Tie conversion to specific action (checkout button click, form submit)
Visitor-based (visitor_id) Direct conversions, offline imports, webhook integrations

Acquisition vs Recurring Revenue

For SaaS and subscription businesses, you need to distinguish between:
- Acquisition: The first conversion (signup, first purchase) - this gets full attribution
- Recurring Revenue: Subsequent payments - these inherit attribution from acquisition

Why this matters: You want to know which channels drive new customers, not just which channels happened to be active when a subscription renewed.

# 1. Mark signup as the acquisition moment Mbuzz.conversion('signup', user_id: user.id, is_acquisition: true ) # 2. Monthly subscription payments inherit acquisition attribution Mbuzz.conversion('payment', user_id: user.id, revenue: 49.00, inherit_acquisition: true )
// 1. Mark signup as the acquisition moment mbuzz.conversion('signup', { userId: user.id, isAcquisition: true }); // 2. Monthly subscription payments inherit acquisition attribution mbuzz.conversion('payment', { userId: user.id, revenue: 49.00, inheritAcquisition: true });
# 1. Mark signup as the acquisition moment mbuzz.conversion('signup', user_id=user.id, is_acquisition=True ) # 2. Monthly subscription payments inherit acquisition attribution mbuzz.conversion('payment', user_id=user.id, revenue=49.00, inherit_acquisition=True )
# 1. Acquisition conversion curl -X POST https://mbuzz.co/api/v1/conversions \ -H "Authorization: Bearer $MBUZZ_API_KEY" \ -d '{"conversion": {"conversion_type": "signup", "user_id": "123", "is_acquisition": true}}' # 2. Recurring revenue curl -X POST https://mbuzz.co/api/v1/conversions \ -H "Authorization: Bearer $MBUZZ_API_KEY" \ -d '{"conversion": {"conversion_type": "payment", "user_id": "123", "revenue": 49.00, "inherit_acquisition": true}}'

How it works:
1. User signs up → is_acquisition: true stores the attribution (channels that drove signup)
2. User pays monthly → inherit_acquisition: true copies attribution from signup
3. All revenue credited to the channels that acquired the customer

When to use:
- is_acquisition: true - First meaningful conversion (signup, first purchase, trial start)
- inherit_acquisition: true - All subsequent revenue from that customer


Common Use Cases

E-Commerce Tracking

class OrdersController < ApplicationController def create @order = current_user.orders.create!(order_params) # Track the event Mbuzz.event("checkout_completed", order_id: @order.id) # Record the conversion with revenue Mbuzz.conversion("purchase", revenue: @order.total, order_id: @order.id ) redirect_to order_path(@order) end end
app.post('/orders', async (req, res) => { const order = await Order.create(req.body); // Track the event mbuzz.event('checkout_completed', { orderId: order.id }); // Record the conversion with revenue mbuzz.conversion('purchase', { revenue: order.total, orderId: order.id }); res.redirect(`/orders/${order.id}`); });
@app.route('/orders', methods=['POST']) def create_order(): order = Order.create(**request.form) # Track the event mbuzz.event('checkout_completed', order_id=order.id) # Record the conversion with revenue mbuzz.conversion('purchase', revenue=order.total, properties={'order_id': order.id} ) return redirect(url_for('order', id=order.id))
curl -X POST https://mbuzz.co/api/v1/events \ -H "Authorization: Bearer $MBUZZ_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "user_id": "123", "event_type": "Purchase Completed", "properties": { "order_id": "order_456", "amount": 99.99, "items": 2, "currency": "USD" } }'

SaaS Subscription Tracking

class SubscriptionsController < ApplicationController def create @subscription = current_user.create_subscription!( plan: params[:plan] ) # Record as conversion with MRR Mbuzz.conversion("subscription", revenue: @subscription.monthly_revenue, plan: @subscription.plan, billing_cycle: @subscription.billing_cycle ) redirect_to dashboard_path end end
app.post('/subscriptions', async (req, res) => { const subscription = await user.createSubscription({ plan: req.body.plan }); // Record as conversion with MRR mbuzz.conversion('subscription', { revenue: subscription.monthlyRevenue, plan: subscription.plan, billingCycle: subscription.billingCycle }); res.redirect('/dashboard'); });
@app.route('/subscriptions', methods=['POST']) def create_subscription(): subscription = current_user.create_subscription( plan=request.form['plan'] ) # Record as conversion with MRR mbuzz.conversion('subscription', revenue=subscription.monthly_revenue, properties={ 'plan': subscription.plan, 'billing_cycle': subscription.billing_cycle } ) return redirect(url_for('dashboard'))
curl -X POST https://mbuzz.co/api/v1/events \ -H "Authorization: Bearer $MBUZZ_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "user_id": "123", "event_type": "Subscription Created", "properties": { "plan": "pro", "billing_cycle": "monthly", "mrr": 99.00 } }'

Error Handling

Client libraries never raise exceptions. All errors are:

  • Logged (if debug mode enabled)
  • Returned as false from tracking methods
  • Silently ignored otherwise

Why: Tracking failures should never break your application.

Debugging:

# Enable debug mode in initializer Mbuzz.init(api_key: ENV['MBUZZ_API_KEY'], debug: true) # Check return values result = Mbuzz.event("test_event", foo: "bar") if result puts "Tracking succeeded" else puts "Tracking failed (check logs)" end
// Enable debug mode in initializer mbuzz.init({ apiKey: process.env.MBUZZ_API_KEY, debug: true }); // Check return values const result = await mbuzz.event('test_event', { foo: 'bar' }); if (result) { console.log('Tracking succeeded'); } else { console.log('Tracking failed (check logs)'); }
# Enable debug mode in initializer mbuzz.init(api_key=os.environ['MBUZZ_API_KEY'], debug=True) # Check return values result = mbuzz.event('test_event', foo='bar') if result.success: print('Tracking succeeded') else: print('Tracking failed (check logs)')
# Check HTTP response codes curl -v -X POST https://mbuzz.co/api/v1/events \ -H "Authorization: Bearer $MBUZZ_API_KEY" \ -H "Content-Type: application/json" \ -d '{"events": [{"event_type": "test", "visitor_id": "abc123"}]}' # 2xx = success, 4xx/5xx = failure

Testing

Disable Tracking in Tests

# config/initializers/mbuzz.rb Mbuzz.init( api_key: ENV['MBUZZ_API_KEY'], enabled: !Rails.env.test? )
// app.js or server.js mbuzz.init({ apiKey: process.env.MBUZZ_API_KEY, enabled: process.env.NODE_ENV !== 'test' });
# app.py or settings.py mbuzz.init( api_key=os.environ['MBUZZ_API_KEY'], enabled=os.environ.get('FLASK_ENV') != 'testing' )
# Use test API key for development export MBUZZ_API_KEY=sk_test_your_key_here

Next Steps

Now that you understand the 4-call model:

  1. Initialize - Set up init() in your app
  2. Track events - Call event() for user interactions
  3. Record conversions - Call conversion() for revenue events
  4. Identify users - Call identify() on signup/login (enables cross-device)
  5. View attribution - Check your dashboard for attribution data

Need help? Check out:
- Authentication - API key management