Widget SDK

The Signalpad widget exposes a global window.signalpad object after the script loads. All methods are safe to call before the widget finishes initialising — they queue internally and flush once the widget is ready.

Installation

Embed the script in your HTML. One tag, no bundler required.

html
<script
  src="https://signalpad.app/widget.js"
  data-project="pk_live_YOUR_PROJECT_KEY"
  data-api="https://signalpad.app"
></script>
AttributeTypeDescription
data-projectrequiredstringYour project key. Found in Dashboard → Settings → Widget.
data-apioptionalstringOverride the API base URL. Defaults to https://signalpad.app. Useful for self-hosted instances or local development.

signalpad.identify(userId, attributes?)

Associates the current session with a known user. Call this after your auth flow resolves. Attributes are stored against the user and used by the targeting engine to decide which updates to show.

signalpad.identify(userId: string, attributes?: Record<string, any>): void
ParameterTypeDescription
userIdstringYour internal user ID. Must be stable across sessions.
attributesobjectOptional. Any JSON-serialisable key-value pairs — plan, role, company, created_at, etc. Used for advanced targeting.
javascript
// Basic — user ID only
signalpad.identify("usr_4821");

// With attributes for targeting
signalpad.identify("usr_4821", {
  plan:       "pro",
  role:       "admin",
  company:    "SignalPad",
  created_at: "2024-06-15",
  beta:       true,
});
Important: If you call identify() after track(), previous anonymous events are not retroactively merged. Call identify() as early as possible in your app lifecycle.

signalpad.track(eventName, metadata?)

Records a custom event. This is how Signalpad measures feature adoption — by matching your track() calls against the feature event key set on each update in the dashboard.

signalpad.track(eventName: string, metadata?: Record<string, any>): void
ParameterTypeDescription
eventNamestringThe event key. Must exactly match the feature event key on the update for adoption to register.
metadataobjectOptional. Extra context stored alongside the event. Not used for matching — purely for your records.
javascript
// Track feature usage — must match the dashboard event key exactly
signalpad.track("voice_note_sent");

// With optional metadata
signalpad.track("export_triggered", {
  format:     "csv",
  row_count:  1420,
});

// React example — in an event handler
function handleExport() {
  exportData();
  signalpad.track("dashboard_exported");
}

signalpad.registerElement(key, elementOrRef)

Registers a DOM element under a named key so guided flows can spotlight and anchor tooltips to it. Use this instead of fragile CSS selectors — your elements are referenced by stable logical names regardless of class or ID changes.

signalpad.registerElement(key: string, elementOrRef: HTMLElement | React.RefObject): void
javascript — Vanilla JS
const btn = document.getElementById("record-btn");
signalpad.registerElement("voice-record-btn", btn);
tsx — React
import { useRef, useEffect } from "react";

function RecordButton() {
  const ref = useRef<HTMLButtonElement>(null);

  useEffect(() => {
    // Pass the ref — the SDK reads .current automatically
    signalpad.registerElement("voice-record-btn", ref);
  }, []);

  return <button ref={ref}>Record</button>;
}

The key you register here must match the Element key set on each flow step in the guided flow builder.

signalpad.open() / signalpad.close()

Programmatically open or close the “What’s new” panel. Useful when your own UI triggers the widget — for example, a “Release notes” menu item.

javascript
// Open the panel — same as clicking the badge
signalpad.open();

// Close it
signalpad.close();

// Example: hook into your own nav item
document.getElementById("whats-new-btn")
  .addEventListener("click", () => signalpad.open());
When your widget’s trigger mode is set to on_event in the dashboard, the badge still renders but the panel will only auto-open via signalpad.open(). This gives you full control over when updates are surfaced.

signalpad.startFlow(updateId)

Starts the guided flow attached to a specific update, bypassing the panel UI. Use this to trigger walkthroughs from your own buttons or deep-link into a flow from an email or notification.

signalpad.startFlow(updateId: string): void
javascript
// Start a flow programmatically — updateId is the UUID from the dashboard
signalpad.startFlow("f3a1b2c4-d5e6-7890-abcd-ef1234567890");

Catch-up mode Pro+

Drip-feeding updates one at a time works when users open your app daily. It breaks when someone returns after two weeks — they see one update, dismiss it, and miss the other twelve you shipped while they were gone.

With Catch-up mode enabled, returning users who’ve been away for catch_up_away_days+ days see a summary panel on first open: every update they missed, grouped by type, with a one-click option to either mark everything read or step through them one-by-one (so they can still react and start guided flows).

Enable from Dashboard → Settings → Widget → Catch-up mode. The widget evaluates eligibility on each load against the user’s last_seen_at timestamp — no code changes required after enabling.

How dismissal sticks:Once a user acknowledges a catch-up batch (via either action button or the close icon), it’s recorded inlocalStorage and never re-shown for the same updates — even if they stay away for another two weeks.

Widget configuration

All widget configuration is managed from the dashboard — not in code. The widget reads its config on load from /api/sdk/config?key=YOUR_PROJECT_KEY. Changes in the dashboard take effect on the next page load.

OptionValuesDescription
positionbottom-right · bottom-left · top-right · top-leftWhere the badge anchors on screen.
themelight · dark · autoauto follows the user’s OS preference via prefers-color-scheme.
triggeron_load · on_click · on_eventon_load auto-opens after 1.8 s if there are unread updates. on_click opens on badge tap only. on_event requires signalpad.open().
custom_cssstringInjected as a <style> tag after the widget’s default styles — use to override colours, border-radius, font.
catch_up_enabledPro+booleanWhen true, returning users who’ve been away for catch_up_away_days+ days see a “Here’s what you missed” summary on first open.
catch_up_away_daysPro+numberHow many days of inactivity trigger the catch-up summary. Default: 7.