Header Image
 
 
  • window.appBlockPlacements ||= []; if (window.klarnaAppBlocksManager) { window.klarnaAppBlocksManager.push({ productVariants: [{"id":55060082164095,"title":"Black \/ ø 31.8mm \/ 35mm","option1":"Black","option2":"ø 31.8mm","option3":"35mm","sku":"","requires_shipping":true,"taxable":true,"featured_image":{"id":73216909902207,"product_id":14928103047551,"position":2,"created_at":"2025-02-01T11:31:45+00:00","updated_at":"2025-02-01T11:31:49+00:00","alt":null,"width":1880,"height":1780,"src":"\/\/projektride.co.uk\/cdn\/shop\/files\/Screenshot2025-02-01at11.31.40.png?v=1738409509","variant_ids":[55060082164095,55060082196863,55060082229631,55060082262399]},"available":true,"name":"Hope Gravity Stem - Black \/ ø 31.8mm \/ 35mm","public_title":"Black \/ ø 31.8mm \/ 35mm","options":["Black","ø 31.8mm","35mm"],"price":11000,"weight":0,"compare_at_price":null,"inventory_management":null,"barcode":null,"featured_media":{"alt":null,"id":64079086190975,"position":2,"preview_image":{"aspect_ratio":1.056,"height":1780,"width":1880,"src":"\/\/projektride.co.uk\/cdn\/shop\/files\/Screenshot2025-02-01at11.31.40.png?v=1738409509"}},"requires_selling_plan":false,"selling_plan_allocations":[],"quantity_rule":{"min":1,"max":null,"increment":1}},{"id":55060082196863,"title":"Black \/ ø 31.8mm \/ 50mm","option1":"Black","option2":"ø 31.8mm","option3":"50mm","sku":"","requires_shipping":true,"taxable":true,"featured_image":{"id":73216909902207,"product_id":14928103047551,"position":2,"created_at":"2025-02-01T11:31:45+00:00","updated_at":"2025-02-01T11:31:49+00:00","alt":null,"width":1880,"height":1780,"src":"\/\/projektride.co.uk\/cdn\/shop\/files\/Screenshot2025-02-01at11.31.40.png?v=1738409509","variant_ids":[55060082164095,55060082196863,55060082229631,55060082262399]},"available":true,"name":"Hope Gravity Stem - Black \/ ø 31.8mm \/ 50mm","public_title":"Black \/ ø 31.8mm \/ 50mm","options":["Black","ø 31.8mm","50mm"],"price":11000,"weight":0,"compare_at_price":null,"inventory_management":null,"barcode":null,"featured_media":{"alt":null,"id":64079086190975,"position":2,"preview_image":{"aspect_ratio":1.056,"height":1780,"width":1880,"src":"\/\/projektride.co.uk\/cdn\/shop\/files\/Screenshot2025-02-01at11.31.40.png?v=1738409509"}},"requires_selling_plan":false,"selling_plan_allocations":[],"quantity_rule":{"min":1,"max":null,"increment":1}},{"id":55060082229631,"title":"Black \/ ø 35mm \/ 35mm","option1":"Black","option2":"ø 35mm","option3":"35mm","sku":"","requires_shipping":true,"taxable":true,"featured_image":{"id":73216909902207,"product_id":14928103047551,"position":2,"created_at":"2025-02-01T11:31:45+00:00","updated_at":"2025-02-01T11:31:49+00:00","alt":null,"width":1880,"height":1780,"src":"\/\/projektride.co.uk\/cdn\/shop\/files\/Screenshot2025-02-01at11.31.40.png?v=1738409509","variant_ids":[55060082164095,55060082196863,55060082229631,55060082262399]},"available":true,"name":"Hope Gravity Stem - Black \/ ø 35mm \/ 35mm","public_title":"Black \/ ø 35mm \/ 35mm","options":["Black","ø 35mm","35mm"],"price":11000,"weight":0,"compare_at_price":null,"inventory_management":null,"barcode":null,"featured_media":{"alt":null,"id":64079086190975,"position":2,"preview_image":{"aspect_ratio":1.056,"height":1780,"width":1880,"src":"\/\/projektride.co.uk\/cdn\/shop\/files\/Screenshot2025-02-01at11.31.40.png?v=1738409509"}},"requires_selling_plan":false,"selling_plan_allocations":[],"quantity_rule":{"min":1,"max":null,"increment":1}},{"id":55060082262399,"title":"Black \/ ø 35mm \/ 50mm","option1":"Black","option2":"ø 35mm","option3":"50mm","sku":"","requires_shipping":true,"taxable":true,"featured_image":{"id":73216909902207,"product_id":14928103047551,"position":2,"created_at":"2025-02-01T11:31:45+00:00","updated_at":"2025-02-01T11:31:49+00:00","alt":null,"width":1880,"height":1780,"src":"\/\/projektride.co.uk\/cdn\/shop\/files\/Screenshot2025-02-01at11.31.40.png?v=1738409509","variant_ids":[55060082164095,55060082196863,55060082229631,55060082262399]},"available":true,"name":"Hope Gravity Stem - Black \/ ø 35mm \/ 50mm","public_title":"Black \/ ø 35mm \/ 50mm","options":["Black","ø 35mm","50mm"],"price":11000,"weight":0,"compare_at_price":null,"inventory_management":null,"barcode":null,"featured_media":{"alt":null,"id":64079086190975,"position":2,"preview_image":{"aspect_ratio":1.056,"height":1780,"width":1880,"src":"\/\/projektride.co.uk\/cdn\/shop\/files\/Screenshot2025-02-01at11.31.40.png?v=1738409509"}},"requires_selling_plan":false,"selling_plan_allocations":[],"quantity_rule":{"min":1,"max":null,"increment":1}},{"id":55060082295167,"title":"Purple \/ ø 31.8mm \/ 35mm","option1":"Purple","option2":"ø 31.8mm","option3":"35mm","sku":"","requires_shipping":true,"taxable":true,"featured_image":{"id":73216910229887,"product_id":14928103047551,"position":3,"created_at":"2025-02-01T11:31:52+00:00","updated_at":"2025-02-01T11:31:56+00:00","alt":null,"width":1880,"height":1780,"src":"\/\/projektride.co.u











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.Track Your Service We also have a physical store, if you are local please pop in -
ProjektRide Bike Shop Edinburgh
003e\n\u003c\/div\u003e"}; window._RestockRocketConfig.variantsInventoryPolicy = {42354640290018 : "deny",42354640355554 : "deny",42354640421090 : "deny",42354640486626 : "deny",42354640552162 : "deny",}; window._RestockRocketConfig.variantsInventoryQuantity = {42354640290018 : parseInt("0"),42354640355554 : parseInt("0"),42354640421090 : parseInt("0"),42354640486626 : parseInt("0"),42354640552162 : parseInt("0"),}; window._RestockRocketConfig.variantsPreorderCount = {42354640290018 : parseInt(""),42354640355554 : parseInt(""),42354640421090 : parseInt(""),42354640486626 : parseInt(""),42354640552162 : parseInt(""),}; window._RestockRocketConfig.variantsPreorderCountForMarket = {42354640290018 : null,42354640355554 : null,42354640421090 : null,42354640486626 : null,42354640552162 : null,}; window._RestockRocketConfig.variantsPreorderMaxCount = {42354640290018 : parseInt(""),42354640355554 : parseInt(""),42354640421090 : parseInt(""),42354640486626 : parseInt(""),42354640552162 : parseInt("Second-Hand Bikesither consumer's try/catch: whether this shop has preorders // configured at all — an enabled selling plan plus at least one preorder variant id, // independent of the block toggle. Fail-open: on error the flag stays unset and both // consumers no-op. try { var _sqCfg = window._RestockRocketConfig; var _sqPlanEnabled = Array.isArray(_sqCfg.sellingPlans) && _sqCfg.sellingPlans.some(function (p) { return p && p.enabled; }); var _sqPreCount = ((_sqCfg.cachedPreorderVariantIds && _sqCfg.cachedPreorderVariantIds.preorder_variant_ids) || []).length; _sqCfg.preordersConfigured = !!(_sqPlanEnabled && _sqPreCount); } catch (e) { /* fail open */ } // STOQ-1612: block (not hide) Buy Now / Shop Pay until our JS runs, so a tap in the // load window can't bypass preorder. pointer-events via .stoq-buy-now-pending (no // reflow); timeout releases; renderPreorderButton / featured_product.js lift it. // Gated by the `block_accelerated_checkout` toggle (default OFF) for gradual r Arm && document.documentElement) { _sqc.acceleratedGateArmed = true; document.documentElement.classList.add('stoq-buy-now-pending'); setTimeout(function () { document.documentElement.classList.remove('stoq-buy-now-pending'); }, 6000); } } catch (e) { /* fail open */ } window._RestockRocketConfig.scriptUrlProduct = 'https://cdn.shopify.com/extensions/019faf5b-94c9-7a24-9306-bf1118ca3099/restockrocket-1-554/assets/restockrocket-product.js' window._RestockRocketConfig.scriptUrlCollection = 'https://cdn.shopify.com/extensions/019faf5b-94c9-7a24-9306-bf1118ca3099/restockrocket-1-554/assets/restockrocket-collection.js' window._RestockRocketConfig.scriptUrlProductBis = 'https://cdn.shopify.com/extensions/019faf5b-94c9-7a24-9306-bf1118ca3099/restockrocket-1-554/assets/restockrocket-product-bis.js' window._RestockRocketConfig.scriptUrlCollectionBis = 'https://cdn.shopify.com/extensions/019faf5b-94c9-7a24-9306-bf1118ca3099/restockrocket-1-554/assets/restockrocket-collectioSee More<
< < che age if (!liquidRenderedAt || typeof liquidRenderedAt !== 'number' || isNaN(liquidRenderedAt)) { console.debug('STOQ - Invalid or missing liquidRenderedAt timestamp, assuming fresh'); window._RestockRocketConfig.isLiquidCacheFresh = true; window._RestockRocketConfig.liquidCacheAge = null; } else { const now = Math.floor(Date.now() / 1000); // Current time in seconds const liquidCacheAge = now - liquidRenderedAt; // Age in seconds // Surfaced into funnel events: a stale cache means the app rendered with // outdated inventory/selling-plan data — a real "had the opportunity but // failed" cause. Negative (client clock ahead) clamps to 0. window._RestockRocketConfig.liquidCacheAge = Math.max(0, liquidCacheAge); // Handle client clock ahead of server if (liquidCacheAge age = Date.now() - updatedAt.getTime(); if (age 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 cusCustom BuildsonStorage.getItem('_stoq_pls') || '0', 10) || 0) + 1; window.sessionStorage.setItem('_stoq_pls', String(_stoqPageSeq)); } catch (e) { /* sessionStorage unavailable (private mode) — leave 0 */ } 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 || '', // Buyer's storefront country (localization.country.iso_code). Seeds the // pixel's extension_details blob so it rides forward onto Shopify's native // events too — a market can span countries, so this is the finer signal. country_code: _stoqInitConfig.countryIsoCode || '', detected_variant_ids: _stoqDetectedVariantIds, selected_variant_id: _stoqSelectedVariantId || '', page_load_seq: _stoqPageSeq, liquid_rendered_at: _stoqInitConfig.liquidRenderedAt || 0, app_version rm 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.closest('form'); var vidEl = form && form.querySelector('[name="id"]'); var variantId = 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 before any scripts are loaded to avoid race conditions function setupCartSellingPlanUpdater(settings) { ned `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/Custom Builds for saleversion>/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:refrontSettings = 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': 'skin, // 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 = settings.preorder_enabled || hasEnabledOffer || hasDisabledPlanIds; const collectionScriptUrl = usePreorderBuild ? window._RestockRocketConfig.scriptUrlCollection : window._RestockRocketConfig.scriptUrlCollectionBis; const productScriptUrl = usePreorderBuild ? window._RestockRocketConfig.scriptUrlProduct : window._RestockRocketConfig.scriptUrlProductBis; const pageType = window._RestockRocketConfig.pageType; const collectiocketConfig.pageType, enabled: settings.enable_app, settings: settings, preorderEnabled: settings.preorder_enabled } }); console.debug('STOQ - dispatching app loaded event'); window.dispatchEvent(appLoadedEvent); } }
Workshop
See More
Track Your Service
See More
Custom Builds
Cycle To Work Schemes
Insure Your Bike
Book a Service
Parts & Components
See More

bike_490f99ba-a097-4bd4-9ba6-e1e4b7c61178.png


equipment.png



Create accountpay.png

Search
confirmation.png

Country
collection.pngGBP£

Åland Islands (EUR€)
ride_confident.png

Albania (ALLL)

Algeria (DZDد.ج)
Andorra (EUR€)

Angola (GBP£)
  • Ascension Island (SHP£)

  • Cyprus (EUR€) Czechia (CZKKč)
  • Denmark (DKKkr.)

    Djibouti (DJFFdj)
  • Egypt (EGPج.م) Equatorial Guinea (XAFCFA)
  • Eritrea (GBP£)

    Estonia (EUR€)


    Eswatini (GBP£)

  • Finland (EUR€)
  • France (EUR€) French Southern Territories (EUR€)