Skip to main content
Event triggers allow you to show popups in response to business logic and user behavior that goes beyond simple DOM interactions. Instead of relying on time, scroll, or click triggers, you can fire popups when specific actions occur in your application.

When to Use Event Triggers

Use event triggers when popup logic depends on product behavior:
  • Search behavior: Show feedback after repeated searches with low engagement
  • Feature usage: Collect input after a user completes a specific workflow
  • Error states: Request feedback when users encounter issues
  • Milestones: Celebrate achievements and gather sentiment
  • Business rules: Fire popups based on complex conditions in your app
Event triggers give you full control over popup timing based on your application’s state and business logic.

How It Works

1

Define an event-based popup

Create a popup definition with type: 'event' and specify the event name:
const popupDefinitions = [
  {
    id: 'popup-search-event',
    title: 'Help us improve search',
    message: '<p>Did you find what you were looking for?</p>',
    triggers: {
      type: 'event',
      value: 'search', // Your custom event name
      condition: [{ answered: false, cooldownDays: 3 }],
    },
    surveyId: 'survey-search-001',
    productId: 'product-main',
    actions: {
      accept: {
        label: 'Share Feedback',
        surveyId: 'survey-search-001',
      },
    },
  },
];
2

Initialize the SDK

import { DeepdotsPopups } from '@magicfeedback/popup-sdk';

const popups = new DeepdotsPopups();

popups.init({
  mode: 'server', // or 'client'
  apiKey: 'YOUR_API_KEY',
  debug: true,
});

popups.autoLaunch();
3

Trigger the event from your code

Call triggerEvent() when your business logic determines a popup should appear:
// In your application code
function handleSearch(query) {
  // Your search logic...
  performSearch(query);
  
  // Trigger the popup
  popups.triggerEvent('search');
}

Real-World Example: Search Intent Detection

This example from the casino demo shows how to track search behavior and trigger popups based on user intent signals:
import { DeepdotsPopups } from '@magicfeedback/popup-sdk';

const SEARCH_EVENT_NAME = 'search';
const SEARCH_WINDOW_MS = 120 * 1000; // 2 minutes
const SEARCH_EVENT_DEDUP_MS = 1200; // Dedup window

// Track search behavior
const searchBehavior = {
  searchTimestamps: [],
  lastSearchResultClickAt: 0,
  lastEventEmitAt: 0,
};

const sdk = new DeepdotsPopups();
sdk.init({
  mode: 'server',
  nodeEnv: 'production',
  debug: true,
  apiKey: 'YOUR_API_KEY',
  userId: 'customer-123',
});
sdk.autoLaunch();

// Evaluate search actions and emit SDK events
function registerSearchAction(query) {
  const normalized = String(query || '').trim().toLowerCase();
  if (normalized.length < 2) return;

  const now = Date.now();
  
  // Remove old searches outside the time window
  searchBehavior.searchTimestamps = searchBehavior.searchTimestamps
    .filter(ts => ts >= now - SEARCH_WINDOW_MS);
  
  searchBehavior.searchTimestamps.push(now);

  const searchesInWindow = searchBehavior.searchTimestamps.length;
  const searchesSinceLastClick = searchBehavior.searchTimestamps
    .filter(ts => ts > searchBehavior.lastSearchResultClickAt)
    .length;

  // Rule 1: Three searches in 2 minutes
  if (searchesInWindow >= 3) {
    emitSearchEvent('three_searches_120s');
    return;
  }

  // Rule 2: Two searches without clicking results
  if (searchesSinceLastClick >= 2) {
    emitSearchEvent('two_searches_no_click');
    return;
  }
}

// Track when user clicks a search result
function markSearchResultClick() {
  searchBehavior.lastSearchResultClickAt = Date.now();
}

// Emit the search event with deduplication
function emitSearchEvent(reason) {
  const now = Date.now();
  if (now - searchBehavior.lastEventEmitAt < SEARCH_EVENT_DEDUP_MS) {
    return; // Too soon, skip
  }

  searchBehavior.lastEventEmitAt = now;
  console.info('[app] triggerEvent', { eventName: 'search', reason });
  sdk.triggerEvent(SEARCH_EVENT_NAME);
}

