Custom Events
Events represent actions users take in your application. Track custom events to build segments, trigger campaigns, and analyze user behavior.
What are Events?
Events are timestamped records of user actions:
{
"userId": "user_123",
"eventName": "Order Completed",
"timestamp": "2024-01-20T14:30:00Z",
"properties": {
"orderId": "order_456",
"total": 99.99,
"currency": "USD",
"items": 3,
"paymentMethod": "credit_card"
}
}
Tracking Events
Via SDK (Client-Side)
import JoryioSDK from '@joryio/web-sdk';
const joryio = new JoryioSDK({ sdkKey: 'jry_sdk_web_...' });
// Simple event
joryio.track('Button Clicked');
// Event with properties
joryio.track('Order Completed', {
orderId: 'order_456',
total: 99.99,
currency: 'USD',
items: 3
});
// Page view
joryio.track('Page Viewed', {
page: '/pricing',
category: 'Marketing',
title: 'Pricing Page'
});
Via API (Server-Side)
fetch('https://api-eu1.joryio.com/track', {
method: 'POST',
headers: {
'Authorization': 'Bearer jry_live_your_api_key',
'Content-Type': 'application/json'
},
body: JSON.stringify({
userId: 'user_123',
eventName: 'Order Completed',
properties: {
orderId: 'order_456',
total: 99.99,
currency: 'USD'
}
})
});
Batch Tracking
The SDK automatically batches events for better performance. Events are queued and sent in groups:
// SDK automatically batches these events
joryio.track('Product Viewed', { productId: '123' });
joryio.track('Added To Cart', { productId: '123', price: 49.99 });
joryio.track('Cart Viewed', { itemCount: 1 });
// Events are sent together after 10 seconds or 20 events (configurable)
// To send immediately:
joryio.flush();
// API: POST /track with a bare array body (max 500)
POST /track
[
{
"userId": "user_123",
"eventName": "Product Viewed",
"properties": { "productId": "123" }
},
{
"userId": "user_123",
"eventName": "Added To Cart",
"properties": { "productId": "123", "price": 49.99 }
}
]
Event Naming
Best Practices
Use clear, consistent naming:
Good (Object + Action):
joryio.track('Product Viewed');
joryio.track('Cart Abandoned');
joryio.track('Order Completed');
joryio.track('Trial Started');
Bad:
joryio.track('view_product'); // Inconsistent case
joryio.track('clicked'); // Too generic
joryio.track('user_action_123'); // Not descriptive
Naming Convention
We recommend: Object + Past Tense Verb
Product Viewed
Order Completed
Account Created
Feature Enabled
Video Watched
Form Submitted
Event Properties
Properties provide context about the event:
E-commerce Events
// Product Viewed
joryio.track('Product Viewed', {
productId: 'prod_123',
productName: 'Premium Plan',
category: 'Subscription',
price: 99.99,
currency: 'USD',
inStock: true
});
// Order Completed
joryio.track('Order Completed', {
orderId: 'order_456',
total: 249.99,
currency: 'USD',
itemCount: 3,
discount: 25.00,
shippingCost: 10.00,
paymentMethod: 'credit_card',
products: [
{ id: 'prod_1', name: 'Item 1', price: 99.99 },
{ id: 'prod_2', name: 'Item 2', price: 149.99 }
]
});
// Cart Abandoned
joryio.track('Cart Abandoned', {
cartValue: 149.99,
itemCount: 2,
cartAge: '2h 30m'
});
SaaS Events
// Trial Started
joryio.track('Trial Started', {
plan: 'premium',
trialDays: 14,
source: 'pricing_page'
});
// Feature Used
joryio.track('Feature Used', {
featureName: 'export',
exportFormat: 'csv',
recordCount: 1500,
duration: 3.5 // seconds
});
// Subscription Upgraded
joryio.track('Subscription Upgraded', {
fromPlan: 'starter',
toPlan: 'professional',
billingCycle: 'monthly',
mrr: 199,
effectiveDate: '2024-02-01'
});
Content/Media Events
// Video Watched
joryio.track('Video Watched', {
videoId: 'vid_123',
videoTitle: 'Product Demo',
duration: 120, // seconds
percentWatched: 85,
quality: '1080p',
platform: 'web'
});
// Article Read
joryio.track('Article Read', {
articleId: 'article_456',
title: '10 Tips for Better Marketing',
category: 'Marketing',
author: 'John Doe',
readTime: 5, // minutes
scrollDepth: 90
});
Common Event Examples
User Lifecycle
// Signup flow
joryio.track('Signup Started');
joryio.track('Signup Completed', {
method: 'email',
source: 'homepage_cta'
});
joryio.track('Email Verified');
joryio.track('Onboarding Completed', {
stepsCompleted: 5,
timeSpent: '8m 30s'
});
// Engagement
joryio.track('Session Started');
joryio.track('Feature Discovered', {
featureName: 'advanced_filters'
});
joryio.track('Help Article Viewed', {
articleId: 'help_123',
query: 'how to export data'
});
joryio.track('Session Ended', {
duration: '15m 20s',
pagesViewed: 8
});
E-commerce Funnel
// Browse
joryio.track('Product Searched', {
query: 'wireless headphones',
results: 45
});
joryio.track('Product Viewed', {
productId: 'prod_123',
price: 199.99
});
joryio.track('Product Compared', {
productIds: ['prod_123', 'prod_456']
});
// Cart
joryio.track('Added To Cart', {
productId: 'prod_123',
quantity: 1,
price: 199.99
});
joryio.track('Cart Viewed');
joryio.track('Coupon Applied', {
code: 'SAVE20',
discount: 39.99
});
// Checkout
joryio.track('Checkout Started', {
value: 159.99
});
joryio.track('Payment Info Entered');
joryio.track('Order Completed', {
orderId: 'order_789',
revenue: 159.99
});
SaaS Metrics
// Activation
joryio.track('Trial Started');
joryio.track('Integration Connected', {
integration: 'salesforce'
});
joryio.track('First Report Created');
joryio.track('Team Member Invited');
// Engagement
joryio.track('Daily Active', {
loginCount: 45
});
joryio.track('API Call Made', {
endpoint: '/users',
method: 'GET'
});
// Revenue
joryio.track('Subscription Created', {
plan: 'professional',
mrr: 199
});
joryio.track('Subscription Renewed', {
plan: 'professional'
});
joryio.track('Subscription Cancelled', {
reason: 'too_expensive'
});
Property Data Types
Supported Types
joryio.track('Event Name', {
// String
name: "John Doe",
plan: "premium",
// Number
age: 30,
price: 99.99,
quantity: 5,
// Boolean
isActive: true,
emailVerified: false,
// Date (ISO 8601 string)
createdAt: "2024-01-20T10:30:00Z",
expiresAt: "2024-02-20T23:59:59Z",
// Array
tags: ["vip", "early-access"],
categories: ["electronics", "accessories"],
// Object
address: {
city: "San Francisco",
state: "CA",
zip: "94102"
},
metadata: {
source: "web",
campaign: "summer_sale"
}
});
Reserved Property Names
Properties starting with $ are reserved:
$app_id- App identifier$app_name- App name$platform- Platform (web, ios, android)$session_id- Session identifier$anonymous_id- Anonymous user ID$is_identified- Whether user is identified
Don't use these names for custom properties.
Using Events for Segmentation
Create segments based on event behavior:
Event Performed
Segment: Active users
Filter: Performed "Session Started" within last 7 days
Event NOT Performed
Segment: Users who haven't upgraded
Filter: Has NOT performed "Subscription Upgraded"
Event Count
Segment: Power users
Filter: Performed "Feature Used" >= 50 times within last 30 days
Event Properties
Segment: High-value customers
Filter: Performed "Order Completed"
WHERE properties.total >= 500
within last 90 days
Complex Behavioral Segments
Segment: At-risk users
Filter Group 1 (AND):
- Performed "Login" within last 90 days
- Has NOT performed "Login" within last 14 days
- Performed "Order Completed" at least 1 time
Use for: Re-engagement campaign
Event-Triggered Campaigns
Trigger campaigns based on events:
Example 1: Cart Abandonment
Trigger: "Cart Abandoned" event
Wait: 1 hour
Condition: Has NOT performed "Order Completed"
Action: Send recovery email with discount
Example 2: Onboarding
Trigger: "Signup Completed" event
Flow:
→ Welcome email (immediate)
→ Wait 2 days
→ Getting started guide
→ Wait 5 days
→ Check: Performed "First Report Created"?
- Yes: Advanced tips email
- No: Help offer email
Event Limits & Performance
Rate Limits
| Tier | Events/Second | Daily Events |
|---|---|---|
| Free | 10/sec | 100,000 |
| Starter | 50/sec | 500,000 |
| Pro | 100/sec | 2,000,000 |
| Enterprise | Custom | Unlimited |
Best Practices for Performance
-
Events are automatically batched by the SDK:
// SDK automatically batches these for you
joryio.track(event1);
joryio.track(event2);
joryio.track(event3);
// All three sent together after batchFlushInterval (default 5s) or batchSize (default 50) reached
// For critical events that need immediate sending:
joryio.track('Order Completed', {...});
joryio.flush(); // Send immediately -
Don't track too frequently:
// Bad: Tracking every scroll
window.addEventListener('scroll', () => {
joryio.track('Page Scrolled');
});
// Good: Track scroll depth milestones
joryio.track('Page Scrolled', {
depth: 75 // %
}); -
Keep properties reasonable:
- Max 50 properties per event
- Max 10KB total event size
- Avoid extremely long strings
Debugging Events
Enable Debug Mode
const joryio = new JoryioSDK({
sdkKey: 'jry_sdk_web_...',
enableDebug: true // See all events in console
});
Verify Events in Dashboard
- Go to Users → Find user
- View Activity tab
- See all tracked events
Common Issues
Events not appearing:
- Check SDK is initialized
- Verify user is identified (or anonymous ID exists)
- Enable debug mode
- Check browser console for errors
Properties not showing:
- Verify property names are correct
- Check data types
- Avoid reserved property names ($prefix)