npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@magicfeedback/popup-sdk

v1.1.0

Published

TypeScript SDK to render and manage survey popups for MagicFeedback

Downloads

296

Readme

Deepdots Popup SDK

TypeScript SDK for loading and displaying Deepdots surveys as popups in browser apps.

Package name: @magicfeedback/popup-sdk

What It Does

  • Loads popup definitions from the Deepdots API (server mode) or from inline definitions (client mode)
  • Triggers popups by time on page, scroll depth, click, route exit, or host-driven events
  • Emits lifecycle events so the host app can track popup activity
  • Supports route targeting through segments.path
  • Falls back to a no-op renderer outside the browser

Installation

npm install @magicfeedback/popup-sdk

Recommended Setup

server mode is the recommended setup for real client integrations. Popup definitions are managed remotely and the SDK fetches them at runtime.

import { DeepdotsPopups } from '@magicfeedback/popup-sdk';

const popups = new DeepdotsPopups();

popups.init({
  mode: 'server',
  nodeEnv: 'production',
  apiKey: 'YOUR_PUBLIC_API_KEY',
  userId: 'customer-123',
  debug: false,
});

popups.on('popup_shown', (event) => {
  console.log('Popup shown', event);
});

popups.on('survey_completed', (event) => {
  console.log('Survey completed', event);
});

popups.autoLaunch();

Notes:

  • mode: 'server' fetches popup definitions from Deepdots.
  • nodeEnv: 'production' uses https://api.deepdots.com.
  • nodeEnv: 'development' uses https://api-dev.deepdots.com.
  • userId is optional, but recommended when popups are targeted per user.
  • autoLaunch() can be called immediately after init(). In server mode, the SDK waits until remote popups are loaded.

When To Use Each Mode

  • server: production integrations where popup definitions are managed remotely.
  • client: local demos, QA, hardcoded fallback flows, and integration testing without API calls.

Real Use Cases From examples/

1. Remote website integration

Files:

  • examples/index.html
  • examples/product.html
  • examples/demo-sdk.js

This flow initializes the SDK in server mode, auto-launches popups on page load, and logs popup events in the page UI. It is the closest example to a standard website integration.

2. Host-driven business event trigger

Files:

  • examples/clients/casino/sdk.js
  • examples/clients/casino/sdk-trigger-event-example.js

This flow tracks search behavior in the host app and calls:

sdk.triggerEvent('search');

Use this pattern when popup logic depends on product behavior instead of plain DOM triggers. In the casino demo, the popup is shown after repeated searches with low intent signals.

3. Route-exit popup after navigation

Files:

  • examples/index.html
  • examples/product.html

Exit triggers are queued when the user leaves a matching route and rendered on the next route after the configured delay. This is useful for "before you go" feedback flows that should appear after navigation, not before it.

4. Inline client-mode sandbox

File:

  • examples/demo.html

This example uses local popup definitions and is useful for validating trigger behavior without hitting the API.

Client Mode Example

Use client mode when you want to preload popup definitions yourself.

import { DeepdotsPopups } from '@magicfeedback/popup-sdk';

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 },
    ],
    cooldown: [
      { answered: 'SHOWED', cooldownDays: 7 },
      { answered: 'COMPLETED', cooldownDays: 30 },
    ],
    actions: {
      accept: {
        label: 'Open survey',
        surveyId: 'survey-home-001',
      },
    },
    surveyId: 'survey-home-001',
    productId: 'product-main',
    segments: {
      path: ['/', '/pricing', '/#/home'],
    },
  },
];

const popups = new DeepdotsPopups();

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

popups.autoLaunch();

Important:

  • The property name is triggers, and it is now an array.
  • time_on_page values are defined in seconds.
  • segments.path can contain full URLs, path fragments such as /pricing, or hash routes such as /#/home.

API Essentials

init(config)

Initializes the SDK.

popups.init({
  mode: 'server',
  apiKey: 'YOUR_PUBLIC_API_KEY',
  userId: 'customer-123',
  nodeEnv: 'production',
  debug: false,
});

Config fields:

  • apiKey?: string
  • userId?: string
  • nodeEnv?: 'development' | 'production'
  • mode?: 'server' | 'client'
  • debug?: boolean
  • popups?: PopupDefinition[]

