Skip to main content

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

TierEvents/SecondDaily Events
Free10/sec100,000
Starter50/sec500,000
Pro100/sec2,000,000
EnterpriseCustomUnlimited

Best Practices for Performance

  1. 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
  2. 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 // %
    });
  3. 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

  1. Go to Users → Find user
  2. View Activity tab
  3. 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)

Next Steps