Appearance
Backend
Need server-side logic — calling an external API, keeping a secret, or producing a trusted result? Use extension actions. They run outside the iframe with your secrets injected at build time, so you get server-side behavior through the platform. In the snippets, ext is your createExtHelper() instance.
Prefer Storage over your own backend
We don't generally recommend relying on your own backend. Stripchat drives large volumes of traffic — a popular room can fan out an action to every viewer at once — and your infrastructure must be able to absorb those bursts without falling over. If it can't keep up, your extension breaks for everyone.
Reach for actions only when you truly need server-side behavior (third-party APIs, secrets, trusted randomness). For plain state and counters, use Storage instead — it scales on the platform with no backend to run.
Do server-side work with extension actions
Declare actions in the manifest and call them with v1.ext.actions.call. Common action types:
externalCall— make an HTTP request to a third-party API.rand— get a trusted random result.delayedEvent— schedule work to run later.
See Backend Actions for the full list and configuration.
Call an external API with a secret
Direct HTTP from the iframe is blocked — go through a declared externalCall action. The secret is injected at build time, never hardcoded. Preserve anonymity: when isAnonymous, do not pass user identity into params.
json
"actions": [{
"name": "controlDevice",
"type": "externalCall",
"config": {
"action": "https://api.example.com/devices/{{deviceId}}/control",
"method": "PUT",
"headers": { "X-Api-Key": "EXT__DEVICE_API_KEY__EXT" }
},
"params": { "deviceId": "string" }
}]ts
// only on a user action — NEVER unconditionally from the background slot
const { code } = await ext.makeRequest('v1.ext.actions.call', {
actionName: 'controlDevice',
params: { deviceId, ...(isAnonymous ? {} : { userId: String(user.id) }) },
});
if (code !== 200) {
await ext.makeRequest('v1.monitoring.report.error', { message: 'controlDevice failed', data: { code } });
}Provably-fair randomness via a backend action
A client Math.random() is untrusted — get the number from a rand action, with a fallback.
json
"actions": [{ "name": "getRandomNumber", "type": "rand" }]ts
async function yourPickWinner(items) {
let idx;
try {
const { body } = await ext.makeRequest('v1.ext.actions.call', {
actionName: 'getRandomNumber',
params: {},
});
idx = body.value;
} catch {
idx = Math.floor(Math.random() * items.length); // fallback
}
return items[idx];
}Recommendations: never trigger actions unconditionally from the background slot
DANGER
The background slot runs for every viewer at once. Never trigger a backend action unconditionally from it — call actions only in response to a user action. See Backend Actions.