Events
Listen to lifecycle, user, and submission events
TheWebRatings emits events throughout the entire review journey. Listen to these events to add custom logic, track user behavior, grant rewards, or integrate with analytics.
All event payloads include timestamp and version fields.
Event API
// Add event listener
TheWebRatings.on(eventName, handler);
// Remove event listener
TheWebRatings.off(eventName, handler);Important: Set up event listeners after calling init(), but they work independently—no .then() chaining needed!
Setup Pattern (Recommended)
// Initialize the widget
TheWebRatings.init({
apiKey: 'your-api-key',
debug: true
});
// Set up event listeners (no .then needed!)
TheWebRatings.on('rating:submitted', (data) => {
console.log('Rating submitted!', data.ratingId, data.rating);
});
// Later, trigger the widget
function handleFeedbackClick() {
TheWebRatings.open(userEmail, userName);
}Initialization Events
init:complete
Fired when TheWebRatings.init() completes successfully.
TheWebRatings.on('init:complete', (data) => {
console.log('TheWebRatings is ready!');
console.log('App name:', data.appName);
console.log('Platform:', data.platform);
});
// Payload:
// {
// appName: "Your App",
// platform: "web",
// timestamp: 1234567890,
// version: "1.0.0"
// }Use case: Show a "Reviews ready" indicator, enable review buttons
Widget Lifecycle Events
modal:opened
Fired when the review modal is opened.
TheWebRatings.on('modal:opened', (data) => {
console.log('Review modal opened');
console.log('Triggered by:', data.trigger);
// Example: Track analytics
analytics.track('Review Modal Opened', {
trigger: data.trigger
});
});
// Payload:
// {
// trigger: "open_call",
// timestamp: "...",
// version: "0.1.x"
// }Use case: Track modal open rate, pause background music, disable page scrolling
widget:closed
Fired when the review widget is closed.
TheWebRatings.on('widget:closed', (data) => {
console.log('Widget closed');
console.log('Reason:', data.reason);
if (data.rating) {
console.log('User submitted rating:', data.rating);
}
});
// Payload:
// {
// reason: "user_action",
// rating: 4, // optional; present if user had submitted a rating this session
// timestamp: "...",
// version: "0.1.x"
// }Use case: Re-enable page scrolling, track abandonment rate, resume background tasks
User Events
user:detected
Fired when a returning user is automatically identified (from localStorage or session).
TheWebRatings.on('user:detected', (data) => {
console.log('Returning user detected!');
console.log('Email:', data.email);
console.log('Name:', data.name);
});
// Payload:
// {
// email: "[email protected]",
// name: "John Doe",
// timestamp: 1234567890,
// version: "1.0.0"
// }Use case: Skip OTP verification, personalize greeting, track returning users
user:created
Fired when a user is created or retrieved from the backend.
TheWebRatings.on('user:created', (data) => {
console.log('User created or retrieved');
console.log('Is cached?', data.fromCache);
console.log('User ID:', data.user.twr_user_id);
});
// Payload:
// {
// user: { twr_user_id, user_email, user_name, ... },
// fromCache: false,
// timestamp: "...",
// version: "0.1.x"
// }Use case: Store user ID in your database, link TWR user to your internal user
user:error
Fired when user identification or creation fails.
TheWebRatings.on('user:error', (data) => {
console.error('User error:', data.error);
console.error('Reason:', data.reason);
if (data.reason === 'missing_user') {
// Prompt user to provide email
}
});
// Payload:
// {
// error: "Network error" | "Invalid email" | "User creation failed",
// reason: "missing_user" | "network" | "validation",
// message: "User-friendly error message",
// timestamp: 1234567890,
// version: "1.0.0"
// }Use case: Show error to user, retry logic, fallback to different auth method
Submission Events
submission:start
Fired when the user clicks "Submit" and the submission process begins.
TheWebRatings.on('submission:start', (data) => {
console.log('Submitting review...');
// Example: Show loading indicator
showLoadingSpinner();
});
// Payload:
// {
// rating: 5,
// timestamp: "...",
// version: "0.1.x"
// }Use case: Show loading spinner, track submission attempts
rating:submitted ⭐
Fired when a new rating is successfully submitted (after OTP verification when required).
TheWebRatings.on('rating:submitted', (data) => {
console.log('✅ Rating submitted!');
console.log('Rating ID:', data.ratingId);
console.log('Rating:', data.rating);
// Example: Grant reward for 5-star ratings
if (data.rating === 5) {
grantDiscount(userEmail);
}
analytics.track('Review Submitted', { ratingId: data.ratingId, rating: data.rating });
});
// Payload:
// {
// ratingId: "rating_abc123",
// rating: 5,
// timestamp: "...",
// version: "0.1.x"
// }Use cases: Grant rewards, track analytics, send thank-you emails, update UI.
Note: On network failure the widget stores the review locally and still shows the success screen. No submission:error event is emitted in that case; use rating:submitted when submission succeeds.
Rating Management Events
rating:updated
Fired when a user updates their existing rating.
TheWebRatings.on('rating:updated', (data) => {
console.log('Rating updated!');
console.log('Rating ID:', data.ratingId);
console.log('New rating:', data.newRating);
});
// Payload:
// {
// ratingId: "rating_abc123",
// newRating: 5,
// newReview: "Updated review text",
// timestamp: 1234567890,
// version: "1.0.0"
// }Use case: Track rating changes, update analytics, notify admins of edits
rating:deleted
Fired when a user deletes their rating.
TheWebRatings.on('rating:deleted', (data) => {
console.log('Rating deleted');
console.log('Rating ID:', data.ratingId);
});
// Payload:
// {
// ratingId: "rating_abc123",
// timestamp: 1234567890,
// version: "1.0.0"
// }Use case: Track deletions, update metrics, remove rewards
Complete Real-World Example
Here's a production-ready setup with all key events:
// Initialize widget
TheWebRatings.init({
apiKey: 'your-api-key',
debug: false // Turn off debug in production
});
// Track initialization
TheWebRatings.on('init:complete', () => {
console.log('TheWebRatings ready');
});
// Track modal opens
TheWebRatings.on('modal:opened', () => {
analytics.track('Review Modal Opened');
// Pause background music, disable page scroll
document.body.style.overflow = 'hidden';
});
// Handle successful submission
TheWebRatings.on('rating:submitted', (data) => {
const rating = data.rating;
analytics.track('Review Submitted', { ratingId: data.ratingId, rating });
if (rating >= 4) {
fetch('/api/rewards/grant', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ reward: 'discount_10' })
});
}
showNotification(`Thank you for your ${rating}-star rating! 🎉`);
});
// Track widget closure
TheWebRatings.on('widget:closed', (data) => {
// Re-enable page scroll
document.body.style.overflow = 'auto';
// Track analytics
analytics.track('Review Modal Closed', {
reason: data.reason,
submitted: data.rating > 0
});
});Cleanup: Remove Event Listeners
When you no longer need an event listener (e.g., component unmounting in React):
const handleSuccess = (data) => {
console.log('Review submitted!', data);
};
// Add listener
TheWebRatings.on('rating:submitted', handleSuccess);
// Later: Remove listener
TheWebRatings.off('rating:submitted', handleSuccess);Important: Use named functions (not anonymous) if you need to remove listeners later!
// ❌ Can't remove this later (anonymous function)
TheWebRatings.on('rating:submitted', (data) => { /* ... */ });
// ✅ Can remove this later (named function)
const handleSuccess = (data) => { /* ... */ };
TheWebRatings.on('rating:submitted', handleSuccess);Next Steps
- Configuration Options - Customize widget behavior
- Triggers - Automatically show widget based on conditions
- Examples - Copy-paste code snippets
Need help? Join our Discord or email [email protected]