Skip to main content
The MagicFeedback Popup SDK emits lifecycle events that allow your application to track and respond to user interactions with popups.

Event Types

The SDK emits three event types:
  • popup_shown - Fired when a popup is displayed to the user
  • popup_clicked - Fired when the user interacts with popup elements
  • survey_completed - Fired when the user completes a survey

Event Structure

All events follow the same payload structure:
interface DeepdotsEvent {
  type: 'popup_shown' | 'popup_clicked' | 'survey_completed';
  surveyId: string;
  timestamp: number;
  data?: Record<string, unknown>;
}

Event Fields

FieldTypeDescription
typeDeepdotsEventTypeThe type of event that occurred
surveyIdstringThe survey ID associated with the popup
timestampnumberUnix timestamp (milliseconds) when the event occurred
dataRecord<string, unknown>Optional additional data about the event

Listening to Events

Subscribe to events using the on() method:
import { DeepdotsPopups } from '@magicfeedback/popup-sdk';

const popups = new DeepdotsPopups();

popups.init({
  mode: 'server',
  apiKey: 'YOUR_API_KEY',
});

popups.on('popup_shown', (event) => {
  console.log('Popup displayed:', event.surveyId);
  console.log('Timestamp:', event.timestamp);
});

popups.on('survey_completed', (event) => {
  console.log('Survey completed:', event.surveyId);
});

popups.autoLaunch();

Unsubscribing from Events

Remove event listeners using the off() method:
const handlePopupShown = (event) => {
  console.log('Popup shown:', event);
};

// Subscribe
popups.on('popup_shown', handlePopupShown);

// Unsubscribe
popups.off('popup_shown', handlePopupShown);
You must pass the exact same function reference to off() that you passed to on(). Anonymous functions cannot be unsubscribed.

Event Details

Fired when a popup is displayed to the user.
popups.on('popup_shown', (event) => {
  console.log(event);
  // {
  //   type: 'popup_shown',
  //   surveyId: 'survey-home-001',
  //   timestamp: 1678901234567,
  //   data: {
  //     popupId: 'popup-home-5s',
  //     userId: 'user-123'
  //   }
  // }
});
Common data fields:
  • popupId: The ID of the popup definition
  • userId: The user ID if provided in init()
Use Cases:
  • Analytics tracking
  • Impression counting
  • A/B test bucketing
  • User behavior analysis
Fired when the user interacts with any popup element (buttons, close icon, etc.).
popups.on('popup_clicked', (event) => {
  console.log(event);
  // {
  //   type: 'popup_clicked',
  //   surveyId: 'survey-home-001',
  //   timestamp: 1678901234567,
  //   data: {
  //     popupId: 'popup-home-5s',
  //     action: 'start_survey',
  //     userId: 'user-123'
  //   }
  // }
});
Common data.action values:
  • loaded - Popup iframe loaded successfully
  • start_survey - User clicked the start button
  • manual_send - User manually submitted the survey
  • back - User clicked the back button
  • complete - User clicked the complete button
  • close_icon - User clicked the X close icon
popup_clicked is a general interaction event. The specific action is determined by the data.action field.
Use Cases:
  • Engagement tracking
  • Funnel analysis
  • Understanding drop-off points
  • User interaction patterns

survey_completed

Fired when the user completes a survey.
popups.on('survey_completed', (event) => {
  console.log(event);
  // {
  //   type: 'survey_completed',
  //   surveyId: 'survey-home-001',
  //   timestamp: 1678901234567,
  //   data: {
  //     popupId: 'popup-home-5s',
  //     userId: 'user-123'
  //   }
  // }
});
Automatic Behavior:
  • When survey_completed is emitted, the SDK automatically marks the survey as answered
  • This affects future trigger conditions with answered: false
  • You can manually mark surveys as answered using markSurveyAnswered(surveyId)
Use Cases:
  • Conversion tracking
  • Thank you messages
  • Follow-up actions (email notifications, CRM updates)
  • Reward distribution
  • Preventing survey fatigue
If you need to manually mark a survey as answered (for example, if the user completes it outside the popup flow):
popups.markSurveyAnswered('survey-home-001');
This will prevent the survey from being shown again if the popup definition has a condition like:
triggers: {
  type: 'time_on_page',
  value: 5,
  condition: [{ answered: false, cooldownDays: 7 }]
}

Event Data Examples

Here are real-world examples of event payloads:
{
  "type": "popup_shown",
  "surveyId": "survey-pricing-feedback",
  "timestamp": 1678901234567,
  "data": {
    "popupId": "popup-pricing-exit",
    "userId": "customer-abc-123"
  }
}

Error Handling

Event listeners should handle errors gracefully. The SDK catches and logs errors in event listeners to prevent one failing listener from affecting others:
popups.on('popup_shown', (event) => {
  try {
    // Your tracking logic
    analytics.track('Popup Shown', event);
  } catch (error) {
    console.error('Failed to track popup:', error);
    // Error is caught by SDK and won't affect other listeners
  }
});
If an error occurs in an event listener, the SDK logs it to the console but continues processing other listeners and SDK operations normally.

Best Practices

Event listeners should execute quickly to avoid blocking the UI. If you need to perform expensive operations (API calls, complex calculations), do them asynchronously:
popups.on('survey_completed', (event) => {
  // Quick synchronous logging
  console.log('Survey completed:', event.surveyId);
  
  // Expensive async operation
  Promise.resolve().then(() => {
    sendToAnalytics(event);
    updateUserProfile(event.data?.userId);
  });
});
In single-page applications, always unsubscribe from events when components unmount:
useEffect(() => {
  const handler = (event) => console.log(event);
  popups.on('popup_shown', handler);
  
  return () => {
    popups.off('popup_shown', handler);
  };
}, []);
The SDK exports TypeScript types for events:
import type { 
  DeepdotsEvent, 
  DeepdotsEventType,
  EventListener 
} from '@magicfeedback/popup-sdk';

const handler: EventListener = (event: DeepdotsEvent) => {
  console.log(event.type, event.surveyId);
};

popups.on('popup_shown', handler);

Server-Side Event Reporting

In server mode, the SDK automatically reports popup_shown and survey_completed events to the Deepdots API for analytics and tracking:
// No additional code needed - automatic in server mode
popups.init({
  mode: 'server',
  apiKey: 'YOUR_API_KEY',
  userId: 'user-123',
});

// SDK automatically posts these events to the API:
// - popup_shown → POST /sdk/popups with status: 'opened'
// - survey_completed → POST /sdk/popups with status: 'completed'
Server-side event reporting only happens in server mode and requires a valid apiKey. Events are still emitted locally via on() regardless of mode.

Build docs developers (and LLMs) love