Skip to content

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 ​

DynamicTriggerCreateData

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 ​

update and remove.

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? ​

DynamicTriggerCallFunction

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 ​

DynamicTriggerConfig

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

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 ​

DynamicTriggerConfig

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

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 ​

create.


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 ​

DynamicTriggerCreateData

New configuration — see DynamicTriggerCreateData.

Returns ​

Promise<DynamicTrigger<DynamicTriggerCreateData, undefined>>

The updated DynamicTrigger, or null if no trigger with this id is known locally.

See ​

create.