This tutorial is for:
By completing this tutorial, you will:
onTrack callback to detect when widgets are readyBefore starting this tutorial, ensure you have:
This tutorial uses the onTrack callback, which is a core widget feature available for all widget types.
Widget loading happens in multiple asynchronous phases:
SIR function becomes availableThe time between widget initialization and data rendering can vary from milliseconds to several seconds depending on network conditions. A loading indicator improves user experience during this wait.
Users see a blank space while widgets load, which can:
A loading indicator provides visual feedback that content is on the way.
Start with a standard widget integration. The widgetloader script downloads asynchronously, then the SIR function loads the widget.
<script>
(function(a,b,c,d,e,f,g,h,i){a[e]||(i=a[e]=function(){(a[e].q=a[e].q||[]).push

Add a separate element for your loading indicator. Keep it outside the widget's target element.
<div class="widgets">
<!-- Widget target element - will be populated by widget code -->
<div id="sr-widget-1" class="box"></div>
<!-- Separate element for loading indicator -->
<div id="your-content" class="box">
<div class="loader"></div>
</div>
</div>Critical: Never add the loading indicator inside the widget's target element (#sr-widget-1). The widget will replace all content in that element when it initializes.
Add styles to size the elements and animate the loader.
View Complete CSS
body {
display: flex;
justify-content: center;
}
.widgets {
max-width: 360px;
width: 100%;
}
/* Set same size for widget and loader containers */
.box {
border

Use the onTrack callback to detect when the widget has loaded data, then swap visibility between the loader and widget.
let widgetHasInitialized = false;
function onTrack(target, data) {
// Listen for 'data_change' event - fired when widget receives data
if (target === "data_change" && !data.error && !widgetHasInitialized) {
// Show the widget
document.getElementById('sr-widget-1').style.
The data_change Event: This event fires when the widget successfully receives data. If data.error is undefined, the widget will render successfully.
SIR("addWidget", "#sr-widget-1", "match.scoreboard", {
matchId: 41960917,
onTrack: onTrack
});Add CSS to hide the widget element until data loads.
/* Hide widget until data loads */
#sr-widget-1 {
display: none;
}View Complete Working Example
<!DOCTYPE html>
<html>
Symptom: The loading indicator vanishes before the widget displays, leaving a blank space.
Cause: The loading indicator was placed inside the widget's target element.

Incorrect Implementation:
<!-- ❌ DON'T DO THIS -->
<div id="sr-widget-1" class="box">
<!-- This will be removed when widget initializes! -->
<div id="your-content" class="box">
<div class="loader"></div>
</div>
</div>Correct Implementation:
<!-- ✅ DO THIS -->
<div class="widgets">
<!-- Widget target - empty, will be filled by widget -->
<div id="sr-widget-1" class="box"></div>
<!-- Loader in separate element -->
<div id="your-content" class="box">
<div class="loader"></div>
</div>
</Cause: Forgot to hide the widget element initially with CSS.
Solution: Add CSS to hide the widget until data_change fires:
#sr-widget-1 {
display: none;
}Cause: The onTrack callback isn't firing or has incorrect logic.
Solution: Verify:
onTrack is passed to widget configurationtarget === "data_change"You can extend the onTrack callback to handle loading errors:
function onTrack(target, data) {
if (target === "data_change" && !widgetHasInitialized) {
widgetHasInitialized = true;
if (data.error) {
// Handle error state
document.getElementById('your-content').innerHTML =
Always keep the loading indicator in a separate element from the widget's target. The widget replaces its target element's content.
The onTrack callback with data_change event is the reliable way to detect when a widget has loaded and is ready to display.
Start with the widget hidden (display: none) and only show it after the data_change event confirms successful loading.
Important: Even though we call SIR("addWidget", ...) immediately, it only executes after the widgetloader downloads. Once executed, it:
You can use any loading indicator style - spinners, skeleton screens, progress bars, or branded animations. Just ensure it provides clear visual feedback.
Optimization: The widgetHasInitialized flag ensures we only change display once, even if multiple data_change events fire.
Never add content to the widget's target element. When addWidget executes, it replaces ALL content in the target element with widget code.