on block above) — nothing to bypass otherwise. variant_id is read per-clicked-button
// from its form so it's correct on collection/index/search too. block_accelerated_checkout
// context (STOQ-1612) rides in `properties` (forwarded verbatim by the pixel, no schema
// change): a buy_now click on a preorder variant while the gate was armed is a visible
// bypass signal for order debug. Also sends page_url (top-level, like the pixel's native
// events) and two preorder signals in properties (see below).
try {
var _sqTrack = window._RestockRocketConfig;
if (_sqTrack.preordersConfigured) {
document.addEventListener('click', function (e) {
try {
var t = e.target;
if (!t || !t.closest) return;
var host = t.closest('.shopify-payment-button, shopify-payment-terms');
if (!host) return;
var channel = host.matches && host.matches('shopify-payment-terms')
? 'shop_pay_installments' : 'buy_now';
var form = host.close<
st('form');
var vidEl = form && form.querySelector('[name="id"]');
var variantId = (vidEl && vidEl.value) || _sqTrack.selected_variant_id || '';
// The enabled STOQ selling plan the clicked variant belongs to (if any), found once and
// reused for in_enabled_plan / enrolled_plan_id / enrolled_plan_provider below.
var _sqVidNum = Number(variantId);
var _sqPlan = null;
// Array.isArray guard (not `|| []`) so a truthy non-array sellingPlans can't throw and
// silently drop the whole publish.
var _sqPlans = Array.isArray(_sqTrack.sellingPlans) ? _sqTrack.sellingPlans : [];
_sqPlans.forEach(function (pl) {
if (!_sqPlan && pl && pl.enabled && Array.isArray(pl.variant_ids) &&
pl.variant_ids.indexOf(_sqVidNum) !== -1) { _sqPlan = pl; }
});
Shopify?.analytics?.publish?.('stoq_accelerated_checkout_clicked', {
variant_id: variantId,
product_id: (_sqTr= LIQUID_CACHE_MAX_AGE) {
console.debug(`STOQ - Liquid cache is fresh (${Math.round(liquidCacheAge / 60)} minutes old)`);
window._RestockRocketConfig.isLiquidCacheFresh = true;
} else {
console.debug(`STOQ - Liquid cache is stale (${Math.round(liquidCacheAge / 60)} minutes old, max ${Math.round(LIQUID_CACHE_MAX_AGE / 60)} minutes)`);
window._RestockRocketConfig.isLiquidCacheFresh = false;
}
}
function checkSettingsExpiry(settings) {
try {
if (!settings || !settings.updated_at) {
console.debug('STOQ - Invalid settings data structure');
return null;
}
if (!settings.cache) {
console.debug('STOQ - settings caching disabled');
return null;
}
// Check if translations are enabled but missing from cache
// This handles the backfill period where DB has translations but metafield doesn't
if (settings.multi_language_enabled) {
if (!settings.translations) {
// Translations enabled but no ack.product && _sqTrack.product.id) || '',
channel: channel,
market_id: _sqTrack.marketId || '',
page_type: _sqTrack.pageType || '',
cart_token: _sqTrack.cartToken || '',
page_url: (window.location && window.location.href) || '',
properties: {
// Mirror the bundle's own preorder check (preorder.js checkInventoryProvider-
// WithCachedFallback): the live set config.preorderVariantIds (refreshed after
// page load by loadVariantInventoryData) OR the Liquid-injected
// cachedPreorderVariantIds — always present, so it covers clicks before the
// bundle loads (why this tracker is inline). ORing both (not preferring one)
// matches the bundle and is correct even if the live set is an empty array. Both
// hold integer ids; the click-time id comes off a DOM input (.value → string) or
// selected_variant_id, so coerce with Number fortranslation data in metafield
// Metafield hasn't been backfilled yet - force refresh
console.debug('STOQ - multi-language enabled but no translation data in cache, fetching fresh');
return null;
}
// Translations object exists in metafield - cache is valid
// If current locale isn't translated, applyTranslations will gracefully use default locale from base fields
if (window._RestockRocketConfig.normalizedLocale &&
!Object.prototype.hasOwnProperty.call(settings.translations, window._RestockRocketConfig.normalizedLocale)) {
console.debug('STOQ - locale not explicitly translated, will use default language from cache');
}
// Don't return null - continue using cache even for untranslated locales
}
const updatedAt = new Date(settings.updated_at);
if (isNaN(updatedAt.getTime())) {
console.debug('STOQ - Invalid updated_at date format in settings');
return null;
}
const
£5,499.00
a like-typed compare.
is_preorder_variant: (function () {
var vid = Number(variantId);
var has = function (a) { return Array.isArray(a) && a.indexOf(vid) !== -1; };
return has(_sqTrack.preorderVariantIds) ||
has(_sqTrack.cachedPreorderVariantIds &&
_sqTrack.cachedPreorderVariantIds.preorder_variant_ids);
})(),
// Narrow, authoritative preorder signal: enrolled in an ENABLED STOQ selling plan
// (is_preorder_variant above is the broad OOS+continue heuristic — non-STOQ too).
in_enabled_plan: !!_sqPlan,
// In-stock preorder signal: enrolled but currently IN STOCK (in the inStockVariantIds
// set, not the OOS preorderVariantIds set). Same live-OR-cached pattern as
// is_preorder_variant. is_preorder_variant OR is_instock_variant = "should sell via
age = Date.now() - updatedAt.getTime();
if (age < // the plan" regardless of stock, so an in-stock preorder bypass is detectable too.
is_instock_variant: (function () {
var has = function (a) { return Array.isArray(a) && a.indexOf(_sqVidNum) !== -1; };
return has(_sqTrack.inStockVariantIds) ||
has(_sqTrack.cachedInStockVariantIds &&
_sqTrack.cachedInStockVariantIds.in_stock_variant_ids);
})(),
// The enrolled plan's Shopify selling-plan id + inventory_provider (stoq = STOQ tracks
// the OOS count; shopify = in-stock preorder). Tells order-debug what kind of preorder
// the Buy Now bypassed, without a downstream lookup.
enrolled_plan_id: (_sqPlan && (_sqPlan.shopify_selling_plan_id || _sqPlan.shopify_selling_plan_group_id)) || '',
enrolled_plan_provider: (_sqPlan && _sqPlan.inventory_provider) || '',
block_enabled: !!(_sqTrack.cachedSettings && _sqTrack.cachedSettings.block_ac
SETTINGS_CACHE_DURATION) {
console.debug('STOQ - settings changed recently, skipping cache');
return null;
}
return settings;
} catch (error) {
console.debug('STOQ - Error checking settings cache:', error);
return null;
}
}
function createRestockRocketContainer() {
const restockRocketContainer = document.createElement('div');
restockRocketContainer.id = 'restock-rocket';
document.body.appendChild(restockRocketContainer);
}
function createRestockRocketScript(scriptUrl) {
const restockRocketScriptElement = document.createElement('script');
restockRocketScriptElement.setAttribute('defer', 'defer');
restockRocketScriptElement.src = scriptUrl;
document.body.appendChild(restockRocketScriptElement);
}
createRestockRocketContainer()
console.debug('STOQ - extension activated')
// Fire stoq_initialized once per page load so the funnel pipeline has a definitive
// "our code ran on this page" signal independent of any cuscelerated_checkout),
gate_armed: !!_sqTrack.acceleratedGateArmed,
gate_active_at_click: !!(document.documentElement &&
document.documentElement.classList.contains('stoq-buy-now-pending')),
},
});
} catch (err) { /* never break checkout */ }
}, true);
}
} catch (e) { /* fail open */ }
function applyTranslations(settings) {
try {
// Skip translation logic entirely if multi-language is not enabled
if (!settings || !settings.multi_language_enabled) {
return settings;
}
if (!settings.translations) {
console.debug('STOQ - No translations found, skipping translation');
return settings;
}
const normalizedLocale = window._RestockRocketConfig.normalizedLocale;
const translations = settings.translations;
if (!normalizedLocale) {
// No matching locale has translations; drop payload to save memory
console.debug('STOQ - No matching locale fortomer interaction.
// Detected variants: the variants present in this page's Liquid context (product page has them;
// collection/index/etc. don't expose variants from Liquid). Used to disambiguate "embed didn't
// load" vs "embed loaded but the variant wasn't a preorder/BIS candidate" in order debug.
try {
const _stoqInitConfig = window._RestockRocketConfig;
const _stoqDetectedVariantIds = (_stoqInitConfig.product && Array.isArray(_stoqInitConfig.product.variants))
? _stoqInitConfig.product.variants.map(function(v) { return v.id })
: [];
const _stoqSelectedVariantId = _stoqInitConfig.selected_variant_id;
Shopify?.analytics?.publish?.('stoq_initialized', {
cart_token: _stoqInitConfig.cartToken || '',
page_url: window.location.href,
page_type: _stoqInitConfig.pageType || '',
shop_domain: _stoqInitConfig.shop || '',
market_id: _stoqInitConfig.marketId || '',
detected_variant_ids: _stoqDetectedVariantIds,
selected_variant_id: _stoqSele translations. Available:', Object.keys(translations || {}));
delete settings.translations;
return settings;
}
console.debug(`STOQ - Applying translations for normalized locale: ${normalizedLocale} (original: ${window._RestockRocketConfig.locale})`);
const translatedFields = translations[normalizedLocale];
if (translatedFields && typeof translatedFields === 'object') {
Object.keys(translatedFields).forEach(function(key) {
const value = translatedFields[key];
if (value !== null && value !== undefined && value !== '') {
settings[key] = value;
}
});
} else {
console.debug('STOQ - No translated fields found for locale:', normalizedLocale);
}
delete settings.translations;
return settings;
} catch (e) {
console.debug('STOQ - error applying translations:', e);
return settings;
}
}
// Setup event listener for cart selling plan updates
// This must be called be
ctedVariantId || '',
liquid_rendered_at: _stoqInitConfig.liquidRenderedAt || 0,
app_version: _stoqInitConfig.appVersion || '',
liquid_cache_age: _stoqInitConfig.liquidCacheAge,
// Selected variant's stock posture as our app saw it at render — explains
// whether we *should* have treated it as a preorder candidate.
inventory_policy: (_stoqInitConfig.variantsInventoryPolicy || {})[_stoqSelectedVariantId] || '',
inventory_quantity: (_stoqInitConfig.variantsInventoryQuantity || {})[_stoqSelectedVariantId],
});
} catch (e) {
console.debug('STOQ - stoq_initialized publish failed:', e);
}
// STOQ-1595: publish stoq_accelerated_checkout_clicked for every accelerated-checkout
// click (Buy Now / dynamic checkout / Shop Pay installments) on ALL surfaces, before our
// bundle loads, via one delegated capture-phase listener (catches late-rendered buttons).
// Only on shops with preorders configured (shared `preordersConfigured` signal from the
// derivatifore any scripts are loaded to avoid race conditions
function setupCartSellingPlanUpdater(settings) {
// Setup listener regardless - updateCartSellingPlans has its own guards
// This ensures cleanup happens even when preorders are disabled globally
// Listen for stoq:inventory-data-loaded event dispatched by api.js
window.addEventListener('stoq:inventory-data-loaded', function(event) {
console.debug('STOQ - Inventory data loaded, updating cart selling plans');
if (window._RestockRocket && window._RestockRocket.updateCartSellingPlans) {
window._RestockRocket.updateCartSellingPlans()
.then(hasUpdates => {
if (hasUpdates) {
console.debug('STOQ - cart selling plans updated successfully');
} else {
console.debug('STOQ - no cart selling plan updates needed');
}
})
.catch(error => {
console.error('STOQ - error updating cart selling plans:', error);
});
}
});
}
// ---- Live settings via the Storefront API (additive, does not gate init) ----
// The inlined `cachedSettings` comes from the app-embed Liquid render, which
// Shopify edge-caches and can serve stale. Reading the same `settings` metafield
// back over the Storefront API is a POST to /api/
st('form');
var vidEl = form && form.querySelector('[name="id"]');
var variantId = (vidEl && vidEl.value) || _sqTrack.selected_variant_id || '';
// The enabled STOQ selling plan the clicked variant belongs to (if any), found once and
// reused for in_enabled_plan / enrolled_plan_id / enrolled_plan_provider below.
var _sqVidNum = Number(variantId);
var _sqPlan = null;
// Array.isArray guard (not `|| []`) so a truthy non-array sellingPlans can't throw and
// silently drop the whole publish.
var _sqPlans = Array.isArray(_sqTrack.sellingPlans) ? _sqTrack.sellingPlans : [];
_sqPlans.forEach(function (pl) {
if (!_sqPlan && pl && pl.enabled && Array.isArray(pl.variant_ids) &&
pl.variant_ids.indexOf(_sqVidNum) !== -1) { _sqPlan = pl; }
});
Shopify?.analytics?.publish?.('stoq_accelerated_checkout_clicked', {
variant_id: variantId,
product_id: (_sqTr
<version>/graphql.json — never
// CDN-cached — so it returns the live value on every page load. We fetch it
// best-effort and stash it on `window._RestockRocketConfig.storefrontSettings`
// so individual behaviours can migrate onto the fresh value over time. This is
// PURELY ADDITIVE: it does NOT change the resolution flow below, never blocks
// init, and silently no-ops on any failure / missing token.
(function loadStorefrontSettings() {
const cfg = window._RestockRocketConfig;
if (!cfg.storefrontAccessToken || cfg.disableStorefrontApi === true) return;
// Deferred to browser idle so this best-effort read runs strictly AFTER the
// critical init flow and never competes with it for a connection — the call
// is a live, uncached Storefront round-trip and can be slow (multi-second
// TTFB observed). Nothing on the critical path waits for it.
function run() {
const query = 'query StoqSettings($namespace: String!) { shop { metafield(namespace: $namespace, key:CUBE STEREO HYBRID ONE77 HPC TM 800 REEDGREEN/MATRIX - color variant: reedgreen/matrix a like-typed compare.
is_preorder_variant: (function () {
var vid = Number(variantId);
var has = function (a) { return Array.isArray(a) && a.indexOf(vid) !== -1; };
return has(_sqTrack.preorderVariantIds) ||
has(_sqTrack.cachedPreorderVariantIds &&
_sqTrack.cachedPreorderVariantIds.preorder_variant_ids);
})(),
// Narrow, authoritative preorder signal: enrolled in an ENABLED STOQ selling plan
// (is_preorder_variant above is the broad OOS+continue heuristic — non-STOQ too).
in_enabled_plan: !!_sqPlan,
// In-stock preorder signal: enrolled but currently IN STOCK (in the inStockVariantIds
// set, not the OOS preorderVariantIds set). Same live-OR-cached pattern as
// is_preorder_variant. is_preorder_variant OR is_instock_variant = "should sell via
// the plan" regardless of stock, so an in-stock preord
"settings") { value } } }';
fetch(
`https://${cfg.shop}/api/2025-07/graphql.json`,
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Shopify-Storefront-Access-Token': cfg.storefrontAccessToken,
},
body: JSON.stringify({ query: query, variables: { namespace: cfg.metafieldNamespace } }),
}
)
.then(function(response) {
if (!response.ok) { throw new Error('Storefront API HTTP ' + response.status); }
return response.json();
})
.then(function(body) {
if (body && body.errors && body.errors.length) {
throw new Error('Storefront API errors: ' + body.errors.map(function(e) { return e && e.message; }).join(', '));
}
const value = body && body.data && body.data.shop && body.data.shop.metafield && body.data.shop.metafield.value;
if (!value) { throw new Error('Storefront API returned no settings metafield value'); }
cfg.storefrontSettings = JSON.parse(value);
console.debug('STOQ - stored live settings from Storefront API on config.storefrontSettings');
})
.catch(function(e) {
console.debug('STOQ - Storefront settings fetch failed (non-fatal):', e && e.message);
});
}
if (typeof window.requestIdleCallback === 'function') {
window.requestIdleCallback(run, { timeout: 5000 });
} else {
setTimeout(run, 0);
}
})();
// First try to get settings from metafields with expiry check
const cachedSettings = window._RestockRocketConfig.cachedSettings;
const validCachedSettings = cachedSettings ? checkSettingsExpiry(cachedSettings) : null;
if (validCachedSettings) {
console.debug('STOQ - using cached settings');
initializeScripts(validCachedSettings);
} else {
console.debug('STOQ - fetching fresh settings');
const headers = {
'X-Shopify-Shop-Domain': window._RestockRocketConfig.shop || window.Shopify.shop,
'ngrok-skip-browser-warning': 'ski
cceleratedGateArmed,
gate_active_at_click: !!(document.documentElement &&
document.documentElement.classList.contains('stoq-buy-now-pending')),
},
});
} catch (err) { /* never break checkout */ }
}, true);
}
} catch (e) { /* fail open */ }
function applyTranslations(settings) {
try {
// Skip translation logic entirely if multi-language is not enabled
if (!settings || !settings.multi_language_enabled) {
return settings;
}
if (!settings.translations) {
console.debug('STOQ - No translations found, skipping translation');
return settings;
}
const normalizedLocale = window._RestockRocketConfig.normalizedLocale;
const translations = settings.translations;
if (!normalizedLocale) {
// No matching locale has translations; drop payload to save memory
console.debug('STOQ - No matching locale for translations. Available:', Object.keys(translations || {})Quick Buyp'
};
if (window.Shopify?.theme?.role === 'main') {
headers['X-Shopify-Theme-Schema-Name'] = window.Shopify.theme.schema_name;
headers['X-Shopify-Theme-Schema-Version'] = window.Shopify.theme.schema_version;
headers['X-Shopify-Theme-Store-Id'] = window.Shopify.theme.theme_store_id;
}
fetch(
`${window._RestockRocketConfig.host}/api/v1/setting.json?translation_locale=${window._RestockRocketConfig.normalizedLocale}`,
{ headers }
)
.then(function(response) {
if (!response.ok) {
throw new Error('Network response was not ok');
}
return response.json();
})
.then(function(settings) {
initializeScripts(settings);
})
.catch(function(error) {
// If request failed and we have cached settings (even if expired), use them as fallback
if (cachedSettings) {
console.debug('STOQ - using expired cached settings as fallback');
initializeScripts(cachedSettings);
} else {
console.error('S
TOQ - failed to load settings:', error);
}
})
.catch(function(e) {
console.error(e)
})
}
function fetchEmbedConfig(endpoint, apply) {
return fetch(
`${window._RestockRocketConfig.host}/api/v1/embed/${endpoint}.json`,
{
headers: {
'X-Shopify-Shop-Domain': window._RestockRocketConfig.shop || window.Shopify.shop,
'ngrok-skip-browser-warning': 'skip'
}
}
)
.then(function(response) {
if (!response.ok) throw new Error(`Failed to fetch ${endpoint}`);
return response.json();
})
.then(function(data) {
try {
apply(data);
} catch (applyError) {
// Apply failures are programming bugs (e.g. response shape changed
// server-side and the assignment threw). Surface them as console.error
// so they're visible in browser logs, then re-throw to fall through
// to the same Liquid-cached fallback as a fetch failure.
console.error('STOQ - apply failed for ' +
tion setupCartSellingPlanUpdater(settings) {
// Setup listener regardless - updateCartSellingPlans has its own guards
// This ensures cleanup happens even when preorders are disabled globally
// Listen for stoq:inventory-data-loaded event dispatched by api.js
window.addEventListener('stoq:inventory-data-loaded', function(event) {
console.debug('STOQ - Inventory data loaded, updating cart selling plans');
if (window._RestockRocket && window._RestockRocket.updateCartSellingPlans) {
window._RestockRocket.updateCartSellingPlans()
.then(hasUpdates => {
if (hasUpdates) {
console.debug('STOQ - cart selling plans updated successfully');
} else {
console.debug('STOQ - no cart selling plan updates needed');
}
})
.catch(error => {
console.error('STOQ - error updating cart selling plans:', error);
});
}
});
}
// ---- Live settings via the Storefront API (ad
endpoint + ':', applyError);
throw applyError;
}
})
.catch(function(error) {
console.debug(`STOQ - using cached ${endpoint}:`, error.message);
});
}
function initializeScripts(settings) {
settings = applyTranslations(settings);
window._RestockRocketConfig.settings = settings;
console.debug(`STOQ - settings configured for ${window._RestockRocketConfig.pageType}`);
// Stale-Liquid resilience (default-on, per-shop opt-out via the
// `disable_refresh_on_stale_liquid` Toggle, surfaced as the negative
// `disable_refresh_on_stale_liquid` flag in settings.json so that
// `undefined` -- in CDN-cached metafield payloads that predate this
// key -- reads as `!undefined === true` and gets default-on behavior
// immediately, no metafield rewrite required).
// When the Liquid CDN cache is older than LIQUID_CACHE_MAX_AGE the in-page
// selling_plans / integrations metafields can be wrong; refresh both from
// the API before launching scr
"settings") { value } } }';
fetch(
`https://${cfg.shop}/api/2025-07/graphql.json`,
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Shopify-Storefront-Access-Token': cfg.storefrontAccessToken,
},
body: JSON.stringify({ query: query, variables: { namespace: cfg.metafieldNamespace } }),
}
)
.then(function(response) {
if (!response.ok) { throw new Error('Storefront API HTTP ' + response.status); }
return response.json();
})
.then(function(body) {
if (body && body.errors && body.errors.length) {
throw new Error('Storefront API errors: ' + body.errors.map(function(e) { return e && e.message; }).join(', '));
}
const value = body && body.data && body.data.shop && body.data.shop.metafield && body.data.shop.metafield.value;
if (!value) { throw new Error('Storefront API returned no settings metafield value'); }
cfg.stoonPageTypes = ['collection', 'index', 'search', 'page'];
if(collectionPageTypes.indexOf(pageType) !== -1 && (settings[`show_button_on_${pageType}`] || settings[`preorder_${pageType}_enabled`])) {
createRestockRocketScript(collectionScriptUrl);
} else if(pageType === 'product') {
createRestockRocketScript(productScriptUrl);
} else if(hijackIntegration) {
createRestockRocketScript(window._RestockRocketConfig.scriptUrlCollection);
} else if(usePreorderBuild) {
// cart/article/blog/list-collections: full build so the cart sweep runs.
createRestockRocketScript(window._RestockRocketConfig.scriptUrlCollection);
} else {
console.debug(`STOQ - no scripts enabled for ${pageType}`);
}
// Dispatch custom event when app is loaded
// Cart selling plan updates will be triggered by stoq:inventory-data-loaded event
const appLoadedEvent = new CustomEvent('stoq:loaded', {
detail: {
pageType: window._RestockR
CUBE TRIKE FAMILY HYBRID 1500 BLUE/REFLEX
£4,499.00CUBE STEREO HYBRID ONE77 HPC SLX 800 GLINTSAND/BLACK
CUBE TRIKE FAMILY HYBRID 1500 BLUE/REFLEX - color variant: blue/reflex
Sold Out
CUBE STEREO HYBRID ONE77 HPC SLX 800 BLUEIRIS/BLACK
£4,499.00
CUBE TOURING HYBRID PRO 800 PEARLGREY/GREY
£2,799.00CUBE STEREO HYBRID ONE77 HPC SLX 800 BLUEIRIS/BLACK - color variant: blueiris/black
CUBE STEREO HYBRID ONE77 HPC RACE 800 WILLOWGREEN/BLACK
£3,999.00
CUBE TOURING HYBRID ONE 600 COAL/CHROME
£2,399.00CUBE STEREO HYBRID ONE77 HPC RACE 800 WILLOWGREEN/BLACK - color variant: willowgreen/black
CUBE STEREO HYBRID ONE77 HPC RACE 800 SWIMMINGPOOL/BLACK
£3,999.00
CUBE TOURING HYBRID COMFORT SLX 800 CHILLI/CHROME
£2,999.00CUBE STEREO HYBRID ONE77 HPC RACE 800 SWIMMINGPOOL/BLACK - color variant: swimmingpool/black
CUBE SUPREME HYBRID PRO 625 BLACK/SPECTRAL - color variant: black/spectralCUBE STEREO HYBRID ONE77 HPC AT 800 ACTIONTEAM
£6,499.00
CUBE STEREO HYBRID ONE77 HPC AT 800 ACTIONTEAM - color variant: actionteam
CUBE SUPREME HYBRID ONE 500 DESERTSTONE/BLACK - color variant: desertstone/blackCUBE STEREO HYBRID ONE44 PRO 800 VULCAN/ORANGE
£3,499.00
CUBE STEREO HYBRID ONE44 PRO 800 VULCAN/ORANGE - color variant: vulcan/orange
CUBE STEREO HYBRID ONE44 PRO 800 SHIFTBLUSH/RAISIN
CUBE SUPREME HYBRID DELUXE SLX 600 SEAGREY/BLACK - color variant: seagrey/black
£3,499.00
CUBE STEREO HYBRID ONE44 PRO 800 SHIFTBLUSH/RAISIN - color variant: shiftblush/raisin
£4,199.00
Quick Buy
CUBE STEREO HYBRID ONE44 HPC TM 800 REEDGREEN/MATRIX
CUBE SUPREME HYBRID DELUXE ONE 600 INDIGOBLUE/SWITCH
Sold Out
CUBE SUPREME HYBRID DELUXE ONE 600 INDIGOBLUE/SWITCH - color variant: indigoblue/switch
Building Your Bike From the Box
Service
CUBE STEREO HYBRID ONE44 HPC SLT 800 CARBONGRID/CHROME
Bosnia & Herzegovina (BAMКМ)
£7,499.00
Botswana (BWPP)
CUBE STEREO HYBRID ONE44 HPC SLT 800 CARBONGRID/CHROME - color variant: carbongrid/chrome

Contact Us






















CUBE SUPREME HYBRID PRO 625 ELECTRICBLUE/BLUE
Sold Out












Algeria (DZDد.ج)