> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/MagicFeedback/deepdots-popup-sdk/llms.txt
> Use this file to discover all available pages before exploring further.

# Exit Popups

> Learn how to configure route exit triggers and show popups after navigation

Exit popups appear after users navigate away from a page, making them perfect for "before you go" feedback flows that capture insights without interrupting the user's current journey.

## How Exit Triggers Work

Unlike traditional exit-intent popups that try to catch the user before they leave, the MagicFeedback SDK's exit triggers are designed for a better user experience:

1. **User visits a matching route** (e.g., `/pricing`)
2. **User navigates away** to a different route
3. **Exit trigger is queued** in sessionStorage
4. **After a configurable delay** on the destination route, the popup appears

<Note>
  Exit popups appear **after** navigation, not before. This avoids interrupting the user's intent to navigate while still capturing valuable feedback.
</Note>

## Defining Exit Triggers

<CodeGroup>
  ```typescript Client Mode theme={null}
  const popupDefinitions = [
    {
      id: 'popup-pricing-exit',
      title: 'Feedback on pricing',
      message: '<p>Help us understand your pricing concerns.</p>',
      triggers: {
        type: 'exit',
        value: 3, // Delay in seconds after navigation
        condition: [{ answered: false, cooldownDays: 14 }],
      },
      surveyId: 'survey-pricing-exit',
      productId: 'product-main',
      segments: {
        path: ['/pricing'], // Show when leaving /pricing
      },
      actions: {
        accept: {
          label: 'Share Feedback',
          surveyId: 'survey-pricing-exit',
        },
      },
    },
  ];

  const popups = new DeepdotsPopups();
  popups.init({
    mode: 'client',
    popups: popupDefinitions,
  });
  popups.autoLaunch();
  ```

  ```typescript Server Mode theme={null}
  // In server mode, configure exit triggers in your Deepdots dashboard
  // The popup definition will include:
  // triggers: { type: 'exit', value: 3 }
  // segments: { path: ['/pricing'] }

  const popups = new DeepdotsPopups();
  popups.init({
    mode: 'server',
    apiKey: 'YOUR_API_KEY',
  });
  popups.autoLaunch();
  ```
</CodeGroup>

## Configuration Options

### Delay Value

The `value` field specifies how many **seconds** to wait after navigation before showing the popup:

```typescript theme={null}
triggers: {
  type: 'exit',
  value: 3, // Wait 3 seconds on the destination route
}
```

* **Short delay (1-3s)**: Good for high-intent pages where users are actively browsing
* **Medium delay (5-10s)**: Balanced approach for general exit feedback
* **Long delay (15-30s)**: For detailed feedback after users have settled on the new page

<Tip>
  A 3-5 second delay typically works well for most exit popups. It gives users time to orient themselves on the new page without feeling interrupted.
</Tip>

### Route Targeting

Use `segments.path` to specify which routes should trigger the exit popup when users navigate away:

```typescript theme={null}
segments: {
  path: [
    '/pricing',           // Exit from pricing page
    '/features',          // Exit from features page
    '/checkout',          // Exit from checkout
  ]
}
```

Learn more in the [Route Targeting guide](/guides/route-targeting).

## The Exit Popup Queue

### How the Queue Works

The SDK uses **sessionStorage** to persist exit popups across navigation:

1. When a user leaves a matching route, the popup is **queued**
2. The queue stores: popup ID, survey ID, source URL, and due time
3. After the delay expires, the SDK shows the popup
4. Shown popups are removed from the queue

```typescript theme={null}
// Queue structure in sessionStorage
interface DeferredExitPopup {
  id: string;         // Popup definition ID
  surveyId: string;   // Survey to show
  sourceUrl: string;  // URL where exit occurred
  dueAt: number;      // Timestamp when popup should appear
}
```

### Queue Persistence

Exit popups survive page reloads and navigation:

```typescript theme={null}
// User flow:
// 1. Visit /pricing
// 2. Navigate to /home (exit trigger queued)
// 3. Reload page
// 4. Popup still appears after delay ✓
```

<Warning>
  The queue uses `sessionStorage`, so exit popups are cleared when:

  * The browser tab is closed
  * The session ends
  * Storage is manually cleared
</Warning>

## Navigation Detection

Exit triggers work with all navigation methods:

<AccordionGroup>
  <Accordion title="Anchor tag navigation">
    ```html theme={null}
    <a href="/home">Go Home</a>
    <!-- Exit trigger fires when clicking the link -->
    ```
  </Accordion>

  <Accordion title="Hash navigation">
    ```html theme={null}
    <a href="#/dashboard">Dashboard</a>
    <!-- Exit trigger fires for hash route changes -->
    ```
  </Accordion>

  <Accordion title="History API">
    ```typescript theme={null}
    // Exit trigger fires for pushState/replaceState
    history.pushState(null, '', '/new-page');
    history.replaceState(null, '', '/different-page');
    ```
  </Accordion>

  <Accordion title="Framework routing">
    Works with modern frameworks:

    ```typescript theme={null}
    // React Router
    navigate('/new-page');

    // Vue Router
    router.push('/new-page');

    // Next.js
    router.push('/new-page');
    ```
  </Accordion>
</AccordionGroup>

## Complete Example

Here's a real-world example with multiple exit triggers:

