Appearance
Backend Actions
Extensions run in sandboxed iframes with restricted network access. To communicate with external servers, you define actions in your manifest.json. The platform executes these actions server-side on your behalf, so your extension never makes direct HTTP requests.
Why Actions?
Since extension iframes are isolated by CSP (Content Security Policy), they cannot make arbitrary network requests. Actions solve this by letting you declare HTTP calls in the manifest and trigger them at runtime via v1.ext.actions.call. The platform handles the actual HTTP request server-side and returns the response to your extension.
Review & Approval
All backend actions are reviewed before your extension is published. Declare only the actions your extension strictly needs to function — keep integrations minimal and straightforward. Actions that are not essential to your extension's core functionality, or that do not meet our security and stability requirements, may be rejected. The goal is to ensure every integration is necessary, transparent, and safe for the platform.
Avoid Unconditional Requests in the Background Slot
The EXTENSION_SLOT_BACKGROUND slot loads automatically in a hidden iframe for every viewer as soon as the extension appears on the page. Other slots (EXTENSION_SLOT_MAIN_GAME_FUN, EXTENSION_SLOT_MAIN_SEX_TOY, EXTENSION_SLOT_RIGHT_OVERLAY, EXTENSION_SLOT_MOVEABLE_OVERLAY) are only mounted after an explicit user interaction, so their traffic is naturally limited.
Never call backend actions unconditionally from the EXTENSION_SLOT_BACKGROUND slot. On a popular stream, thousands of viewers can have your extension loaded simultaneously. If the background slot fires a request on initialization without any condition, your server will receive a request from every single one of them at the same time — which can bring your backend down.
Always trigger actions in response to:
- A user interaction (button click, tip, token spend, etc.)
- A specific event with a meaningful state change
Never trigger actions unconditionally:
- On page load or
createExtHelper()initialization in theEXTENSION_SLOT_BACKGROUNDslot - On every context update or re-render
Failure to follow this rule may cause your backend to become unavailable due to the volume of traffic originating from the Stripchat platform.
Action Types
| Type | Purpose |
|---|---|
externalCall | Make an HTTP request to an external URL. |
delayedEvent | Poll and execute another action after a delay. |
Defining Actions in Manifest
Actions are declared in the root actions array of manifest.json. Each action has the following fields:
| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Unique action name, used as actionName when calling from SDK. |
type | string | Yes | One of externalCall or delayedEvent. |
config | object | Yes | Configuration specific to the action type. |
params | object | No | Input parameter definitions. |
available_for_guests | boolean | No | Allows guests to call this action. Defaults to false — actions are not accessible to guests unless explicitly enabled. |
externalCall
Makes an HTTP request to an external URL. This is the most common action type.
Config
| Field | Type | Required | Description |
|---|---|---|---|
action | string | Yes | HTTP URL to call. Must start with https://. |
method | string | Yes | HTTP method: GET, POST, PUT, DELETE, or PATCH. |
headers | object | No | HTTP headers as key-value pairs. Values support {{paramName}} placeholders. |
body | object | No | Static key-value map merged into the request body (for POST, PUT, PATCH). Config body keys override payload keys when both are present. Values must be static — no placeholders. |
Placeholder Templating
URLs and header values support placeholders in {{paramName}} format. At runtime, the platform replaces them with values from params passed to v1.ext.actions.call.
paramNamemust match[\w\d]+.- Values substituted into URLs must match
[\w\d_-]+.
Example
json
{
"name": "stopDevice",
"type": "externalCall",
"config": {
"action": "https://api.example.com/devices/{{deviceId}}/stop",
"method": "PUT",
"headers": {
"Authorization": "Bearer {{token}}"
}
},
"params": {
"deviceId": "string",
"token": "string"
}
}Calling from SDK:
ts
const result = await ext.makeRequest('v1.ext.actions.call', {
actionName: 'stopDevice',
params: {
deviceId: 'dev_456',
token: 'tok_abc',
},
});The platform sends the following HTTP request:
http
PUT https://api.example.com/devices/dev_456/stop
Authorization: Bearer tok_abcRequest Body
For POST, PUT, and PATCH methods, the platform sends all params as a JSON body:
ts
await ext.makeRequest('v1.ext.actions.call', {
actionName: 'createSession',
params: {
name: 'my-session',
mode: 'interactive',
},
});Resulting HTTP request:
http
POST https://api.example.com/sessions
Content-Type: application/json
{
"name": "my-session",
"mode": "interactive"
}For GET and DELETE, the body is not sent.
Response
v1.ext.actions.call returns an object with:
| Field | Type | Description |
|---|---|---|
code | number | HTTP status code from the external server. |
body | unknown | Parsed response body. |
delayedEvent
A polling-based action. When called, the platform starts polling and once the polling period of delay_ms elapses, it executes the action specified in config.action. Useful for deferred cleanup, follow-up requests, or timed logic that should run even if the user leaves the page.
Config
| Field | Type | Required | Description |
|---|---|---|---|
action | string | Yes | Name of the target action to trigger. |
delay_ms | number | Yes | Delay in milliseconds. |
Example
json
{
"name": "delayedCloseSession",
"type": "delayedEvent",
"config": {
"action": "closeSession",
"delay_ms": 30000
},
"params": {
"sessionId": "string",
"token": "string"
}
}When called, the platform starts polling. After 30 seconds, it executes the closeSession action with the provided params.
params Schema
The params object defines input parameters for an action. Each key is a parameter name. Parameter names must match [\w\d]+ and can be used as {{paramName}} placeholders in URLs and header values.
The value can be either a type string (shorthand) or an object with type (required) and description (optional):
json
{
"params": {
"deviceId": "string",
"userId": "number"
}
}Allowed types: string, number, integer, boolean, array, object.
Full Example
A manifest combining externalCall and delayedEvent actions to manage device sessions through an external API:
json
{
"actions": [
{
"name": "authenticate",
"type": "externalCall",
"config": {
"action": "https://api.example.com/auth/token",
"method": "GET",
"headers": {
"X-Api-Key": "your-api-key"
}
}
},
{
"name": "stopDevice",
"type": "externalCall",
"config": {
"action": "https://api.example.com/devices/{{deviceId}}/stop",
"method": "PUT",
"headers": {
"Authorization": "Bearer {{token}}"
}
},
"params": {
"deviceId": "string",
"token": "string"
}
},
{
"name": "createSession",
"type": "externalCall",
"config": {
"action": "https://api.example.com/sessions",
"method": "POST",
"headers": {
"X-Api-Key": "your-api-key"
}
}
},
{
"name": "closeSession",
"type": "externalCall",
"config": {
"action": "https://api.example.com/sessions/{{sessionId}}/close",
"method": "PUT",
"headers": {
"Authorization": "Bearer {{token}}"
}
},
"params": {
"sessionId": "string",
"token": "string"
}
},
{
"name": "delayedCloseSession",
"type": "delayedEvent",
"config": {
"action": "closeSession",
"delay_ms": 30000
},
"params": {
"sessionId": "string",
"token": "string"
}
},
{
"name": "delayedStopDevice",
"type": "delayedEvent",
"config": {
"action": "stopDevice",
"delay_ms": 30000
},
"params": {
"deviceId": "string",
"token": "string"
}
}
]
}This manifest demonstrates:
externalCallactions to interact with an external API (authentication, device control, session management).- Placeholder templating in URLs (
{{sessionId}}) and headers ({{token}}). delayedEventactions for deferred cleanup — closing a session and stopping a device after 30 seconds.