Skip to main content
Client mode allows you to define popups inline without making API calls. This is ideal for local demos, QA environments, integration testing, and hardcoded fallback flows.

When to Use Client Mode

Use client mode when:
  • Running local demos without API access
  • Testing popup behavior in QA environments
  • Building integration tests that shouldn’t depend on external APIs
  • Creating hardcoded fallback flows
  • Validating trigger logic before deploying to production
For production integrations, use server mode instead. Server mode allows you to manage popup definitions remotely without code changes.

Basic Setup

1

Install the SDK

npm install @magicfeedback/popup-sdk
2

Define your popups

Create an array of popup definitions:
const popupDefinitions = [
  {
    id: 'popup-home-5s',
    title: 'Help us improve',
    message: '<p>Thanks for visiting our homepage.</p>',
    triggers: {
      type: 'time_on_page',
      value: 5,
      condition: [{ answered: false, cooldownDays: 7 }],
    },
    actions: {
      accept: {
        label: 'Open survey',
        surveyId: 'survey-home-001',
      },
    },
    surveyId: 'survey-home-001',
    productId: 'product-main',
    segments: {
      path: ['/', '/pricing', '/#/home'],
    },
  },
];
3

Initialize in client mode

Pass your popup definitions to the SDK:
import { DeepdotsPopups } from '@magicfeedback/popup-sdk';

const popups = new DeepdotsPopups();

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

popups.autoLaunch();
Each popup definition must include these fields:
interface PopupDefinition {
  id: string;                    // Unique identifier for this popup
  title: string;                 // Popup title
  message: string;               // HTML message content
  triggers: TriggerConfig;       // When to show this popup
  surveyId: string;              // Survey to display
  productId: string;             // Product identifier
  actions?: ActionConfig;        // Button labels and behavior
  segments?: SegmentConfig;      // Targeting rules
  style?: StyleConfig;           // Visual customization
}

Trigger Configuration

The triggers field determines when your popup appears:
{
  triggers: {
    type: 'time_on_page',
    value: 5, // seconds
    condition: [{ answered: false, cooldownDays: 7 }]
  }
}
Important:
  • The property name is triggers (plural), not trigger
  • time_on_page values are defined in seconds, not milliseconds
  • The SDK converts seconds to milliseconds internally

Condition Configuration

Conditions control when popups can be shown:
condition: [
  {
    answered: false,      // Only show if survey not answered
    cooldownDays: 7       // Wait 7 days between shows
  }
]
  • answered: Set to false to only show popups for unanswered surveys
  • cooldownDays: Minimum days between popup displays

Segment Targeting

Use segments.path to target specific routes:
segments: {
  path: [
    '/',                          // Homepage
    '/pricing',                   // Pricing page
    '/#/home',                    // Hash route
    'https://example.com/about'   // Full URL
  ]
}
Learn more in the Route Targeting guide.

Complete Example

Here’s a complete client mode setup with multiple popup types:
import { DeepdotsPopups } from '@magicfeedback/popup-sdk';

const popupDefinitions = [
  // Time-based popup
  {
    id: 'popup-home-5s',
    title: 'Welcome!',
    message: '<p>How are you enjoying our site?</p>',
    triggers: {
      type: 'time_on_page',
      value: 5,
      condition: [{ answered: false, cooldownDays: 7 }],
    },
    actions: {
      accept: {
        label: 'Give Feedback',
        surveyId: 'survey-home-001',
      },
    },
    surveyId: 'survey-home-001',
    productId: 'product-main',
    segments: {
      path: ['/'],
    },
  },
  // Scroll-based popup
  {
    id: 'popup-scroll-50',
    title: 'Finding what you need?',
    message: '<p>Let us know how we can help.</p>',
    triggers: {
      type: 'scroll',
      value: 50,
      condition: [{ answered: false, cooldownDays: 14 }],
    },
    actions: {
      accept: {
        label: 'Take Survey',
        surveyId: 'survey-scroll-001',
      },
    },
    surveyId: 'survey-scroll-001',
    productId: 'product-main',
    segments: {
      path: ['/pricing', '/features'],
    },
  },
  // Event-based popup
  {
    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',
      condition: [{ answered: false, cooldownDays: 3 }],
    },
    actions: {
      accept: {
        label: 'Share Feedback',
        surveyId: 'survey-search-001',
      },
    },
    surveyId: 'survey-search-001',
    productId: 'product-main',
  },
];

const popups = new DeepdotsPopups();

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

popups.autoLaunch();

Styling Popups

Customize popup appearance with the optional style field:
style: {
  theme: 'dark',           // 'light' or 'dark'
  position: 'bottom-right', // 'bottom-right', 'bottom-left', 'top-right', 'top-left', 'center'
  imageUrl: 'https://example.com/image.png' // Optional header image
}
The current browser renderer focuses on the embedded MagicFeedback form and does not render title, message, or style fields as standalone popup controls. These fields are part of the definition contract for future renderer implementations.

Action Configuration

Define button labels and behavior:
actions: {
  accept: {
    label: 'Open survey',
    surveyId: 'survey-home-001',
  },
  start: {
    label: 'Start Survey',
  },
  back: {
    label: 'Go Back',
  },
  complete: {
    label: 'Submit',
    surveyId: 'survey-home-001',
    autoCompleteParams: { source: 'homepage' },
    cooldownDays: 30,
  },
  decline: {
    label: 'No Thanks',
    cooldownDays: 14,
  }
}
The decline action is accepted in the definition shape, but the current browser renderer does not render a dedicated decline button or enforce decline.cooldownDays.

Testing Locally

To test client mode popups locally:
  1. Create an HTML file with your SDK setup
  2. Use a local HTTP server (file:// URLs may not work correctly)
  3. Enable debug mode to see trigger logs
# Serve your files locally
python3 -m http.server 8000

# Open in browser
open http://localhost:8000

Next Steps

Event Triggers

Trigger popups from business events

Exit Popups

Show popups after route navigation

Route Targeting

Target popups to specific pages

Server Mode

Switch to remote popup management

Build docs developers (and LLMs) love