Rubik Combined Listings Swatch dispatches a custom JavaScript event whenever a user clicks on a swatch. This allows you to integrate with analytics, tracking systems, or custom functionality.
The event is delivered on two channels, so you can pick whichever fits your setup:
rcl_swatch_clicked: a regular JavaScript event on window, for theme code and scripts running on the pagerubik:swatch_clicked: a Shopify Customer Events custom event, for web pixels (custom pixels and app pixels)Both carry the same payload described in the table below.
rcl_swatch_clicked
window.addEventListener('rcl_swatch_clicked', function(e) {
console.log('Swatch clicked:', e.detail);
});
Web pixels run in a sandbox and cannot hear regular JavaScript events, so the app also publishes every
swatch click to Shopify's Customer Events system as a custom event named rubik:swatch_clicked.
This lets you track swatch clicks from a custom pixel with no theme code changes, and the pixel keeps working
if you switch themes.
analytics.subscribe('rubik:swatch_clicked', (event) => {
// The swatch payload arrives under event.customData
var swatch = event.customData;
console.log('Swatch clicked:', swatch.optionValue, swatch.productId, swatch.context);
// Forward it to your analytics tool from here (GA4, GTM, Meta, etc.)
});
Notes:
event.customData.
Shopify wraps them in its standard pixel envelope (event id, clientId,
timestamp, and page context), so you can correlate swatch clicks with other
customer events such as page_viewed or checkout_completed.console.log to your pixel and check the browser console.| Property | Type | Description |
|---|---|---|
optionValue |
string|null | Swatch label (e.g., "Blue", "Large") |
productId |
number|null | Shopify product ID |
productTitle |
string|null | Product name |
productUrl |
string|null | URL to product page |
productPrice |
string|null | Formatted price (e.g., "$19.99") |
productPriceWithCurrency |
string|null | Formatted price with currency code (e.g., "$19.99 USD") |
hasPriceRange |
boolean | True if product has multiple prices |
productAvailable |
boolean | Stock availability. With Cross-filter the first group on, a swatch crossed out only because it does not pair with the current selection still reports true: it is in stock, just not in this combination |
productCompareAtPrice |
string|null | Compare-at price if on sale |
productCompareAtPriceWithCurrency |
string|null | Compare-at price with currency code if on sale |
firstAvailableVariantId |
number|null | Selected or first available variant ID of the product |
isCurrent |
boolean | True if this swatch was the selected one when the page rendered |
category |
string|null | Swatch category label |
swatchType |
string | "visual", "button", or "dropdown" |
context |
string | "product_page" or "product_card" |
viewport |
string | "desktop" or "mobile" |
position |
number | Zero-based index in the swatch group |
groupOptionName |
string|null | Option name (e.g., "Color") |
groupId |
number|null | ID of the Rubik product group the clicked swatch belongs to |
timestamp |
number | Unix timestamp in milliseconds |
window.addEventListener('rcl_swatch_clicked', function(e) {
if (window.gtag) {
gtag('event', 'swatch_click', {
product_id: e.detail.productId,
product_name: e.detail.productTitle,
option_value: e.detail.optionValue,
swatch_type: e.detail.swatchType,
context: e.detail.context
});
}
});
window.addEventListener('rcl_swatch_clicked', function(e) {
// Send to your analytics endpoint
fetch('/api/track', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
event: 'swatch_click',
data: e.detail
})
});
});
Paste this snippet into your browser console to see all event data when clicking swatches:
window.addEventListener('rcl_swatch_clicked', function(e) {
var d = e.detail;
alert(
'Swatch Clicked!\n\n' +
'— Swatch Data —\n' +
'optionValue: ' + d.optionValue + '\n' +
'productId: ' + d.productId + '\n' +
'productTitle: ' + d.productTitle + '\n' +
'productUrl: ' + d.productUrl + '\n' +
'productPrice: ' + d.productPrice + '\n' +
'productPriceWithCurrency: ' + d.productPriceWithCurrency + '\n' +
'hasPriceRange: ' + d.hasPriceRange + '\n' +
'productAvailable: ' + d.productAvailable + '\n' +
'productCompareAtPrice: ' + d.productCompareAtPrice + '\n' +
'productCompareAtPriceWithCurrency: ' + d.productCompareAtPriceWithCurrency + '\n' +
'firstAvailableVariantId: ' + d.firstAvailableVariantId + '\n' +
'isCurrent: ' + d.isCurrent + '\n' +
'category: ' + d.category + '\n\n' +
'— Context —\n' +
'swatchType: ' + d.swatchType + '\n' +
'context: ' + d.context + '\n' +
'viewport: ' + d.viewport + '\n' +
'position: ' + d.position + '\n' +
'groupOptionName: ' + d.groupOptionName + '\n' +
'groupId: ' + d.groupId + '\n\n' +
'— Timestamp —\n' +
'timestamp: ' + d.timestamp
);
console.log('rcl_swatch_clicked:', d);
});
setTimeout(0) to avoid blocking the UI