Skip to main content
Popup definitions describe the structure, behavior, and appearance of feedback popups in the MagicFeedback Popup SDK.

PopupDefinition Interface

The complete TypeScript interface for popup definitions:
interface PopupDefinition {
  id: string;
  title: string;
  message: string;
  triggers: PopupTrigger;
  actions?: PopupActions;
  surveyId: string;
  productId: string;
  style?: PopupStyle;
  segments?: PopupSegments;
}

Required Fields

id

Type: string Unique identifier for the popup definition. Used for tracking, deduplication, and manual triggering.
{
  id: 'popup-home-5s',
  // ... other fields
}
When multiple popups share the same surveyId, use the id field to distinguish between them. Use showByPopupId() to show a specific popup by its ID.

title

Type: string The title of the popup.
{
  title: 'Help us improve',
  // ... other fields
}
Note: The current browser renderer focuses on embedded MagicFeedback forms and does not render the title field as standalone UI. This field is part of the contract for future renderers.

message

Type: string (HTML) The message content of the popup. Supports HTML.
{
  message: '<p>Thanks for visiting our homepage. <strong>We value your feedback!</strong></p>',
  // ... other fields
}
Like title, the message field is not currently rendered as standalone UI by the default browser renderer. It’s part of the definition contract for custom renderers.

surveyId

Type: string The ID of the MagicFeedback survey to display.
{
  surveyId: 'survey-home-001',
  // ... other fields
}
This ID is used to:
  • Load the survey form from MagicFeedback
  • Track survey completion
  • Apply trigger conditions based on survey answered state

productId

Type: string The product ID associated with this popup.
{
  productId: 'product-main',
  // ... other fields
}

triggers

Type: PopupTrigger Defines when and how the popup should be triggered.
interface PopupTrigger {
  type: 'time_on_page' | 'scroll' | 'exit' | 'click' | 'event';
  value: number | string;
  condition?: PopupTriggerCondition[];
}
Example:
{
  triggers: {
    type: 'time_on_page',
    value: 5, // seconds
    condition: [
      { answered: false, cooldownDays: 7 }
    ]
  },
  // ... other fields
}
See the Triggers page for detailed documentation on all trigger types.

Optional Fields

actions

Type: PopupActions Defines the action buttons and their behavior.
interface PopupActions {
  accept?: PopupActionAccept;
  decline?: PopupActionDecline;
  complete?: PopupActionComplete;
  start?: PopupActionStart;
  back?: PopupActionDecline;
}
Opens the survey when clicked.
actions: {
  accept: {
    label: 'Take Survey',
    surveyId: 'survey-home-001'
  }
}
Fields:
  • label (string): Button text
  • surveyId (string): Survey to open

style

Type: PopupStyle Customizes the appearance of the popup.
interface PopupStyle {
  theme: 'light' | 'dark';
  position: 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left' | 'center';
  imageUrl: string | null;
}
Example:
{
  style: {
    theme: 'dark',
    position: 'bottom-right',
    imageUrl: 'https://example.com/banner.png'
  },
  // ... other fields
}
The current browser renderer does not fully implement all style options. These fields are part of the contract for future renderers and custom implementations.

segments

Type: PopupSegments Defines targeting rules for when the popup should be shown.
interface PopupSegments {
  path?: string[];
  lang?: string[];
  [key: string]: unknown;
}
Example:
{
  segments: {
    path: [
      '/pricing',
      '/docs',
      '/#/home'
    ],
    lang: ['en', 'es']
  },
  // ... other fields
}
segments.path is currently the only segment field evaluated by the SDK. Other fields like lang are accepted but not yet implemented.
Path Matching:
  • Full URLs: https://example.com/pricing
  • Path fragments: /pricing
  • Hash routes: /#/home
  • If path is empty or not provided, popup can trigger on any route

Complete Examples

{
  id: 'popup-home-welcome',
  title: 'Welcome!',
  message: '<p>Thanks for visiting our site.</p>',
  triggers: {
    type: 'time_on_page',
    value: 10,
    condition: [
      { answered: false, cooldownDays: 30 }
    ]
  },
  actions: {
    accept: {
      label: 'Share Feedback',
      surveyId: 'survey-welcome-001'
    }
  },
  surveyId: 'survey-welcome-001',
  productId: 'product-main',
  style: {
    theme: 'light',
    position: 'bottom-right',
    imageUrl: null
  },
  segments: {
    path: ['/', '/home']
  }
}

Trigger Conditions Reference

Conditions are evaluated before showing a popup:
interface PopupTriggerCondition {
  answered: boolean;
  cooldownDays: number;
}

answered

When set to false, the popup will not show if the user has already completed the survey.
triggers: {
  type: 'time_on_page',
  value: 5,
  condition: [
    { answered: false, cooldownDays: 0 }
  ]
}
The SDK tracks answered surveys using:
  • Automatic tracking when survey_completed event is emitted
  • Manual tracking via popups.markSurveyAnswered(surveyId)

cooldownDays

Minimum number of days that must pass before showing the popup again to the same user.
triggers: {
  type: 'time_on_page',
  value: 5,
  condition: [
    { answered: false, cooldownDays: 30 }
  ]
}
How It Works:
  • SDK records the timestamp when a popup is shown
  • Before showing again, SDK checks if cooldownDays have passed
  • Cooldown is tracked per popup id, not per survey
You can provide multiple conditions, and all must pass for the popup to show:
triggers: {
  type: 'time_on_page',
  value: 5,
  condition: [
    { answered: false, cooldownDays: 7 },
    { answered: true, cooldownDays: 90 }
  ]
}
This configuration means:
  • If user hasn’t answered: wait 7 days between shows
  • If user has answered: wait 90 days between shows

Validation

The SDK validates popup definitions and logs warnings for invalid structures:
// Valid popup definition
const valid = {
  id: 'popup-1',
  title: 'Title',
  message: 'Message',
  triggers: { type: 'time_on_page', value: 5 },
  surveyId: 'survey-1',
  productId: 'product-1'
};

// Invalid - missing required fields
const invalid = {
  id: 'popup-2',
  // Missing title, message, triggers, surveyId, productId
};
Enable debug mode to see validation warnings:
popups.init({
  mode: 'client',
  debug: true, // Shows validation warnings
  popups: [valid, invalid]
});

Best Practices

Make popup IDs descriptive and follow a naming convention:
// Good
id: 'popup-pricing-exit-3s'
id: 'popup-home-welcome-time'
id: 'popup-docs-scroll-50'

// Avoid
id: 'popup1'
id: 'test'
id: 'xyz123'
Balance feedback collection with user experience:
  • High-priority feedback: 7-14 days
  • General feedback: 30-60 days
  • Low-priority surveys: 90+ days
condition: [
  { answered: false, cooldownDays: 30 }
]
Use segments.path to show relevant popups on specific pages:
// Pricing feedback only on pricing page
segments: {
  path: ['/pricing']
}

// Documentation feedback on all docs pages
segments: {
  path: ['/docs', '/docs/*']
}
Before deploying to production, test popup definitions locally:
popups.init({
  mode: 'client',
  debug: true,
  popups: [
    // Your popup definitions
  ]
});
This allows you to:
  • Validate definition structure
  • Test trigger behavior
  • Verify UI rendering
  • Debug conditions and segments

Build docs developers (and LLMs) love