# MTB Deals (full) > The long version of https://mtbdeals.co/llms.txt. MTB Deals (https://mtbdeals.co/) tracks Black Friday 2026 mountain bike deals: every discounted bike, part and piece of gear from 60 European, UK and US shops, read from the shops' own sale pages and product feeds every two hours. Independent: no affiliate links, no sponsored placements, no ads, no cookies, no trackers. Everything below is public. ## What it is - One page (https://mtbdeals.co/) that routes on the URL hash: Deals (https://mtbdeals.co/#deals), Shops (https://mtbdeals.co/#shops), Calendar (https://mtbdeals.co/#calendar), Saved (https://mtbdeals.co/#saved), Alerts (https://mtbdeals.co/#alerts). A filtered list is a hash too: https://mtbdeals.co/#deals/shop=rose&sizes=L. One deal: https://mtbdeals.co/#deal=. - Each deal shows the shop's price next to the old one, the saving, the real cut against the pre-campaign price, the frame sizes in stock, a price history and a buy-or-wait verdict with the facts behind it. Saved deals, followed shops and target searches live in the browser; email alerts are the only account (an address, double opt-in). - Filters: category (MTB, e-MTB, Parts, Gear & apparel, Gravel & road, Other e-bikes, Other bikes), region (EU, UK, US), shop, campaign, minimum discount, maximum price, new in 48 h, real markdowns only, price band, brand, frame size (S to 3XL), wheel size, riding type, hardtail or full suspension, the verdict. Sorts: best (best deals: the discount weighted by the money it saves); pct (biggest discount: percentage off, ties by the money saved); save (biggest saving: money saved; £ and $ converted); popular (most opened: opened most here in two days); low (lowest price: £ and $ converted); high (highest price: £ and $ converted); new (newest first: first seen most recently; deals without a first-seen date last); real (real markdown: the cut against the pre-campaign price; deals without a reference last); signal (buy now first: Buy now, then Good price, Wait, Too early). ## How the data is read - Every two hours (at the even UTC hours) the tracker reads each shop's own sale pages and product feeds (Shopify collections, HTML tiles, WooCommerce Store APIs). A deal exists only if the shop itself shows a lower price next to the old one; nothing is reported second-hand. Shop prices are read for the Netherlands or the shop's home market (pinned country), so a function running abroad never records export prices without VAT. - Noise control: the first read of a shop (or of a feed that was failing) is a baseline, so nothing in it counts as new; a feed read as a sliding window of a bigger collection is partial, and a product seen only there is never "new"; the "new" event counts what the snapshot keeps. - A campaign is "live" only inside its window and only when the shop's page or a campaign collection with discounted products shows it; a countdown, a newsletter promise or last year's page count for nothing. Each shop's state (live campaigns, announced windows, codes) is in the feed under `shops`. - Some shops block automated reading (Bike-Discount, BikeExchange, Decathlon, Buycycle, Jenson USA, Backcountry, Competitive Cyclist, Alltricks, Hibike, Orbea, Scott): they show the research (campaign windows, earlier-year discounts) but no live deals. - Sizes: shops that list bikes without variants have their product pages read once a day for the sizes in stock (Fahrrad XXL, Bikepalast, Canyon, Bike-Components, YT, Rose); `sizesFrom` says where a product's sizes came from (the listing, the product page or the name) and `none: true` means the page listed sizes and none was in stock. Frame sizes are one scale, S to 3XL; cm, inch and Specialized S1–S6 sizes are mapped onto it. ## Is the discount real? - A shop's "−44%" is against its RRP. Every deal gets a reference price from before the campaign and a verdict (`real`): the shop's own "lowest price of the previous 30 days" where the product page prints it (an EU Omnibus rule; Rose and Canyon do), otherwise the price when the tracker first saw the product. `real.verdict`: `real` = at least 5% under the reference (a genuine new cut), `same` = within 5% (not a campaign cut, though it can still be a fair price), `up` = above it (the price rose since), `new` = seen for the first time. - Bikes also get the second-hand market as context (`used`): Marktplaats asking prices for the model (count, lowest, median). Never a reason to wait on its own. ## Buy now or wait? - Every deal gets one verdict (`signal.v`) with the fact codes behind it (`signal.r`, the headline first): - `buy` ("Buy now"): a real cut plus a reason not to wait: one size left (bikes and gear), the cheapest of the shops listing a comparable build, close to second-hand asking prices, at the level the shop reached in earlier years, dropped to its lowest price in our history, or the Black Friday weekend is here. - `good` ("Good price"): a real cut, or the shop's campaign price, with nothing concrete saying a better price is coming; waiting is a gamble, not a plan. - `wait` ("Wait"): a concrete reason to expect better: the price went up against its reference, another shop in the same region lists a comparable build at least 3% cheaper, the shop's own campaign is announced or confirmed and not live yet, or a quiet shop that went to 30% or more in earlier years has not shown yet before Black Friday. - `early` ("Too early to say"): under two days of history, or no reference price at all, and no hard fact either way. - The decision order, first match wins: a price that went up is a wait whatever else is true; cheaper elsewhere beats the shop's own facts unless the item is scarce; the shop's campaign ahead beats everything except a real cut with one size left; then too early / no history; then a real cut (buy with a strong reason, good without); then an unchanged price: good at a live shop, wait at a quiet shop with a deep earlier-year record before 27 November, good otherwise. - Fact codes: up, cheaper, ahead, early, nohist, real, scarce, cheapest, used, peak, headroom, low, altAhead, camp-price, noshow, peakdays, late, flat, popular. `alt` is the cross-shop view for bikes: other same-region shops with a comparable build (RRP within ±12%), the cheapest and its distance in percent. - Deliberately not shown: predicted prices or "expect another −10%", a per-shop "will take part" guess beyond the facts, cross-region price comparisons, second-hand prices as a reason to wait, click counts as a verdict, charts or scores. Earlier years are quoted as "up to", never as a forecast for a product. ## The JSON feed - [https://mtbdeals.co/api/deals](https://mtbdeals.co/api/deals): the full snapshot the app reads. Public, read-only, no key, GET only, JSON (about 2.3 MB raw, 300 KB compressed; fetch it server-side, there are no CORS headers), cached five minutes at the edge, written by the scan at every even UTC hour. https://mtbdeals.co/api/deals?head=1 is the first page of the default list (48 deals with the shop states, about 70 KB raw). - Top level: `v`, `checkedAt` (the time of the scan it holds), `nextCheckAt`, `shops` (per shop id: live campaigns, announced windows, codes, what the scanner saw), `products`, `market` (the site-wide read: phase, live shops, bikes with a real cut), `health`, `alerts`. - A product: `id` (`:`, the key in share links), `shop`, `title`, `brand`, `url` (the shop's product page, no affiliate parameters), `img` (the shop's photo, a CDN base URL), `price`, `was`, `cur` (EUR, GBP or USD), `pct`, `cat` (mtb = MTB, emtb = e-MTB, parts = Parts, gear = Gear & apparel, gravel = Gravel & road, ebike = Other e-bikes, bike = Other bikes), `ride` (xc, trail, enduro, dh, dirt), `frame` (fs, ht), `wheels`, `sizes` with `sizesFrom`, `camp`, `first`, `low`, `prev`, `h` (recent price points), `real`, `used`, `alt`, `signal`, `hot` (opened often here in the last two days). ## URLs - The app and its hash routes: https://mtbdeals.co/, https://mtbdeals.co/#deals, https://mtbdeals.co/#deals/, https://mtbdeals.co/#deal=, https://mtbdeals.co/#shops, https://mtbdeals.co/#calendar. - Filter keys (the same string after #deals/ and after list?): shop=, regions=EU,UK,US, cats=mtb|emtb|parts|gear|gravel|ebike|bike, brands=Cube,Scott, sizes=S,M,L,XL,XXL,3XL, wheels=29,mx,27.5, rides=xc|trail|enduro|dh|dirt, frames=fs|ht, sig=buy,good,wait,early, max=, min=, q=, camp=, new=1, real=1, strict=1, sort=best|pct|save|popular|low|high|new|real|signal. - One deal, shareable: https://mtbdeals.co/d/ (the id URL-encoded). A link expander gets the title with the price, the cut and the shop, the verdict as the description, the card below as the image and a schema.org Product/Offer; a person gets the deal as a page (photo, price, the recorded price points, the verdict and its reason, sizes in stock, the shop's own link) with an "Open in the app" link to https://mtbdeals.co/#deal=. Indexable. - The season's pages, rendered from the live snapshot on every request (cached five minutes at the edge): https://mtbdeals.co/black-friday-mountainbike-2026/ (the main page), https://mtbdeals.co/shop// (every shop: its live deals, campaign dates and earlier-year record), https://mtbdeals.co/brand// (brands with three or more deals in the default list), https://mtbdeals.co/category//, https://mtbdeals.co/calendar/ (the campaign window of every shop, as schema.org SaleEvents) and https://mtbdeals.co/faq/. Each opens with a two-sentence answer from the data (campaign start, how many deals are below their pre-campaign price, the median real cut), lists the first 48 deals as a schema.org ItemList and links the app at the same filter. - A filtered list, shareable: https://mtbdeals.co/list?. The count in the title, the top deals as the description, the list card as the image, an ItemList of the first ten; a person is sent on to https://mtbdeals.co/#deals/. noindex. - The share cards: https://mtbdeals.co/og/.png (the photo on a white panel, the price, the discount badge, the verdict) and https://mtbdeals.co/og/list.png?, 1200×630 PNG, composed from the live snapshot, cached an hour. - Static: https://mtbdeals.co/about/, https://mtbdeals.co/privacy/, https://mtbdeals.co/faq/, https://mtbdeals.co/llms.txt, https://mtbdeals.co/robots.txt, https://mtbdeals.co/manifest.webmanifest, https://mtbdeals.co/og.png (the site's card). https://mtbdeals.co/sitemap.xml is served live from the snapshot: the pages above plus the 500 biggest discounts as /d/ pages, each with the date of its last price change as lastmod. ## Independence and privacy - No affiliate links, no sponsored placements, no ads, no trackers, no cookies, no analytics. Product links are the shops' own URLs. Outbound clicks are counted anonymously per deal (the "Popular" badge); nothing else is recorded about a visitor. Details: https://mtbdeals.co/privacy/. - Email alerts are double opt-in; an account is an email address; unsubscribing or deleting the account removes the record. - The shop's checkout is what counts: UK and US shops may add shipping, duty and VAT for the Netherlands. ## The 60 shops - EU: Canyon, Rose Bikes, Radon, Specialized, Trek, Giant, Bikester.nl, 12GoBiking, Bike24, Bike-Discount, Fahrrad XXL, Mantel, Mount7, BikeExchange, Decathlon, Buycycle, Bike-Components, Fahrrad.de, Liquid-Life, Bike-Mailorder, Probikeshop, Propain, YT Industries, Thok, Bikepalast, Futurumshop, Alltricks, Hibike, Bikeinn (Tradeinn), Commencal, Cannondale, Orbea, Scott, BMC, Kona, Zweirad Stadler, Rabe Bike, B.O.C., Mammoth Bikes, Bike Totaal / Profile, Nr1 MTB Shop, Purebike. - UK: Tredz, Chain Reaction / Wiggle, Biketart, Go Outdoors, Tweeks Cycles, Auto Trader (e-MTB), Sigma Sports, Merlin Cycles, Leisure Lakes Bikes. - US: Jenson USA, evo, Backcountry, Competitive Cyclist, BikesOnline, Ari Bikes, Bikemart, Mike's Bikes, REI. - Shop ids, regions, delivery to the Netherlands, campaign windows and earlier-year discounts: https://mtbdeals.co/#shops and the `shops` object of the feed.