The Web Ratings
Going Deeper

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!


// 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

Need help? Join our Discord or email [email protected]