Skip to main content

Overview

Exit triggers let you show popups after a user leaves a specific route. Unlike traditional exit intent that blocks navigation, these popups appear on the destination page after a configured delay. This is perfect for “before you go” or “how was your experience” feedback flows that don’t interrupt the user’s navigation.

How Exit Triggers Work

1

User is on a matching route

The SDK monitors navigation and checks if the current route matches a popup’s segments.path configuration.
2

User navigates away

When the user leaves the matching route (via anchor click, hash navigation, or history.pushState), the SDK queues the exit popup.
3

Popup shows on destination

After the configured delay (in seconds), the popup appears on the new route.
Pending exit popups are stored in sessionStorage until they’re shown or discarded.

Basic Example

Here’s how the demo website (examples/index.htmlexamples/product.html) implements exit popups:
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Home Page</title>
  <script type="importmap">
    {
      "imports": {
        "@magicfeedback/popup-sdk": "https://cdn.jsdelivr.net/npm/@magicfeedback/[email protected]/dist/index.mjs"
      }
    }
  </script>
</head>
<body>
  <header class="navbar">
    <nav>
      <a href="#features">Features</a>
      <a href="#customers">Customers</a>
      <a href="./product.html">Product page</a>
    </nav>
  </header>

  <main>
    <section class="hero">
      <h1>Understand your users with delightful popups</h1>
      <p>Gather rich feedback at the right time and place.</p>
    </section>

    <section id="features">
      <h2>Powerful features</h2>
      <div class="cards">
        <a class="card" href="./product.html">
          <h3>Smart triggers</h3>
          <p>Time on page, scroll depth, exit intent, and more.</p>
          <span class="route-cta">Open product route →</span>
        </a>
      </div>
    </section>
  </main>

  <script type="module">
    import { initDemoSdk } from './demo-sdk.js';

    const eventLog = document.getElementById('event-log');
    const { sdk } = initDemoSdk({ eventLogEl: eventLog });

    // Start all triggers including exit intent
    sdk.autoLaunch();
  </script>
</body>
</html>
Configure an exit popup in your Deepdots dashboard or client-mode definition:
{
  "id": "popup-exit-home",
  "title": "Before you go...",
  "message": "<p>How was your experience on our homepage?</p>",
  "triggers": {
    "type": "exit",
    "value": 3,
    "condition": [
      {
        "answered": false,
        "cooldownDays": 7
      }
    ]
  },
  "actions": {
    "accept": {
      "label": "Give feedback",
      "surveyId": "survey-exit-001"
    }
  },
  "surveyId": "survey-exit-001",
  "productId": "product-main",
  "segments": {
    "path": ["/", "/index.html", "/#/home"]
  }
}

Key Properties

PropertyDescription
triggers.typeSet to "exit"
triggers.valueDelay in seconds after navigation
segments.pathRoutes where exit should be monitored
The value is the delay after navigation completes, not during navigation.
Exit triggers work with all common navigation patterns:

Path Matching

The segments.path array supports multiple formats:
{
  "segments": {
    "path": [
      "/",                          // Root path
      "/pricing",                   // Specific path
      "/products/123",              // Path with ID
      "/#/home",                    // Hash route
      "https://example.com/blog"   // Full URL
    ]
  }
}
Path matching is exact. Use separate entries for paths with and without trailing slashes if needed.

Complete Working Example

Here’s a full implementation with exit tracking:
demo-sdk.js
import { DeepdotsPopups } from '@magicfeedback/popup-sdk';

function formatLogLine(event) {
  const time = new Date(event.timestamp).toLocaleTimeString();
  const action = event?.data?.action ? ` (${event.data.action})` : '';
  return `[${time}] ${event.type} - survey:${event.surveyId}${action}`;
}

export function initDemoSdk({ modeLabelEl, eventLogEl } = {}) {
  const mode = 'server';

  const sdk = new DeepdotsPopups();
  sdk.init({
    mode,
    nodeEnv: 'production',
    debug: true,
    apiKey: 'YOUR_PUBLIC_API_KEY'
  });

  if (modeLabelEl) {
    modeLabelEl.textContent = mode;
  }

  if (eventLogEl) {
    const log = (ev) => {
      const line = document.createElement('div');
      line.className = 'event';
      line.textContent = formatLogLine(ev);
      eventLogEl.appendChild(line);
      eventLogEl.scrollTop = eventLogEl.scrollHeight;
    };
    sdk.on('popup_shown', log);
    sdk.on('popup_clicked', log);
    sdk.on('survey_completed', log);
  }

  return { sdk };
}

Use Cases

Page Feedback

Ask “How helpful was this page?” after users navigate away

Feature Discovery

Show tips about features on the next page after leaving

Content Rating

Request article ratings after users finish reading

Exit Survey

Gather feedback when users leave critical flows

Testing Exit Popups

1

Enable Debug Mode

sdk.init({
  mode: 'server',
  apiKey: 'YOUR_API_KEY',
  debug: true  // Shows console logs
});
2

Check SessionStorage

Open DevTools → Application → Session StorageLook for keys like:
  • deepdots_pending_exit_popups
  • deepdots_survey_states
3

Navigate Between Routes

  1. Visit a page with an exit trigger configured
  2. Navigate to a different page
  3. Wait for the configured delay
  4. The popup should appear
4

Check Console Logs

With debug: true, you’ll see:
[Deepdots] Exit trigger queued for popup-exit-home
[Deepdots] Showing queued exit popup after 3s delay
[Deepdots] popup_shown - survey:survey-exit-001

Advanced: Client Mode with Exit Triggers

You can test exit popups locally without an API:
import { DeepdotsPopups } from '@magicfeedback/popup-sdk';

const popupDefinitions = [
  {
    id: 'popup-exit-local',
    title: 'Thanks for visiting!',
    message: '<p>How was your experience?</p>',
    triggers: {
      type: 'exit',
      value: 2,  // 2 second delay
      condition: [{ answered: false, cooldownDays: 1 }]
    },
    actions: {
      accept: {
        label: 'Share feedback',
        surveyId: 'survey-local-001'
      }
    },
    surveyId: 'survey-local-001',
    productId: 'product-local',
    segments: {
      path: ['/index.html', '/']
    }
  }
];

const sdk = new DeepdotsPopups();
sdk.init({
  mode: 'client',
  debug: true,
  popups: popupDefinitions
});

sdk.autoLaunch();

Common Issues

Remember:
  • Paths are exact match (case-sensitive)
  • Include both /page and /page/ if needed
  • Hash routes need the # prefix: "/#/home"

API Reference

Exit Trigger Schema

interface ExitTrigger {
  type: 'exit';
  value: number;  // Delay in seconds
  condition?: Array<{
    answered: boolean;
    cooldownDays: number;
  }>;
}

interface PopupSegments {
  path?: string[];  // Routes to monitor for exit
  [key: string]: unknown;
}

Best Practices

  1. Keep delays short: 2-5 seconds is ideal. Users forget context quickly.
  2. Use cooldowns: Don’t show exit popups on every navigation.
  3. Target specific routes: Only monitor high-value pages.
  4. Test across browsers: Different browsers handle history API slightly differently.
  5. Monitor sessionStorage: Exit state persists across page loads in the same tab.

Next Steps

Basic Integration

Learn SDK fundamentals and setup

Business Events

Trigger popups from application logic

Build docs developers (and LLMs) love