Header Image
handle>-
version>/assets/... // Trailing digits (e.g. ".../restockrocket-1-521/assets/" -> "521"). Kept numeric to // match ParseStoqData, so funnel app_version lines up with the order-attribution // app_version. Reflects the ACTUAL deployed build. This is the SINGLE source of the // parsed version — preorder.js getAppVersion() reads it back off config rather than // re-parsing, so the regex lives in exactly one place. try { const _stoqVersionMatch = window._RestockRocketConfig.scriptHost.match(/(\d+)\/?(?:assets\/?)?$/); window._RestockRocketConfig.appVersion = (_stoqVersionMatch && _stoqVersionMatch[1]) || ''; } catch (e) { window._RestockRocketConfig.appVersion = ''; } const SETTINGS_CACHE_DURATION = 15 * 60 * 1000; // 15 minutes in milliseconds const LIQUID_CACHE_MAX_AGE = 15 * 60; // 15 minutes in seconds // Calculate Liquid cache freshness once at initialization const liquidRenderedAt = window._RestockRocketConfig.liquidRenderedAt; // Validate timestamp and calculate ca
<
<
tomer 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 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.closeFaroe Islands (DKKkr.) 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 for ipts. Race against a 1000ms timeout so a slow // API can't block init indefinitely. If the timeout wins, the in-flight // fetches still complete and update window._RestockRocketConfig — the // bundle re-reads sellingPlans/integrations on every interaction, so the // late-arriving values benefit subsequent renders even though the first // paint may use the Liquid-cached values. On any failure the existing // Liquid-loaded values stay in place via fetchEmbedConfig's catch. if (!window._RestockRocketConfig.isLiquidCacheFresh && !settings.disable_refresh_on_stale_liquid) { console.debug('STOQ - Liquid cache stale, refreshing selling_plans + integrations'); Promise.race([ Promise.all([ fetchEmbedConfig('selling_plans', function(data) { if (data && Array.isArray(data.plans)) { window._RestockRocketConfig.sellingPlans = data.plans; window._RestockRocketConfig.disabledSellingPlanIds = data.disabled_plan_ids || []; France (EUR€) tSellingPlanUpdater(settings); if(settings.enable_app) { const hijackIntegration = window._RestockRocketConfig.integrations.find(function(integration) { return integration.type === 'hijack' && integration.enabled && integration.page_types.includes(window._RestockRocketConfig.pageType); }) // STOQ-1520: serve the lean back-in-stock-only build (no preorder/hijack code) // only to shops with NO preorder plans. Use the full build if preorder is on, // an enabled offer exists, or a disabled-but-kept plan id remains (cart sweep // must still strip those). Rationale in the PR. const hasEnabledOffer = Array.isArray(window._RestockRocketConfig.sellingPlans) && window._RestockRocketConfig.sellingPlans.some(function(plan) { return plan && plan.enabled; }); const hasDisabledPlanIds = Array.isArray(window._RestockRocketConfig.disabledSellingPlanIds) && window._RestockRocketConfig.disabledSellingPlanIds.length > 0; const usePreorderBuild =

Marin Alpine Trail XR AXSGabon (XOFFr)

Gambia (GMDD)
Size Georgia (GBP£)
Ghana (GBP£) Gibraltar (GBP£) Greenland (DKKkr.) Guadeloupe (EUR€)
Guernsey (GBP£)

  • SRAM GX Eagle AXS T-TypeSomalia (GBP£)

  • South Africa (GBP£)

    Derailleur Front

    -South Sudan (GBP£)

  • Spain (EUR€)

    Shift Lever

    SRAM AXS POD MMXSt. Helena (SHP£)

  • Sudan (GBP£)

    Crankset

    SRAM GX Eagle, 32T, 55MM CL, 170MM LengthSvalbard & Jan Mayen (GBP£)

  • Sweden (SEKkr)

    Bottom Bracket

    SRAM DUB MTB 73Switzerland (CHFCHF)

  • Tanzania (TZSSh)

    Chain

    SRAM GX Eagle T-TypeTogo (XOFFr)

  • Tristan da Cunha (GBP£)

    Cassette

    SRAM GX 1275 T-Type 10-52TTunisia (GBP£)

  • Brakes Rear

    SRAM Code Bronze 4-Piston Hydraulic, HSC 200mm RotorUnited Kingdom (GBP£)

  • United States (GBP£)

    Brake Levers

    SRAM Code Bronze Stealth HydraulicVatican City (EUR€)

  • Western Sahara (MADد.م.)

    Handlebar

    Marin Trail, 35mm Clamp, 7000 Alloy Bar, 800mm Length, 20mm Rise, 5 Degree Up, 8 Degree BackZambia (GBP£)

  • Zimbabwe (USD$)

    Stem

  • Grips

    Shop All

    Marin Grizzly Lock-On

  • Headset

    FSA Custom, Adjustable HTA Design

  • Seatpost

    TranzX, YSP39 1x Remote, 34.9 Seatpost Diameter, Travel S = 150mm, M/L = 170mm, XL = 200mm

  • Saddle

    Marin Speed Concept

    BUY
  • SELL

    PedalsRIDE CONFIDENT

    -

  • #productTemplate--template--26482385912191__main { --PT: 60px; --PB: 60px; }

Frequently Asked Questions

  • Please get in touch with a member of the team either by phone (Open image lightbox01313745324 ) or email ( [email protected] ) where on of the team will be more than happy to help.

    ProjektRide Bike Shop Edinburgh

  • Open image lightbox

    If the item is showing in stock, we aim to post the product within 24 hours. Please allow 5 working days to receive the item.

    Postage is free on orders over £50. Orders under £50, our postage charge is £3.99.

    We also have a physical store, if you are local please pop in - Kinesis R2 – ProjektRide

    ProjektRide Bike Shop Edinburgh

    82 Newington Road, EH91QN, Edinburgh.Open image lightbox

Open image lightbox