orwel
v1.4.4
Published
Human-behavior event tracking SDK
Maintainers
Readme
🛰️ Orwel SDK
Orwel is a lightweight, JavaScript SDK for tracking frontend events, visitor traits, and UX signals — all from a simple script or npm install. Designed for marketing teams and product analysts who want real-time visibility into their funnel.
✨ Key Features
- 🛡️ Parameter Validation: Runtime validation with clear error messages
- 🔧 TypeScript: Full IntelliSense support with detailed method documentation
- 📊 Batch Processing: High-performance event batching for reduced server load
- 🔄 Auto-retry: Circuit breaker pattern with automatic failure recovery
- 📱 Cross-platform: Works in all modern browsers and frameworks
🚀 Quickstart (via npm)
npm install orwel🔑 Key Concepts
Before diving into the implementation, it's important to understand some key concepts:
Singleton Pattern
Orwel uses a singleton pattern, meaning there's only one instance of the SDK throughout your application. You don't need to create new instances with new Orwel() - instead, you import the pre-configured instance and initialize it:
import { orwel } from 'orwel'
// Initialize as early as possible in your application
orwel.init({
apiKey: 'orwel_xxxxxxxxxxxxx',
autoMonitor: true, // optional: automatically enable all monitoring features
})Initialization Timing
The init() call should be placed:
- React: In your root component (e.g.,
App.js) or initialization component - Next.js: In
_app.jsor root layout - Vue: In
main.jsbefore mounting the app - Svelte: In
src/routes/+layout.svelteorsrc/routes/+page.svelte - Plain HTML: In
<head>or early in<body>
State Management
Once initialized:
- Configuration is stored in memory and persists throughout the session
- Visitor data is stored in localStorage/cookies for cross-session persistence
- You can import and use
orwelfrom any file without re-initialization
💡 Usage Examples
Basic Event Tracking
// Track a simple event
orwel.track('button_clicked')
// Track with properties
orwel.track('form_submitted', {
form_id: 'contact',
time_to_complete: 45,
errors_count: 0
})🎯 Event Types & Tracking
Events in Orwel are not random strings - they follow a predefined schema to ensure consistency and enable powerful analytics:
Standard Events
A comprehensive list of standard events is available at orwel.io/events. These events are optimized for common tracking scenarios:
// User interaction events
orwel.track('button_click', { button_id: 'submit_form' })
orwel.track('page_view', { path: '/checkout' })
orwel.track('form_submit', { form_name: 'signup' })
// E-commerce events
orwel.track('product_view', { product_id: '123', price: 99.99 })
orwel.track('add_to_cart', { product_id: '123', quantity: 1 })
orwel.track('checkout_complete', { order_id: 'ORDER123' })
// Subscription events
orwel.track('subscription_started', { plan: 'pro', method: 'stripe' })
orwel.track('subscription_cancelled', { reason: 'cost' })Custom Events
For unique tracking needs, you can use:
- Custom Event Type:
orwel.track('custom_event', {
event_category: 'my_feature',
event_action: 'special_action',
// ... custom properties
})- Event Aliases: You can create aliases for frequently used custom events in your Orwel dashboard:
// After creating alias 'special_action' for 'custom_event'
orwel.track('special_action', {
// ... your properties
})Best Practices
- Use standard events when possible for better analytics integration
- Keep event names in snake_case format
- Document custom events and their expected properties
- Use consistent property names across similar events
- Avoid sending sensitive data in event properties
Visitor Identification
orwel.identify({
// id is auto-generated and persisted if not provided
email: '[email protected]',
plan: 'pro',
company: 'Acme Inc',
subscription_status: 'active'
})Lead Generation
// Capture conversions with specific event codes
orwel.conversion('newsletter_signup', {
email: '[email protected]',
source: 'landing_page',
campaign: 'winter_sale'
})
// Demo request conversion
orwel.conversion('demo_request', {
company: 'Acme Corp',
phone: '+1234567890',
interest: 'enterprise'
})
// Contact form conversion
orwel.conversion('contact_form', {
name: 'John Doe',
email: '[email protected]',
message: 'Interested in your services'
})👤 Visitor Management
The SDK automatically manages visitor identification and persistence. Here's how it works:
Visitor Lifecycle
Initial Visit: When the SDK initializes, it automatically:
- Generates a unique visitor ID if none exists
- Stores it in localStorage under
__orwel_visitor__ - Collects basic browser information
Identifying Visitors: Use
identify()to attach traits to the visitor:
// Returns { success: true, visitorId: 'generated-uuid' }
const result = orwel.identify({
email: '[email protected]',
plan: 'pro'
})Automatic Data Collection
When calling identify(), the SDK automatically collects and merges:
- Browser information
- User agent details
- Language preferences
- Platform information
These are merged with your provided traits, but your explicit values take precedence.
Storage & Persistence
- Visitor data is stored in localStorage
- Persists across page reloads and browser sessions
- Automatically loaded when SDK initializes
- Synced with server on identify calls
Implementation Details
The visitor manager:
- Loads existing visitor data on init
- Generates UUID for new visitors
- Merges browser info with provided traits
- Persists data to localStorage
- Queues identify event for server sync
🎯 Conversion Tracking
Conversion tracking allows you to capture potential customers and prospects with structured data collection. Unlike visitor identification, conversions are independent entities with their own unique identifiers.
Conversion vs Identify
| Feature | identify() | conversion() |
|---------|-------------|----------|
| Purpose | Update current visitor traits | Capture conversion information |
| Persistence | Saves to visitor profile | Independent conversion record |
| ID Generation | Uses visitor ID | Generates unique conversion ID |
| Event Type | identify | conversion |
| Use Cases | User login, profile updates | Forms, newsletters, demos |
Conversion Event Structure
When you call orwel.conversion(), it generates an event with this structure:
{
type: 'conversion',
code: 'newsletter_signup', // The event code you provided
properties: {
id: 'conversion-uuid-generated', // Unique conversion identifier
email: '[email protected]',
source: 'landing_page',
// ... other properties + browser info
},
timestamp: '2024-01-01T12:00:00.000Z'
}Common Conversion Types
// Newsletter subscription
orwel.conversion('newsletter_signup', {
email: '[email protected]',
source: 'footer_form',
interests: ['product_updates', 'marketing']
})
// Demo request
orwel.conversion('demo_request', {
company: 'Tech Corp',
email: '[email protected]',
phone: '+1-555-0123',
employees: '50-100',
use_case: 'customer_analytics'
})
// Contact form
orwel.conversion('contact_form', {
name: 'Sarah Johnson',
email: '[email protected]',
subject: 'Partnership Inquiry',
message: 'We would like to discuss...'
})
// Whitepaper download
orwel.conversion('whitepaper_download', {
email: '[email protected]',
title: 'State of Analytics 2024',
job_title: 'Data Analyst',
company_size: '100-500'
})Automatic Data Collection
The conversion() method automatically collects and merges:
- Browser information (user agent, language, platform)
- Page context (URL, referrer, timestamp)
- Session data when available
Best Practices
- Use descriptive codes:
newsletter_signup,demo_request,contact_form - Consistent naming: Use snake_case for event codes
- Required fields: Always include essential contact information (email, phone, etc.)
- Source tracking: Include
source,campaign,mediumfor attribution - Progressive profiling: Capture additional data over time, not all at once
- GDPR compliance: Respect privacy preferences and consent management
Session Management
// Store performance metrics and other data in the session
orwel.session({
currentPage: 'homepage',
experimentGroup: 'B',
userPreferences: {
theme: 'dark',
language: 'en'
}
})Application Monitoring
// Enable all monitoring features
orwel.monitor()
// Or customize monitoring options
orwel.monitor({
performance: true, // Page load and navigation timing
errors: true, // JavaScript errors and unhandled rejections
console: true, // Console errors and warnings
network: false // XHR and Fetch API calls
})🚀 Batch Processing
The SDK automatically batches events for optimal performance:
// Multiple events are queued and sent together
orwel.track('page_view', { path: '/dashboard' });
orwel.track('button_click', { buttonId: 'cta-header' });
orwel.conversion('newsletter_signup', { email: '[email protected]' });
// Events are automatically batched and sent in a single HTTP request
// Or manually flush the queue
const result = await orwel.flush();
console.log(`Sent ${result.count} events in batch`);Batch Benefits
- Performance: 5-10x faster than individual requests
- Network: 90% reduction in HTTP requests
- Server Load: Reduced connection overhead
- Reliability: Automatic fallback to individual sends if batch fails
🛡️ Parameter Validation & Type Safety
The SDK includes comprehensive parameter validation with clear error messages:
// ❌ Invalid API key format
orwel.init({ apiKey: 'invalid_key' });
// Error: apiKey must start with "orwel_"
// ❌ Invalid event code format
orwel.track('Invalid-Event!', {});
// Error: Event code must contain only lowercase letters, numbers, and underscores
// ❌ Invalid email format
orwel.conversion('signup', { email: 'invalid-email' });
// Error: Invalid email format in properties
// ✅ Correct usage
orwel.init({ apiKey: 'orwel_your_key_here_12345' });
orwel.track('button_click', { buttonId: 'cta-header' });Validation Rules
- API Keys: Must start with
orwel_and be at least 20 characters - Event Codes: Lowercase letters, numbers, and underscores only (max 50 chars)
- Email Addresses: Validated automatically when present in properties
- Required Parameters: Clear error messages for missing required fields
- Type Safety: Runtime validation ensures correct data types
IntelliSense Features
- Method Documentation: Hover over any method to see detailed descriptions
- Parameter Hints: Complete parameter documentation with examples
- Return Type Info: Full TypeScript definitions for all return values
- Usage Examples: Code examples shown directly in your IDE
🔗 Quickstart (via CDN)
<script src="https://cdn.orwel.io/orwel.js"></script>
<script>
orwel.init({ apiKey: 'pk_live_abc123' })
orwel.track('page_view', { url: window.location.pathname })
</script>🧠 Available Methods
| Method | Description | Best Practices |
|--------|-------------|----------------|
| init(config) | Set your apiKey for identification | Call as early as possible in your app lifecycle. Required before using other methods. |
| identify(traits) | Attach metadata to the current visitor | Call after user authentication or when user data becomes available. Persists across sessions. |
| lead(code, properties) | Capture lead information with event code | Use for newsletter signups, demo requests, contact forms. Each lead gets unique ID. |
| track(code, props) | Track named events | Use consistent event names. Include relevant properties for analysis. |
| session(props, final?) | Store session data | Use for temporary state that shouldn't persist across sessions. Automatically included with events. Set final=true for session end. |
| form(element, options) | Track form interactions | Connect to important forms to capture user interaction data, submissions, and abandonment. |
| monitor(options) | Enable monitoring features | Enable early to catch all relevant metrics. Consider performance impact of enabled features. |
| flush() | Force-send pending events | Called automatically on page unload. Manual calls rarely needed. |
📝 Form Tracking
The SDK provides comprehensive form tracking capabilities to give you insights into how users interact with your forms.
Form Tracking Setup
// Get a reference to your form
const signupForm = document.getElementById('signup-form');
// Start tracking the form
orwel.form(signupForm, {
formId: 'user_signup', // Unique identifier for the form
trackFocus: true, // Track when fields are focused
trackInput: true, // Track when users enter data in fields
trackChange: true, // Track when field values change
trackSubmit: true, // Track form submissions
trackAbandon: true, // Track when users abandon forms
autoUntrack: true, // Automatically stop tracking when form is removed/hidden (default: true)
submitCallback: (result) => { // Optional callback after submission
if (result.success) {
// Form submission successful
} else {
// Form submission failed
console.error(result.error);
}
}
});Form Events
The form tracker generates the following events:
| Event | Description | Key Properties |
|-------|-------------|----------------|
| form_focus | User focused on a form field | form_id, field_id, field_name, field_type |
| form_input | User entered data in a form field | form_id, field_id, field_name, field_type, has_value |
| form_change | User changed a form field value | form_id, field_id, field_name, field_type |
| form_submit_attempt | User attempted to submit the form | form_id, form_fields_count, fields_filled_count, time_on_form_ms |
| form_submit_success | Form submitted successfully | form_id, form_fields_count, fields_filled_count, time_on_form_ms |
| form_submit_error | Form submission failed | form_id, validation_failed, invalid_fields, error_message |
| form_abandon | User abandoned form before completing | form_id, fields_started, fields_changed, time_on_form_ms, time_since_last_interaction_ms |
Form Tracking Best Practices
- Add form tracking early in your page lifecycle
- Use consistent
formIdvalues across your application - Track critical forms (signup, checkout, contact, etc.)
- Analyze form abandonment to identify UX problems
- Optimize forms based on field interaction data
- Monitor submission errors to fix validation issues
- The
autoUntrackoption is enabled by default and will automatically stop tracking forms that are:- Removed from the DOM
- Hidden or not visible for more than 10 seconds
- When navigating to other pages
Form Abandonment
The SDK automatically tracks form abandonment when a user:
- Spends at least 10 seconds on the form
- Interacts with the form in the last 30 minutes
- Has filled at least one field
- Has changed at least one field
🔍 Monitoring Features
The SDK includes comprehensive application monitoring that can be enabled with one line of code. Each feature is designed to have minimal performance impact and can be enabled/disabled independently.
Performance Monitoring
Automatically tracks:
- Navigation Timing API metrics
- Resource loading performance
- Paint timing (FP, FCP)
- Custom performance marks/measures
// Example: Track custom performance mark
performance.mark('feature_loaded')Web Vitals Monitoring
Note: Web Vitals monitoring is implemented but not automatically enabled with monitor(). It requires manual setup.
Core Web Vitals tracked:
- LCP (Largest Contentful Paint)
- Good: < 2.5s
- Needs Improvement: 2.5s - 4s
- Poor: > 4s
- FID (First Input Delay)
- Good: < 100ms
- Needs Improvement: 100ms - 300ms
- Poor: > 300ms
- CLS (Cumulative Layout Shift)
- Good: < 0.1
- Needs Improvement: 0.1 - 0.25
- Poor: > 0.25
Error Monitoring
Captures:
- Uncaught JavaScript errors
- Unhandled promise rejections
- Stack traces and error context
- Source file and line numbers
Best practices:
try {
// Your code
} catch (error) {
// Orwel automatically captures these
console.error('Operation failed:', error)
}Console Monitoring
Tracks:
console.error()callsconsole.warn()calls- Automatic deduplication
- Rate limiting to prevent flooding
Network Monitoring
Captures:
- XHR/Fetch requests
- Response times
- Status codes
- Request/response sizes
- Automatic correlation with events
📊 Automatic Data Collection
The SDK automatically collects contextual data when you call identify():
Browser & Platform
// Automatically collected - no code required
{
userAgent: "Mozilla/5.0...",
language: "en-US",
platform: "MacIntel",
doNotTrack: "1",
browserName: "Chrome",
browserVersion: "91.0.4472.124"
}Screen & Window
// Automatic collection
{
screenWidth: 1920,
screenHeight: 1080,
colorDepth: 24,
pixelRatio: 2,
viewportWidth: 1200,
viewportHeight: 800
}Device Capabilities
// Automatic collection
{
touchscreen: true,
darkMode: false,
online: true,
connectionType: "4g",
memory: "8GB",
cpuCores: 8
}💾 Offline & Resilient
The SDK implements several strategies to ensure data reliability:
Event Queue
- Events are stored in localStorage when offline
- Automatic retry with exponential backoff
- Queue persistence across page reloads
- Automatic queue cleanup
Session Handling
- Unique session IDs per browser session
- Automatic session recovery after crashes
- Session data persistence in localStorage
- Merge strategy for concurrent updates
Visitor Identification
- Anonymous visitor IDs (UUID v4)
- Cross-session visitor tracking
- Privacy-compliant tracking
- Automatic ID management
🔧 Configuration Options
orwel.init({
// Required
apiKey: 'your-orwel-api-key',
// Optional features
autoMonitor: true, // Enable all monitoring
autoEventDetection: true, // Enable automatic event detection
debug: false, // Enable debug logging
verbose: false, // Enable verbose logging
// Auto event detection options
eventDetectionOptions: {
enabledCategories: ['auth', 'ecommerce', 'navigation', 'form'],
confidenceThreshold: 0.7
}
});🚀 Session Tracking
Sessions are a core concept in Orwel, providing a way to group related events and metrics:
Session Lifecycle
- Creation: New session on SDK initialization
- Updates: Through
session()method calls - Expiration: After inactivity timeout
- Termination: On page unload
Session Data
// Add custom data - merges with existing
orwel.session({
userPreferences: {
theme: 'dark',
fontSize: 'large'
},
abTests: {
newHeader: 'variant_b',
checkoutFlow: 'two_step'
}
});
// Update specific values
orwel.session({
activePage: 'checkout',
cartValue: 99.99
});Automatic Collection
When monitoring is enabled, sessions automatically include:
- Page load metrics
- Resource timing
- Error counts
- Network activity
- Memory usage
- Web Vitals
Session Events
The SDK automatically tracks session lifecycle:
- Session Start: Initial creation
- Session Updates: Property changes
- Session End: Clean termination
- Session Timeout: Inactivity detection
🔒 Privacy & Security
The SDK implements several privacy and security measures:
Data Collection
- Respects Do Not Track
- No PII collection by default
- Configurable data retention
- Data minimization
Security
- HTTPS-only API endpoints
- API key validation
- Rate limiting
- Request signing
Compliance
- GDPR-ready
- CCPA-compliant
- Cookie law compatible
- Privacy policy friendly
⚠️ Current Limitations
While the SDK is fully functional, some features are implemented but not yet integrated:
Not Currently Available in monitor():
- Web Vitals Monitoring: Implementation exists but requires manual setup
- Memory Monitoring: Implementation exists but not integrated in monitoring system
Available Monitoring Features:
- ✅ Performance monitoring (Navigation, Resource timing)
- ✅ Error monitoring (JS errors, Promise rejections)
- ✅ Console monitoring (errors, warnings)
- ✅ Network monitoring (XHR, Fetch requests)
📄 License
MIT — built with ✨ by orwel.io
🤝 Support
Need help? Check out:
Section Visibility Tracking
Using data-orwel-section
The Orwel SDK provides automatic tracking of section visibility on your website. This feature helps you understand how users engage with different sections of your content.
How to implement
- Add the
data-orwel-sectionattribute to any HTML element you want to track:
<div data-orwel-section="hero-banner">
<!-- Your content here -->
</div>
<section data-orwel-section="product-features">
<!-- Your content here -->
</section>- The SDK will automatically detect and track these sections, measuring:
- Total time (in milliseconds) the section was visible in the viewport
- Maximum visibility percentage achieved
- Word count within the section
- User interactions with the section (clicks, scrolls)
Payload Structure
The section visibility data will be included in the event payload under the sectionEngagement property:
{
"sectionEngagement": [
{
"sectionId": "hero-banner",
"totalVisibilityMs": 12500,
"maxVisibilityPercentage": 1.0,
"wordCount": 45,
"interactions": {
"clicks": 2,
"scrollsInside": 1
}
},
{
"sectionId": "product-features",
"totalVisibilityMs": 8200,
"maxVisibilityPercentage": 0.75,
"wordCount": 120,
"interactions": {
"clicks": 0,
"scrollsInside": 3
}
}
]
}Best Practices
- Use descriptive IDs that reflect the content or purpose of the section
- Apply to meaningful content sections rather than small UI elements
- Consider the natural reading flow when deciding which sections to track
- Track key conversion sections to understand engagement correlation with conversions
