Appearance
Class: DynamicTriggerService
Service for managing dynamic triggers: triggers created on the fly by an app (chat command, keyword, regex, dashboard button, channel-points reward, interval, bits…) that run an app-side callback when a viewer activates them.
Remarks
Accessible everywhere via k.dynamicTriggers. You never have to instantiate this service yourself — it is created by the SDK when the app/widget starts.
Each created trigger is represented by a DynamicTrigger that carries its configuration and its onTrigger callback. When a trigger that requires validation is fired, you confirm or reject the activation via `resolveRequest` / `rejectRequest`.
Example
ts
// Create a !boom chat command that reacts when a viewer types it
await k.dynamicTriggers.create({
type: 'CHATCMD',
title: 'Boom',
keyword: 'boom',
onTrigger: async (trigger, request, resolve) => {
await k.chat.say('💥');
await resolve();
return 'ok';
},
});Implements
Methods
create()
ts
create(data): Promise<DynamicTrigger<DynamicTriggerCreateData, undefined>>;Creates a new dynamic trigger on the backend and stores it locally.
Parameters
data
Trigger configuration — see DynamicTriggerCreateData for the details of each field (type, title, keyword, cost, cooldowns, onTrigger callback, etc.).
Returns
Promise<DynamicTrigger<DynamicTriggerCreateData, undefined>>
The created DynamicTrigger. If data.onTrigger is provided, it is automatically wired up to the trigger.
Example
ts
const trigger = await k.dynamicTriggers.create({
type: 'TWREW',
title: 'Random draw',
cost: 500,
onTrigger: async (t, req, resolve) => {
await resolve();
return 'done';
},
});See
Deprecated
Use createFromConfig instead. This method remains fully functional and keeps the historical /trigger/v1 contract for existing apps.
createFromConfig()
Call Signature
ts
createFromConfig(config, onTrigger?): Promise<null>;Creates a dynamic trigger from a complete normalized configuration.
Parameters
config
null
Complete configuration built manually or hydrated by a dynamicTrigger preference WorkUnit. Pass null when an optional preference was left unconfigured by the streamer.
onTrigger?
Optional callback registered immediately on the returned trigger. It can also be registered later with onTrigger.
Returns
Promise<null>
The created trigger, or null when config is null. In that case no HTTP request is made.
Remarks
This method uses the strict /trigger/v2 contract. It is intentionally separate from create, whose payload and /trigger/v1 behavior are preserved for existing apps. A trigger returned here keeps using PUT /trigger/v2/{id} for its instance update calls.
The app must declare the triggers:manage scope. A TWREW additionally requires the Twitch Rewards feature to be available and enabled for the channel.
Add arguments to the config to declare this trigger's own ordered argument schema. The callback then receives named values in request.args, with _raw and _config; Player values become SDK User instances and missing optional arguments are null. Literal schemas infer the callback types. The schema is immutable: settings updates may omit it or repeat it unchanged. Without arguments, the historical callback payload is preserved; [] explicitly opts into the typed payload with no named arguments.
Parsing retains the existing trigger rules, including integer coercion (abc becomes 0). The schema comes from app code, not the WorkUnit.
Examples
ts
const config = k.preferences.get('viewerAction') as DynamicTriggerConfig | null;
const trigger = await k.dynamicTriggers.createFromConfig(
config,
async (_trigger, request, resolve) => {
await resolve();
return `Handled ${request.id}`;
},
);
if (trigger) {
// The optional preference was configured and the callback is active.
}ts
const config = k.preferences.get('give') as DynamicTriggerConfig | null;
await k.dynamicTriggers.createFromConfig(config === null ? null : {
...config,
arguments: [
{name: 'Player', key: 'player', type: 'Player', required: true},
{name: 'Amount', key: 'amount', type: 'int', required: true},
],
}, async (_trigger, request, resolve) => {
k.chat.say(`${request.args.player.display_name}: ${request.args.amount}`);
await resolve();
return 'ok';
});Call Signature
ts
createFromConfig<TSchema>(config, onTrigger?): Promise<DynamicTrigger<DynamicTriggerUpdateConfig<TSchema>, TSchema>>;Creates a dynamic trigger from a complete normalized configuration.
Type Parameters
TSchema
TSchema extends DynamicTriggerArgumentSchema
Parameters
config
DynamicTriggerConfigWithArguments<TSchema>
Complete configuration built manually or hydrated by a dynamicTrigger preference WorkUnit. Pass null when an optional preference was left unconfigured by the streamer.
onTrigger?
DynamicTriggerCallFunction<TSchema, DynamicTriggerUpdateConfig<TSchema>>
Optional callback registered immediately on the returned trigger. It can also be registered later with onTrigger.
Returns
Promise<DynamicTrigger<DynamicTriggerUpdateConfig<TSchema>, TSchema>>
The created trigger, or null when config is null. In that case no HTTP request is made.
Remarks
This method uses the strict /trigger/v2 contract. It is intentionally separate from create, whose payload and /trigger/v1 behavior are preserved for existing apps. A trigger returned here keeps using PUT /trigger/v2/{id} for its instance update calls.
The app must declare the triggers:manage scope. A TWREW additionally requires the Twitch Rewards feature to be available and enabled for the channel.
Add arguments to the config to declare this trigger's own ordered argument schema. The callback then receives named values in request.args, with _raw and _config; Player values become SDK User instances and missing optional arguments are null. Literal schemas infer the callback types. The schema is immutable: settings updates may omit it or repeat it unchanged. Without arguments, the historical callback payload is preserved; [] explicitly opts into the typed payload with no named arguments.
Parsing retains the existing trigger rules, including integer coercion (abc becomes 0). The schema comes from app code, not the WorkUnit.
Examples
ts
const config = k.preferences.get('viewerAction') as DynamicTriggerConfig | null;
const trigger = await k.dynamicTriggers.createFromConfig(
config,
async (_trigger, request, resolve) => {
await resolve();
return `Handled ${request.id}`;
},
);
if (trigger) {
// The optional preference was configured and the callback is active.
}ts
const config = k.preferences.get('give') as DynamicTriggerConfig | null;
await k.dynamicTriggers.createFromConfig(config === null ? null : {
...config,
arguments: [
{name: 'Player', key: 'player', type: 'Player', required: true},
{name: 'Amount', key: 'amount', type: 'int', required: true},
],
}, async (_trigger, request, resolve) => {
k.chat.say(`${request.args.player.display_name}: ${request.args.amount}`);
await resolve();
return 'ok';
});Call Signature
ts
createFromConfig<TSchema>(config, onTrigger?): Promise<DynamicTrigger<DynamicTriggerUpdateConfig<TSchema>, TSchema>>;Creates a dynamic trigger from a complete normalized configuration.
Type Parameters
TSchema
TSchema extends DynamicTriggerArgumentSchema
Parameters
config
DynamicTriggerConfigWithArguments<TSchema>
Complete configuration built manually or hydrated by a dynamicTrigger preference WorkUnit. Pass null when an optional preference was left unconfigured by the streamer.
onTrigger?
DynamicTriggerCallFunction<TSchema, DynamicTriggerUpdateConfig<TSchema>>
Optional callback registered immediately on the returned trigger. It can also be registered later with onTrigger.
Returns
Promise<DynamicTrigger<DynamicTriggerUpdateConfig<TSchema>, TSchema>>
The created trigger, or null when config is null. In that case no HTTP request is made.
Remarks
This method uses the strict /trigger/v2 contract. It is intentionally separate from create, whose payload and /trigger/v1 behavior are preserved for existing apps. A trigger returned here keeps using PUT /trigger/v2/{id} for its instance update calls.
The app must declare the triggers:manage scope. A TWREW additionally requires the Twitch Rewards feature to be available and enabled for the channel.
Add arguments to the config to declare this trigger's own ordered argument schema. The callback then receives named values in request.args, with _raw and _config; Player values become SDK User instances and missing optional arguments are null. Literal schemas infer the callback types. The schema is immutable: settings updates may omit it or repeat it unchanged. Without arguments, the historical callback payload is preserved; [] explicitly opts into the typed payload with no named arguments.
Parsing retains the existing trigger rules, including integer coercion (abc becomes 0). The schema comes from app code, not the WorkUnit.
Examples
ts
const config = k.preferences.get('viewerAction') as DynamicTriggerConfig | null;
const trigger = await k.dynamicTriggers.createFromConfig(
config,
async (_trigger, request, resolve) => {
await resolve();
return `Handled ${request.id}`;
},
);
if (trigger) {
// The optional preference was configured and the callback is active.
}ts
const config = k.preferences.get('give') as DynamicTriggerConfig | null;
await k.dynamicTriggers.createFromConfig(config === null ? null : {
...config,
arguments: [
{name: 'Player', key: 'player', type: 'Player', required: true},
{name: 'Amount', key: 'amount', type: 'int', required: true},
],
}, async (_trigger, request, resolve) => {
k.chat.say(`${request.args.player.display_name}: ${request.args.amount}`);
await resolve();
return 'ok';
});Call Signature
ts
createFromConfig(config, onTrigger?): Promise<DynamicTrigger<DynamicTriggerConfig, undefined>>;Creates a dynamic trigger from a complete normalized configuration.
Parameters
config
Complete configuration built manually or hydrated by a dynamicTrigger preference WorkUnit. Pass null when an optional preference was left unconfigured by the streamer.
onTrigger?
Optional callback registered immediately on the returned trigger. It can also be registered later with onTrigger.
Returns
Promise<DynamicTrigger<DynamicTriggerConfig, undefined>>
The created trigger, or null when config is null. In that case no HTTP request is made.
Remarks
This method uses the strict /trigger/v2 contract. It is intentionally separate from create, whose payload and /trigger/v1 behavior are preserved for existing apps. A trigger returned here keeps using PUT /trigger/v2/{id} for its instance update calls.
The app must declare the triggers:manage scope. A TWREW additionally requires the Twitch Rewards feature to be available and enabled for the channel.
Add arguments to the config to declare this trigger's own ordered argument schema. The callback then receives named values in request.args, with _raw and _config; Player values become SDK User instances and missing optional arguments are null. Literal schemas infer the callback types. The schema is immutable: settings updates may omit it or repeat it unchanged. Without arguments, the historical callback payload is preserved; [] explicitly opts into the typed payload with no named arguments.
Parsing retains the existing trigger rules, including integer coercion (abc becomes 0). The schema comes from app code, not the WorkUnit.
Examples
ts
const config = k.preferences.get('viewerAction') as DynamicTriggerConfig | null;
const trigger = await k.dynamicTriggers.createFromConfig(
config,
async (_trigger, request, resolve) => {
await resolve();
return `Handled ${request.id}`;
},
);
if (trigger) {
// The optional preference was configured and the callback is active.
}ts
const config = k.preferences.get('give') as DynamicTriggerConfig | null;
await k.dynamicTriggers.createFromConfig(config === null ? null : {
...config,
arguments: [
{name: 'Player', key: 'player', type: 'Player', required: true},
{name: 'Amount', key: 'amount', type: 'int', required: true},
],
}, async (_trigger, request, resolve) => {
k.chat.say(`${request.args.player.display_name}: ${request.args.amount}`);
await resolve();
return 'ok';
});Call Signature
ts
createFromConfig(config, onTrigger?): Promise<DynamicTrigger<DynamicTriggerConfig, undefined>>;Creates a dynamic trigger from a complete normalized configuration.
Parameters
config
Complete configuration built manually or hydrated by a dynamicTrigger preference WorkUnit. Pass null when an optional preference was left unconfigured by the streamer.
onTrigger?
Optional callback registered immediately on the returned trigger. It can also be registered later with onTrigger.
Returns
Promise<DynamicTrigger<DynamicTriggerConfig, undefined>>
The created trigger, or null when config is null. In that case no HTTP request is made.
Remarks
This method uses the strict /trigger/v2 contract. It is intentionally separate from create, whose payload and /trigger/v1 behavior are preserved for existing apps. A trigger returned here keeps using PUT /trigger/v2/{id} for its instance update calls.
The app must declare the triggers:manage scope. A TWREW additionally requires the Twitch Rewards feature to be available and enabled for the channel.
Add arguments to the config to declare this trigger's own ordered argument schema. The callback then receives named values in request.args, with _raw and _config; Player values become SDK User instances and missing optional arguments are null. Literal schemas infer the callback types. The schema is immutable: settings updates may omit it or repeat it unchanged. Without arguments, the historical callback payload is preserved; [] explicitly opts into the typed payload with no named arguments.
Parsing retains the existing trigger rules, including integer coercion (abc becomes 0). The schema comes from app code, not the WorkUnit.
Examples
ts
const config = k.preferences.get('viewerAction') as DynamicTriggerConfig | null;
const trigger = await k.dynamicTriggers.createFromConfig(
config,
async (_trigger, request, resolve) => {
await resolve();
return `Handled ${request.id}`;
},
);
if (trigger) {
// The optional preference was configured and the callback is active.
}ts
const config = k.preferences.get('give') as DynamicTriggerConfig | null;
await k.dynamicTriggers.createFromConfig(config === null ? null : {
...config,
arguments: [
{name: 'Player', key: 'player', type: 'Player', required: true},
{name: 'Amount', key: 'amount', type: 'int', required: true},
],
}, async (_trigger, request, resolve) => {
k.chat.say(`${request.args.player.display_name}: ${request.args.amount}`);
await resolve();
return 'ok';
});rejectRequest()
ts
rejectRequest(id, reason?): Promise<void>;Rejects a pending trigger request: cancels the trigger's activation (any currency spent is refunded to the viewer).
Parameters
id
number
Identifier of the trigger request (trigger_request.id).
reason?
string = null
Reason for the rejection, passed to the backend for information.
Returns
Promise<void>
A promise that resolves once the rejection has been sent.
Default Value
null
Remarks
In practice you rather use the reject callback provided to onTrigger, which calls this method with the right identifier.
See
resolveRequest to validate.
remove()
ts
remove(id): Promise<void>;Removes a trigger on the backend and drops it from the local registry.
Parameters
id
number
Identifier of the trigger to remove. Has no effect if this trigger is not known locally.
Returns
Promise<void>
A promise that resolves once the removal is complete.
See
resolveRequest()
ts
resolveRequest(id): Promise<void>;Validates a pending trigger request: confirms the viewer's activation of the trigger (any currency spent is consumed).
Parameters
id
number
Identifier of the trigger request (trigger_request.id).
Returns
Promise<void>
A promise that resolves once the validation has been sent.
Remarks
In practice you rather use the resolve callback provided to onTrigger, which calls this method with the right identifier.
See
rejectRequest to reject.
update()
ts
update(id, data): Promise<DynamicTrigger<DynamicTriggerCreateData, undefined>>;Updates the configuration of an existing trigger (known locally).
Parameters
id
number
Identifier of the trigger to modify.
data
New configuration — see DynamicTriggerCreateData.
Returns
Promise<DynamicTrigger<DynamicTriggerCreateData, undefined>>
The updated DynamicTrigger, or null if no trigger with this id is known locally.