Server-side multi-touch attribution for Ruby. Track customer journeys, attribute conversions, know which channels drive revenue.
Add to your Gemfile:
gem 'mbuzz'Then:
bundle install# config/initializers/mbuzz.rb
Mbuzz.init(api_key: ENV['MBUZZ_API_KEY'])Track steps in the customer journey:
Mbuzz.event("page_view", url: request.url)
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")Record revenue-generating outcomes:
Mbuzz.conversion("purchase",
revenue: 99.99,
funnel: "purchase", # Optional: group into funnel
order_id: order.id
)Link visitors to known users (enables cross-device attribution):
# On signup or login
Mbuzz.identify(current_user.id,
traits: {
email: current_user.email,
name: current_user.name
}
)Group related events into funnels for focused conversion analysis in your dashboard.
# 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.conversion("purchase", funnel: "purchase", revenue: 99.99)Why use funnels?
- Separate signup flow from purchase flow
- Analyze each conversion path independently
- Filter dashboard to specific customer journeys
mbuzz auto-integrates with Rails via Railtie:
- Middleware for visitor and session cookie management
- Controller helpers for convenient access
class ApplicationController < ActionController::Base
# Access current IDs
mbuzz_visitor_id # Returns the visitor ID from cookie
mbuzz_user_id # Returns user_id from session["user_id"]
mbuzz_session_id # Returns the session ID from cookie
endNote: For tracking and identification, prefer the main API which auto-enriches events with URL/referrer:
# Recommended - use main API in controllers
Mbuzz.event("page_view", page: request.path)
Mbuzz.identify(current_user.id, traits: { email: current_user.email })Access IDs from anywhere in your request cycle:
Mbuzz.visitor_id # Current visitor ID (from cookie)
Mbuzz.user_id # Current user ID (from session["user_id"])
Mbuzz.session_id # Current session ID (from cookie)When tracking from background jobs (Sidekiq, GoodJob, etc.), there's no HTTP request context. Rails 7+ handles this automatically via CurrentAttributes.
mbuzz uses ActiveSupport::CurrentAttributes which Rails automatically serializes into ActiveJob payloads:
# In your controller - just enqueue the job
class OrdersController < ApplicationController
def create
@order = Order.create!(order_params)
ProcessOrderJob.perform_later(@order.id)
# visitor_id is automatically captured and passed to the job
end
end
# In your job - mbuzz just works!
class ProcessOrderJob < ApplicationJob
def perform(order_id)
order = Order.find(order_id)
# Mbuzz::Current.visitor_id was restored by Rails
Mbuzz.conversion("purchase", revenue: order.total)
end
endHow it works:
- Middleware captures
visitor_idfrom cookie intoMbuzz::Current - Controller enqueues job
- Rails serializes
Mbuzz::Currentinto job payload - Job runs → Rails restores
Mbuzz::Current Mbuzz.conversion()reads fromCurrent- works!
For non-Rails apps or when you need more control:
# Store visitor_id on your model
class Order < ApplicationRecord
before_create { self.mbuzz_visitor_id = Mbuzz.visitor_id }
end
# Pass explicitly in background job
class ProcessOrderJob
def perform(order_id)
order = Order.find(order_id)
Mbuzz.conversion("purchase",
visitor_id: order.mbuzz_visitor_id, # Explicit
revenue: order.total
)
end
endFor non-Rails apps, add the middleware manually:
# config.ru or app.rb
require 'mbuzz'
Mbuzz.init(api_key: ENV['MBUZZ_API_KEY'])
use Mbuzz::Middleware::SessionEndpoint # see "Full-page caching" below
use Mbuzz::Middleware::Tracking
run MyAppIf pages are served from a full-page cache (Cloudflare, Varnish, nginx, Rack::Cache, a CDN), the cache answers the request without entering the Rack stack, so the tracking middleware never runs, no visitor cookie is set, and every later event is dropped for having no one to attribute it to. The page renders perfectly and nothing is logged — the failure is silent.
Mbuzz::Middleware::SessionEndpoint fixes this. It answers POST /_mbuzz/session, a path
caches don't store, and the server sets the cookie on that response. Rails mounts it for
you; Rack and Sinatra apps add it ahead of Tracking as shown above.
Then call it once per page, from your layout:
<script>
fetch('/_mbuzz/session', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ url: location.href, referrer: document.referrer || '' }),
credentials: 'same-origin',
keepalive: true
}).catch(function () {});
</script>Two things to keep as they are:
- Inline the script, don't enqueue a file. Asset optimisers (WP Rocket, LiteSpeed, and the Rails equivalents) delay external scripts until the visitor first interacts. A visitor who lands and converts without clicking anything first would never be established.
credentials: 'same-origin'is required, or the cookie never comes back.
The visitor id is never created or read in JavaScript. It stays HttpOnly and server-set, which
is what preserves its full two-year life — a cookie written by document.cookie is capped at
7 days under Safari's ITP, and 24 hours after an ad click.
Mbuzz.init(
api_key: "sk_live_...", # Required - from mbuzz.co dashboard
api_url: "https://api.mbuzz.co/api/v1", # Optional - API endpoint
debug: false # Optional - enable debug logging
)| Method | When to Use |
|---|---|
init |
Once on app boot |
event |
User interactions, funnel steps |
conversion |
Purchases, signups, any revenue event |
identify |
Login, signup, when you know the user |
mbuzz never raises exceptions. All methods return false on failure and log errors in debug mode.
- Ruby 3.0+
- Rails 6.0+ (for automatic integration) or any Rack app
MIT License