Triggers
A trigger decides when a popup shows. The trigger is configured by your team in Deepdots and delivered to the SDK automatically — you never write trigger definitions in code.
However, depending on the trigger type, your application may need to do something so the trigger can actually fire: render an element with a specific id, emit a custom business event, etc. This page explains each type and shows the host-side code required.
The five trigger types
Section titled “The five trigger types”| Type | Fires when… | Value semantics |
|---|---|---|
time_on_page | The user has been on a page for N seconds. | number — seconds on page |
scroll | The user has scrolled N% of the page height. | number — percentage 0–100 |
click | The user clicks an element with a specific DOM id. | string — the element’s id attribute |
exit | The user navigates away from the current route. | number — seconds of delay on the next route |
event | Your application calls popups.triggerEvent(name). | string — the event name |
time_on_page
Section titled “time_on_page”Fires after the user has spent a number of seconds on the page.
Host-side code: none. As long as the SDK has been initialized and autoLaunch() was called, the SDK starts the timer when the page loads.
import { DeepdotsPopups } from '@magicfeedback/popup-sdk';
const popups = new DeepdotsPopups();popups.init({ mode: 'server', apiKey: 'YOUR_PUBLIC_API_KEY' });popups.autoLaunch();// Time triggers configured in Deepdots will now fire on their own.scroll
Section titled “scroll”Fires when the user has scrolled past a given percentage of the page height.
Host-side code: none. The SDK attaches its own scroll listener and removes it once the threshold is reached.
popups.init({ mode: 'server', apiKey: 'YOUR_PUBLIC_API_KEY' });popups.autoLaunch();// A scroll trigger configured at 70% in Deepdots fires automatically// when the user reaches 70% of the page.Fires when the user clicks a DOM element with a specific id.
Host-side code: your application must render an element whose id matches the value configured in Deepdots.
<!-- Any element with the configured id will trigger the popup --><button id="feedback-btn">Give feedback</button>Or, in a framework:
// React<button id="feedback-btn" onClick={handleClick}> Give feedback</button>The SDK attaches a one-shot click listener to the element. Once it fires, the listener is removed automatically.
Queues a popup to appear on the next route after the user leaves the current one. Useful for “before you go” surveys without blocking navigation.
Host-side code: none for standard SPA navigation. The SDK monkey-patches history.pushState / history.replaceState and listens to popstate, hashchange, and same-origin link clicks. Any normal client-side route change is detected.
popups.init({ mode: 'server', apiKey: 'YOUR_PUBLIC_API_KEY' });popups.autoLaunch();// When the user navigates away from a targeted route,// the popup is queued and shown on the next route after the configured delay.How it works in practice:
- The user is on
/pricing(where an exit trigger is targeted). - The user clicks a link to
/features. - The SDK queues the popup in
sessionStorage. - On
/features, after the delay configured in Deepdots, the popup appears.
Fires when your application emits a custom business event by name. This is the trigger type you will use most often in code.
Host-side code: call popups.triggerEvent(eventName) whenever the business condition is met. The event name must match exactly the value configured for the trigger in Deepdots.
import { DeepdotsPopups } from '@magicfeedback/popup-sdk';
const popups = new DeepdotsPopups();popups.init({ mode: 'server', apiKey: 'YOUR_PUBLIC_API_KEY' });popups.autoLaunch();
// Later, when something interesting happens in your app:function onCheckoutCompleted() { popups.triggerEvent('checkout_completed');}
function onSearchAttempted(query: string) { if (searchAttempts >= 3) { popups.triggerEvent('search_no_results'); }}Example: React
Section titled “Example: React”function CheckoutButton({ popups }: { popups: DeepdotsPopups }) { return ( <button onClick={async () => { await placeOrder(); popups.triggerEvent('checkout_completed'); }} > Pay </button> );}Example: Vanilla JS in any flow
Section titled “Example: Vanilla JS in any flow”async function submitContactForm(data) { const ok = await api.submit(data); if (ok) { popups.triggerEvent('contact_form_sent'); }}Multiple triggers on the same popup
Section titled “Multiple triggers on the same popup”A popup in Deepdots can have more than one trigger. Any of them firing will show the popup (subject to cooldowns and route targeting). For example: a popup might be configured to fire after 30 seconds or when the user emits cart_abandoned, whichever happens first.
You don’t need to do anything special in code — just make sure your application provides the right host signals (mounting the click target id, calling triggerEvent, etc.) for every trigger type the popup uses.
Manually showing a popup outside any trigger
Section titled “Manually showing a popup outside any trigger”If you need to bypass triggers entirely — for example, a “Feedback” button always available in the footer — call show() or showByPopupId() directly:
popups.show({ surveyId: 'survey-feedback-001', productId: 'product-main',});
// Or, if you know the popup id from Deepdots:popups.showByPopupId('popup-footer-feedback');Cooldowns and route targeting are still respected.