autoLaunch()

Starts the triggers derived from the popup definitions loaded during init().

popups.autoLaunch();

triggerEvent(eventName)

Shows the first eligible popup whose definition contains:

triggers: [{ type: 'event', value: eventName }]

Example:

popups.triggerEvent('search');

show({ surveyId, productId })

Shows a popup immediately without waiting for a trigger.

popups.show({
  surveyId: 'survey-home-001',
  productId: 'product-main',
});

showByPopupId(popupId)

Shows a popup definition by id. This is useful when multiple popups reuse the same surveyId.

popups.showByPopupId('popup-home-5s');

markSurveyAnswered(surveyId)

Marks a survey as answered so cooldown rules like { answered: 'COMPLETED', cooldownDays: 30 } start applying.

popups.markSurveyAnswered('survey-home-001');

on(eventType, listener) / off(eventType, listener)

Subscribe or unsubscribe from SDK events.

const onShown = (event) => console.log(event);

popups.on('popup_shown', onShown);
popups.off('popup_shown', onShown);

Supported Trigger Types

Popup definitions use these trigger types:

  • time_on_page: shows after N seconds on the page
  • scroll: shows after reaching a scroll percentage
  • click: shows after clicking the element with the given DOM id
  • exit: shows after leaving a matching route and waiting N seconds on the destination route
  • event: shows when the host app calls triggerEvent(name)

Popup Definition Shape

client mode accepts popup definitions with this structure:

interface PopupDefinition {
  id: string;
  title: string;
  message: string;
  triggers: Array<{
    type: 'time_on_page' | 'scroll' | 'exit' | 'click' | 'event';
    value: number | string;
  }>;
  cooldown?: Array<{
    answered: 'SHOWED' | 'PARTIAL' | 'COMPLETED';
    cooldownDays: number;
  }>;
  actions?: {
    accept?: {
      label: string;
      surveyId: string;
    };
    start?: {
      label: string;
    };
    back?: {
      label: string;
    };
    complete?: {
      label: string;
      surveyId: string;
      autoCompleteParams: Record<string, unknown>;
      cooldownDays?: number;
    };
    decline?: {
      label: string;
      cooldownDays?: number;
    };
  };
  surveyId: string;
  productId: string;
  style?: {
    theme: 'light' | 'dark';
    position: 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left' | 'center';
    imageUrl: string | null;
  };
  segments?: {
    path?: string[];
    [key: string]: unknown;
  };
}

Events

The SDK emits:

  • popup_shown
  • popup_clicked
  • survey_completed

Payload:

interface DeepdotsEvent {
  type: 'popup_shown' | 'popup_clicked' | 'survey_completed';
  surveyId: string;
  timestamp: number;
  data?: Record<string, unknown>;
}

data often contains values such as:

  • popupId
  • action
  • userId

popup_clicked is a general interaction event. Depending on the flow, data.action can contain values such as loaded, start_survey, manual_send, back, complete, or close_icon.

Important Behavior Notes

  • segments.path is the only segment currently evaluated by the SDK runtime.
  • exit triggers work across anchor navigation, hash navigation, history.pushState(), and history.replaceState().
  • Pending exit popups are stored in sessionStorage until they are shown or discarded.
  • The default browser renderer uses Deepdots forms and applies button labels from actions.accept, actions.start, actions.back, and actions.complete.
  • title, message, and style belong to the popup definition contract, but the current browser renderer focuses on the embedded form and does not render those fields as standalone popup copy/layout controls.
  • actions.decline is accepted in the definition shape, but the current browser renderer does not render a dedicated decline button or enforce decline.cooldownDays.
  • In browser mode, the SDK creates #deepdots-popup-container and injects the shared popup stylesheet from jsDelivr.

Running The Examples Locally

npm install
npm run build
python3 -m http.server 4173

Then open:

  • http://localhost:4173/examples/index.html
  • http://localhost:4173/examples/product.html
  • http://localhost:4173/examples/demo.html
  • http://localhost:4173/examples/clients/casino/index.html

Using a local HTTP server is recommended. Some browser module imports and navigation flows do not behave correctly when opening the files directly with file://.

Development

npm run build
npm run build:watch
npm run lint
npm test

License

MIT