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
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' ,
},
},
},
];
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 ();
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
Use descriptive event names
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 );
}
Combine with business logic
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