Custom Widget
This is the most powerful tool in SE Overlay editor. You can do a lot of things within this widget using HTML/CSS/JavaScript and accessing variables
Note:
You cannot access
document.cookie
norIndexedDB
via it (security reasons), so you need to keep your data elsewhere (accessible via HTTP API) or SE_API store.
Before Starting
Prerequisites
This article requires you to have an Overlay created with a Custom Widget added there. To do so, follow the steps in the Before Starting article.
Custom Code Editor
The Custom Code Editor is a powerful tool that allows you to write custom code in the Overlay Editor. For more information about the Custom Code Editor, please refer to the Widget Structure article.
SE_API
SE_API is a set of functions that provide access to various personalized features for custom widgets. You can check the ones available below:
-
.store - A key-value store where objects can be saved globally in a permanent way. The stored data is accessible to other custom widgets under the same account.
-
.cheerFilter - Removes cheer emotes from a message.
-
.counters - Retrieves the value of a specific counter.
-
.getOverlayStatus - Gets the status of the overlay.
-
.resumeQueue - Resumes the queue immediately.
-
.sanitize - Sanitizes a message by removing bad words.
-
.setField - Sets a value for
fieldData[key]
. This does not save the value and works only in the Overlay Editor.
store.set
Stores an object in the database under the specified keyName (keyName
can be any alphanumeric string).
Note 1: Setting a value will completely overwrite any existing data stored under the same key. Ensure you send the full object, as partial updates are not supported.
Note 2: Keys cannot be removed once created. You can update their values as often as needed, but deletion is not possible so far.
const object = { "item1":"value1", "item2":"value2" }
SE_API.store.set("keyName", object);
It emits an onEventReceived
event for every custom widget. Example payload:
{
"detail": {
"listener": "kvstore:update",
"event": {
"data": {
"key": "customWidget.keyName",
"value": {
"item1": "value1",
"item2": "value2"
}
}
}
}
}
.store.get
Retrieves the contents stored under the specified "keyName" key. The returned obj is the full object stored in the database.
SE_API.store.get('keyName').then(obj => {
console.log(obj);
/*
The result would look like below:
{
"item1": "value1",
"item2": "value2"
}
*/
});
.counters.get
Gets the value of a counter. Your counters can be found at https://streamelements.com/dashboard/bot/counters
For example, if you have a counter named "test" with a value of "15":
SE_API.counters.get('test').then(counter => {
console.log(counter);
/*
The result would look like below:
{
"id": "test",
"count":15
}
*/
});
.sanitize
Sanitizes a message by filtering vulgar words.
For example, if the word "vulgarWord" is marked as a bad word (configured in Tipping Settings) and the filter is set to "Replace bad words with emotes":
const vulgarSentence = "This is a sentence with vulgarWord";
SE_API.sanitize({ message: vulgarSentence }).then(sanityResult => {
console.log(sanityResult);
/*
The result would look like this:
{
"skip": false, // Indicates whether the message should be skipped according to the rules.
"result":{
"message":"This is a sentence with 4Head" // Message after filtering
}
}
*/
});
.cheerFilter
Clears cheer emotes from message.
const message = "shamrock100 This is a cheer message cheer100 cheer100 cheerwhal100"
SE_API.cheerFilter(message).then(cheerResult => {
console.log(cheerResult);
/*
The result would look like below:
This is a cheer message
*/
});
.getOverlayStatus
Gets overlay Status.
SE_API.getOverlayStatus().then(status => {
console.log(status);
/*
Result would look like below:
{
"isEditorMode":true,
"muted":false
}
*/
});
.setField
Sets a value for fieldData[key]
.
It works only in the Overlay Editor itself and does not save the value.
The third parameter is an optional boolean that indicates whether the overlay should be reloaded after the value is set. The default is true.
SE_API.setField('key', 'value', false);
resumeQueue method and widgetDuration property
The widgetDuration
property defines the maximum event queue hold time (execution time of widget) by widget in seconds (default is 0). For example, if you want to show animations by this widget and don’t want them to overlap, instead of building your own queue, you can use this. This property is defined in JSON (as mentioned above). Premature queue resume can be called by SE_API.resumeQueue();
The best way to explain this is through an example:
Scenario:
We have an animation for community sub gifts (only), and we want to use it. The animation duration is dynamic between 7 and 15 seconds, and we don’t want it to overlap on alerts.
Code:
Fields:
{
"widgetDuration":{
"type": "hidden",
"value": 15
}
}
JS:
let skippable=["bot:counter","event","event:test","event:skip","alertService:toggleSound","message","delete-message","delete-messages","kvstore:update"]; //Array of events coming to widget that are not queued so they can come even if queue is on hold
let playAnimation=(event)=>{
$("container").html(`<div id="sender">${event.sender}</div><div class="amount">${event.amount} subs!</div>`)
return Math.floor(Math.random()*8)+7;
};
window.addEventListener('onEventReceived', function (obj) {
const listener = obj.detail.listener;
console.log(obj.detail);
const data = obj.detail.event;
console.log(`RECEIVED ${listener}`);
if (skippable.indexOf(listener)!==-1) return;
if (listener !== 'subscriber-latest') {
console.log("Resuming as event is not sub");
SE_API.resumeQueue();
return;
}
if (data.bulkGifted !== true && !data.gifted) {
console.log("Resuming as event is not sub gift");
SE_API.resumeQueue();
return;
}
if (data.name === data.sender) {
console.log("Getting animation duration for premature resume");
let time=playAnimation(data);
setTimeout(SE_API.resumeQueue, time*1000);
}
});