// Use in your app
document.querySelector('#search-input').addEventListener('input', (e) => {
  registerSearchAction(e.target.value);
});

document.querySelectorAll('.search-result').forEach(result => {
  result.addEventListener('click', markSearchResultClick);
});
This example tracks search intent by monitoring:
  • Number of searches in a time window
  • Whether users click on search results
  • Time since last popup to avoid flooding

Simple Event Trigger Example

For simpler use cases, trigger events directly:
import { DeepdotsPopups } from '@magicfeedback/popup-sdk';

const popups = new DeepdotsPopups();

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

popups.autoLaunch();

// Trigger on button click
document.querySelector('#feedback-button').addEventListener('click', () => {
  popups.triggerEvent('feedback-button-click');
});

// Trigger after form submission
function handleFormSubmit(form) {
  // Submit form...
  submitForm(form);
  
  // Request feedback
  popups.triggerEvent('form-submitted');
}

// Trigger on error
function handleError(error) {
  logError(error);
  popups.triggerEvent('error-occurred');
}

API Reference

triggerEvent(eventName)

Shows the first eligible popup whose definition contains:
triggers: { type: 'event', value: eventName }
Parameters:
  • eventName (string): The name of the event to trigger. Must match the value field in your popup definition.
Example:
popups.triggerEvent('search');
popups.triggerEvent('checkout-complete');
popups.triggerEvent('feature-used');
Behavior:
  • Finds all popup definitions with matching event triggers
  • Evaluates conditions (answered, cooldownDays) and segments
  • Shows the first eligible popup
  • Logs debug info if no matching popups are found
The event name is case-sensitive and must match exactly. 'Search' and 'search' are different events.

Event Trigger Conditions

Control when event-triggered popups can fire:
triggers: {
  type: 'event',
  value: 'search',
  condition: [
    {
      answered: false,      // Only show if survey not completed
      cooldownDays: 3       // Wait 3 days between shows
    }
  ]
}
  • answered: false: Popup won’t show if user already completed the survey
  • cooldownDays: Minimum days between popup displays for this definition

Best Practices

Choose clear, specific event names that describe the business action:
// Good
popups.triggerEvent('checkout-abandoned');
popups.triggerEvent('trial-ending-soon');
popups.triggerEvent('feature-discovery');

// Avoid
popups.triggerEvent('event1');
popups.triggerEvent('popup');
Prevent flooding by tracking when you last triggered an event:
let lastTriggerTime = 0;
const DEDUP_WINDOW_MS = 5000; // 5 seconds

function triggerWithDedup(eventName) {
  const now = Date.now();
  if (now - lastTriggerTime < DEDUP_WINDOW_MS) {
    return; // Skip duplicate
  }
  lastTriggerTime = now;
  popups.triggerEvent(eventName);
}
Evaluate complex conditions before triggering:
function handleFeatureUsage(feature) {
  const usageCount = getFeatureUsageCount(feature);
  const userTier = getCurrentUserTier();
  
  // Only trigger for power users
  if (usageCount > 10 && userTier === 'pro') {
    popups.triggerEvent('power-user-feedback');
  }
}
Don’t trigger popups during critical workflows:
function shouldTriggerFeedback() {
  // Avoid interrupting checkout
  if (isCheckoutInProgress()) return false;
  
  // Avoid during onboarding
  if (isOnboardingActive()) return false;
  
  return true;
}

if (shouldTriggerFeedback()) {
  popups.triggerEvent('general-feedback');
}

Debugging Event Triggers

Enable debug mode to see event trigger logs:
popups.init({
  mode: 'server',
  apiKey: 'YOUR_API_KEY',
  debug: true, // Enable logging
});
The SDK will log:
  • When triggerEvent() is called
  • Which popup definitions match the event name
  • Why popups were blocked (conditions, segments, etc.)
  • When popups are shown

Next Steps

Exit Popups

Show popups when users navigate away

Route Targeting

Target popups to specific pages

Server Mode

Manage event triggers remotely

Client Mode

Define event triggers inline

Build docs developers (and LLMs) love