How to integrate a html web story carousel on your website
This guide explains how to embed the Slidy Story Carousel into your application, configure its behavior, and correctly handle user consent for analytics and personalization.
⚠️ Important! This guide assumes the reader has a technical background.
Basic Integration
Minimal Embed Example
<div
class="cutnutwidget"
id="wamRUXg0OV"
style="min-height: 250px; padding: 10px 0 35px 0; position: relative;"
></div>
<script async defer src="https://widget.zazuapp.co/widget.js"></script>
Widget Configuration
The widget can be configured using HTML data-* attributes.
These options allow control over which stories are displayed, personalization behavior, and analytics handling.
Full Configuration Example
<div
class="cutnutwidget"
id="wamRUXg0OV"
data-user-id="12345"
data-story-ids="aaa,bbb"
data-excluded-story-ids="ccc,ddd"
data-content-ids="abc,def,ghi"
data-excluded-content-ids="xyz,123"
style="min-height: 250px; padding: 10px 0 35px 0; position: relative;"
></div>
<script async defer src="https://widget.zazuapp.co/widget.js"></script>
User Identification
data-user-id
A known user identifier that can be passed to the widget at runtime.
Behavior
- Used for Google Analytics tracking if analytics consent is enabled
Example
data-user-id="12345"
Story Inclusion
data-story-ids
Comma-separated list of story IDs.
Behavior
- Only these stories are shown
- Stories are rendered in the exact order provided
- Overrides personalization and content-based selection
- Exclusions are still applied
Example
data-story-ids="aaa,bbb"
Story Exclusion
data-excluded-story-ids
Comma-separated list of story IDs to exclude.
Behavior
- Always applied
- Has priority over included story IDs
- Removes matching stories in all cases
Example
data-excluded-story-ids="ccc,ddd"
Content-Based Selection
data-content-ids
Comma-separated list of content IDs.
Behavior
- Used only if
data-story-idsis not provided - Shows only stories matching these content IDs
- Order follows the attribute order
- If multiple stories share the same content ID, the first one wins
- Exclusions are still applied
Example
data-content-ids="abc,def,ghi"
Content Exclusion
data-excluded-content-ids
Comma-separated list of content IDs to exclude.
Behavior
- Always applied
- Has priority over included content IDs
- Removes matching stories in all cases
Example
data-excluded-content-ids="xyz,123"
Selection Logic
The widget resolves stories using the following logic:
-
If story IDs are provided
→ Only those stories are rendered (ordered) -
Else, if content IDs are provided
→ Only stories matching those content IDs are rendered -
Else, if personalization is enabled and consent is given
→ Stories are reordered dynamically -
Else
→ Default editor order is used
Exclusions are applied in all cases.
Exclusion Rules
- Story exclusions match against
story.id - Content exclusions match against
story.contentId - Exclusions always override inclusion rules
Notes & Edge Cases
- Duplicate IDs are ignored (first occurrence wins)
- Empty or invalid IDs are skipped
- All ID comparisons are string-based and trimmed
Quick Recommendations
- Use
data-story-idsfor full manual control - Use
data-content-idsfor group-based control - Use exclusion attributes to force-remove content
- Personalization is used only when no include lists are provided
Consent Management
The widget includes a built-in Consent Manager that controls analytics and personalization behavior.
No widget code changes are required—only consent signals from your site or CMP.
Why Consent Is Required
The widget may:
- Send Google Analytics events
- Decorate outgoing URLs
- Use personalization logic
If no consent is provided:
- Analytics are disabled
- Personalization is disabled
Consent Categories
- Analytics — controls tracking and analytics behavior
- Personalization — controls content ordering and future customization features
Consent Namespace
Default widget namespace:
slidy_carousel
Supported Consent Methods
The widget can receive consent from:
- Custom DOM events
postMessage(iframe-based CMPs)- Data layer pushes (GTM / Tealium)
- TCF 2.x (
__tcfapi) - Global Privacy Control (GPC)
Only one method is required.
Custom DOM Event (Recommended)
<script>
window.dispatchEvent(new CustomEvent(
"slidy_carousel:consent_update",
{
detail: {
analytics: true,
personalization: false
}
}
));
</script>
postMessage (CMP in iframe)
parent.postMessage({
ns: "slidy_carousel",
type: "CONSENT_APPLY",
payload: { analytics: true, personalization: false }
}, "*");
Widget acknowledgement:
{
"ns": "slidy_carousel",
"type": "slidy_carousel:CONSENT_ACK"
}
Data Layer Integration (GTM / Tealium)
<script>
window.dataLayer = window.dataLayer || [];
window.dataLayer.push({
event: "slidy_carousel:consent_update",
analytics: true,
personalization: false
});
</script>
TCF 2.x Integration (Automatic)
If window.__tcfapi is available, the widget automatically maps IAB purposes:
- Analytics → purposes 1,7,8,9,10
- Personalization → purposes 1,3,4,5,6,11
CMP signals always override TCF decisions.
For details on TCF purposes, please refer to:
👉 TCF Translations
Global Privacy Control
If the browser sends a GPC signal:
- Analytics are disabled
- Personalization is disabled
No configuration is required.
Consent Precedence
- GPC overrides everything
- CMP signals override TCF
- Default state disables analytics and personalization
Storage & Data Handling
Consent State Storage
Stored in both:
- Local Storage:
slidy_carousel - Cookie:
slidy_carousel
Deleting both resets the consent state.
Seen Stories Storage
Stored per widget instance:
slidy_carousel:{widgetKey}
Used only in the browser unless personalization consent is enabled.
AMP Story Consent
AMP stories require additional consent handled by AMP itself.
Stored under:
amp-story-state
amp-store:{DOMAIN}
Default domain:
https://stories.zazuapp.co
Troubleshooting
Consent updates are ignored
- Verify the namespace matches
slidy_carousel - Ensure consent values are booleans, not strings
Analytics cookies remain after disabling
- The widget stops sending data
- Cookie deletion must be handled by your CMP