Skip to content

How do Extensions Work?

This page explains the architecture behind extensions — how they load, render, communicate, and interact with the platform.

Architecture Overview

An extension is a collection of static HTML pages that run inside sandboxed iframes on Stripchat. Each iframe is isolated from the host page and from other extensions. The platform manages the full lifecycle — loading, rendering, resizing, and unloading iframes as users navigate the site.

Extension Lifecycle

1. Upload

You build your extension and upload a ZIP archive containing a manifest, a resolver script, HTML pages, and assets. The platform validates the archive and stores it.

2. Slot Resolution

When a user visits a model's page where your extension is active, the platform determines which slots to render. For each slot, it calls your resolver script with the slot type, context, and settings. The resolver returns a page key — or null to skip rendering.

3. Iframe Loading

For each resolved slot, the platform creates a sandboxed iframe and loads the corresponding HTML page. Your page initializes the SDK via createExtHelper(), which:

  • Establishes a PostMessage transport to talk to the platform runtime.
  • Applies the current theme (dark or light).

4. Runtime Communication

Once loaded, your extension communicates with the platform through two mechanisms:

  • Requests (makeRequest) — typed RPC calls for reading context, saving settings, sending chat messages, spending tokens, calling backend actions, etc.
  • Events (subscribe) — real-time notifications about context changes, whisper messages, payment confirmations, and settings save requests.

5. Unmounting

Visual slots (everything except EXTENSION_SLOT_BACKGROUND) can be unmounted at any time — for example, when a viewer closes the Send Tip panel or collapses an overlay. The EXTENSION_SLOT_BACKGROUND slot persists as long as the extension is active on the page.

Communication Model

Extensions have three communication channels:

Platform ↔ Extension (Requests & Events)

Every iframe communicates with the platform via PostMessage-based RPC. You send requests and receive events through the SDK:

ts
// Request: activity request
const res = await ext.makeRequest('v1.ext.activity.request', {
  durationMs: 60000,
});

// Event: tokens spend
ext.subscribe('v1.payment.tokens.spend.succeeded', (data) => { });

Slot ↔ Slot (Local Whisper)

Iframes of the same extension within one browser tab can exchange messages using local whisper. Messages stay client-side and are not sent to the server:

ts
// Send from EXTENSION_SLOT_BACKGROUND slot
await ext.makeRequest('v1.ext.whisper.local', {
  data: { type: 'STATE_UPDATE', score: 42 },
});

// Receive in EXTENSION_SLOT_RIGHT_OVERLAY slot
ext.subscribe('v1.ext.whispered', (data) => { });

Broadcast (Global Whisper)

To send a message to all clients (all viewers + model) who have the extension loaded, use broadcast whisper. The message goes through the server:

ts
await ext.makeRequest('v1.ext.whisper', {
  data: { type: 'GAME_EVENT', round: 3 },
});

Sandboxing & Security

Extensions are fully isolated:

  • No parent DOM access — you cannot read or modify the Stripchat page.
  • No cookie access — host cookies are not available.
  • CSP restrictions — external domains must be whitelisted during upload.
  • No direct HTTP — network calls to external servers go through Backend Actions, which are executed server-side by the platform.

Settings

Models configure extensions through a settings page — an HTML form rendered inside a platform-managed modal. Settings are saved via the SDK and available to all slots and the resolver script at runtime.

Backend Actions

Since iframes cannot make arbitrary network requests, the platform provides Backend Actions — HTTP calls declared in the manifest and executed server-side. Your extension triggers them via v1.ext.actions.call and receives the response.

Putting It All Together

A typical extension flow:

  1. Model installs the extension and configures settings.
  2. Viewer opens the model's page → the platform calls the resolver for each slot.
  3. Resolved HTML pages load in iframes → each calls createExtHelper().
  4. The EXTENSION_SLOT_BACKGROUND slot initializes state and subscribes to events.
  5. Visual slots render UI based on context and settings.
  6. User interactions trigger requests (tips, actions, whispers).
  7. The EXTENSION_SLOT_BACKGROUND slot coordinates via local whisper, visual slots update.
  8. Broadcast whisper synchronizes state across all connected clients.