```typescript theme={null}
import { DeepdotsPopups } from '@magicfeedback/popup-sdk';

const popupDefinitions = [
  // Pricing page exit
  {
    id: 'popup-pricing-exit',
    title: 'Pricing feedback',
    message: '<p>What made you leave the pricing page?</p>',
    triggers: {
      type: 'exit',
      value: 3,
      condition: [{ answered: false, cooldownDays: 7 }],
    },
    surveyId: 'survey-pricing-exit',
    productId: 'product-main',
    segments: {
      path: ['/pricing'],
    },
    actions: {
      accept: {
        label: 'Tell Us Why',
        surveyId: 'survey-pricing-exit',
      },
    },
  },
  // Product page exit
  {
    id: 'popup-product-exit',
    title: 'Product feedback',
    message: '<p>Did you find what you were looking for?</p>',
    triggers: {
      type: 'exit',
      value: 5,
      condition: [{ answered: false, cooldownDays: 14 }],
    },
    surveyId: 'survey-product-exit',
    productId: 'product-main',
    segments: {
      path: ['/product/*'], // Match all product pages
    },
    actions: {
      accept: {
        label: 'Share Feedback',
        surveyId: 'survey-product-exit',
      },
    },
  },
];

const popups = new DeepdotsPopups();

popups.init({
  mode: 'client',
  debug: true,
  popups: popupDefinitions,
});

// Listen for popup events
popups.on('popup_shown', (event) => {
  console.log('Exit popup shown:', event);
});

popups.autoLaunch();
```

## Exit Popup Behavior

### When Popups Are Shown

An exit popup will show when:

1. ✅ User was on a matching route (defined in `segments.path`)
2. ✅ User navigated to a **different** route
3. ✅ The configured delay has elapsed
4. ✅ Conditions are met (`answered`, `cooldownDays`)
5. ✅ No other popup is currently showing

### When Popups Are Skipped

An exit popup will **not** show when:

* ❌ User is still on the same route
* ❌ Conditions block it (`answered: false` and survey was completed)
* ❌ Cooldown period hasn't elapsed
* ❌ Route doesn't match `segments.path`
* ❌ User closed the tab before delay elapsed

<Note>
  The SDK checks conditions at **render time** (after the delay), not when the exit is queued. This ensures popups respect real-time user state.
</Note>

## Source Code Reference

The exit popup implementation is in `src/core/deepdots-popups.ts`:

* **Queue storage**: Lines 307-444 handle sessionStorage persistence
* **Navigation detection**: Triggers module detects route changes
* **Path matching**: Lines 247-283 evaluate `segments.path`
* **Deferred rendering**: Lines 362-392 manage timers and display logic

## API Reference

### `queueExitPopup(surveyId, delaySeconds, sourceUrl?, popupId?)`

Manually queue an exit popup (typically called by trigger handlers):

```typescript theme={null}
popups.queueExitPopup(
  'survey-exit-001',  // Survey ID
  5,                  // Delay in seconds
  '/pricing',         // Source URL (optional)
  'popup-exit-001'    // Popup ID (optional)
);
```

<Warning>
  You typically don't need to call this directly. The SDK automatically queues exit popups when `autoLaunch()` is enabled and exit triggers are configured.
</Warning>

## Best Practices

<AccordionGroup>
  <Accordion title="Choose appropriate delays">
    Match your delay to the user's context:

    ```typescript theme={null}
    // High-value page (pricing, checkout)
    triggers: { type: 'exit', value: 3 }

    // Content pages
    triggers: { type: 'exit', value: 5 }

    // Post-navigation surveys
    triggers: { type: 'exit', value: 10 }
    ```
  </Accordion>

  <Accordion title="Use meaningful cooldowns">
    Prevent survey fatigue with cooldown periods:

    ```typescript theme={null}
    condition: [
      {
        answered: false,
        cooldownDays: 14 // Don't show again for 2 weeks
      }
    ]
    ```
  </Accordion>

  <Accordion title="Target specific routes">
    Focus on pages where exit feedback is most valuable:

    ```typescript theme={null}
    // Good: Specific high-value pages
    segments: { path: ['/pricing', '/checkout', '/signup'] }

    // Avoid: Too broad
    segments: { path: ['*'] }
    ```
  </Accordion>

  <Accordion title="Test navigation flows">
    Verify exit popups work in your app:

    ```typescript theme={null}
    popups.init({
      mode: 'client',
      debug: true, // See queue and render logs
      popups: definitions,
    });
    ```
  </Accordion>
</AccordionGroup>

## Debugging Exit Popups

Enable debug mode to see exit popup logs:

```typescript theme={null}
popups.init({
  mode: 'client',
  debug: true,
  popups: definitions,
});
```

Logs include:

* When exits are queued
* Queue contents in sessionStorage
* When delays expire
* Why popups are skipped
* When popups are shown

## Next Steps

<CardGroup cols={2}>
  <Card title="Route Targeting" icon="route" href="/guides/route-targeting">
    Learn path matching rules for exit triggers
  </Card>

  <Card title="Event Triggers" icon="bolt" href="/guides/event-triggers">
    Trigger popups from business events
  </Card>

  <Card title="Server Mode" icon="server" href="/guides/server-mode">
    Manage exit popups remotely
  </Card>

  <Card title="Client Mode" icon="code" href="/guides/client-mode">
    Define exit triggers inline
  </Card>
</CardGroup>
