JavaScript SDK

Everything the widget does is scriptable through window.Janus: open popups from your own buttons, jump steps, read and write flow variables, and listen for signups.

Methods

CallWhat it does
Janus.open(campaignId, opts?)Opens a campaign. If it's already armed on the page it opens instantly; otherwise the widget fetches it first. Options: { ignoreTargeting: true } to bypass audience rules (previews), { openStep: idOrIndex } to land on a specific step. A popup that's already open won't be interrupted.
Janus.close()Closes the active popup.
Janus.step(idOrIndex)Jumps the open popup to a step by id or index.
Janus.refresh()Re-evaluates which campaign matches (fresh cart, new URL, changed state) and re-arms triggers. Nothing pops instantly.
Janus.vars.get(key) / Janus.vars.set(key, value)Read/write session-scoped flow variables, the same store text variables and the Set variable(s) action use.

Calling before the widget loads

The SDK absorbs a pre-init queue, so you never need to worry about script order:

window.Janus = window.Janus || [];
window.Janus.push({ type: 'open', campaignId: 42 });

The manual trigger

Give a campaign the Manual (SDK) trigger and it never auto-fires; it waits for your call. Perfect for "Get 10% off" buttons in your nav, mid-article links, or app-driven moments:

document.querySelector('#offer-button')
  .addEventListener('click', () => Janus.open(42));

Events

A successful signup dispatches a DOM event on window:

window.addEventListener('popupstudio:signup', (e) => {
  // fire pixels, open a chat, update UI…
});

For server-side needs, prefer the Klaviyo Popup Reward Issued event or the on-signup code hook, which receives the subscriber's details.

Embedded form mode

Render a campaign inline, no overlay and no trigger, by placing its container anywhere in your page:

<div id="ps_campaign_42"></div>

The widget mounts the campaign into the div on load. Embedded instances don't show teaser buttons and ignore frequency logic; they're part of the page. Grab the exact snippet from the builder under How it appears → Inside the page.

Preview URL parameters

ParameterEffect
?ps_preview=IDLoad campaign ID for this visit only, regardless of status: the admin preview link.
?embed=IDOn the demo sandbox: mount campaign ID inline for embed testing.

What the widget stores

Visitor state lives in first-party localStorage keys prefixed ps_: session id, first-seen time, page/session counters, dismissals, conversion flag, variant assignment, teaser state and the claimed-code record. No third-party cookies, nothing cross-site. Clearing them resets the visitor, useful when testing:

Object.keys(localStorage)
  .filter(k => k.startsWith('ps_'))
  .forEach(k => localStorage.removeItem(k));
Also good to knowThe widget is dependency-free, ships ~57 KB gzipped, loads async, and exposes the logged-in customer's order count via the embed as window.JanusCustomer; see installation.