Skip to your basket
Get 10% off your first order - use code FIRST10
0

Your basket

Review tool — not part of the design

    Your basket is empty

    Nothing in here yet. Every Hayati range runs a multibuy — the seven live offers are below.

    New here? FIRST10 takes 10% off anything not already on a multibuy, and delivery is free on UK orders £30 and over.

    Every Hayati multibuy

    All seven live offers, each on its own page. Pods, kits, nic salts and refills — mix flavours within an offer.

    Each tile shows one product that carries the offer and what the offer saves against that product’s own price. The offers run wider than the tiles show.

    Have a coupon?

    Spend your points

    Your points balance lives in your account. Sign in to see it and spend it on this order. You earn 5 points for every £1 you spend.

    Goes with your basket

    Continue shopping

    Total Proceed to checkout
    Data provenance
    ElementSource
    Products, prices, images, stock stateReal — the live /brand/hayati/ archive
    Multibuy offers on each itemReal — each product’s own hv-deal-tag, read off the live archive. Offers vary by format as well as range
    What is in the basketIllustrative. You cannot crawl a stranger’s cart. The products, prices and offers are real; the choice of what is sitting in the basket is ours, picked to show the mechanics. Use the review tool at the top to move between states
    The empty basketReal routes throughout. The six range tiles are the live top-level nav (brand/nav.json), each on its own live URL; the seven offer tiles are the live HAYATI DEALS menu, each on its own /deal/multibuy-…/ page. FIRST10 and the £30 threshold are the live promo bar and delivery strip. Which product stands for which range, and which stands for each offer, is our choice — the offer tile shows the product in our crawl that gets the most out of that offer
    “Save £x” on an offer tileDerived, not quoted: that product’s own price against the offer price, both real. Claimed only where the offer actually saves money. On the Mini Ultra kit, “5 for £20” costs 5p more than five singles at £3.99, so that tile claims nothing and says so. A question for Hayati
    Delivery services and pricesReal — the live shipping table (Tracked 48 £2.95, Tracked 24 £3.95, DPD Express £7.95, Special Next Day £8.95)
    Which delivery service becomes freeReal, and no longer an assumption — the live shipping page says “Free Royal Mail Tracked 48. All orders of £30 and above are sent via Free Royal Mail Tracked 48”
    The 4pm dispatch cut-off, and the returns windowReal — the live shipping page (“Same-day dispatch is available for orders placed before 4 PM (Monday - Friday)”, Friday after 4pm dispatches the following Monday, none on Bank Holidays) and the live returns policy (“within 14 days of making their purchase”, authorised by support first, unopened and unused). Both were in the crawl and neither was on the page
    The dispatch countdownReal rule, live clock. The shipping page and the FAQ both say: same-day dispatch before 4pm Monday to Friday, orders after 4pm on Friday dispatch the following Monday, no dispatches on Bank Holidays. The countdown applies that rule to the browser’s clock, with Bank Holidays taken from GOV.UK’s England and Wales list (published free, runs to 26 December 2028)
    The trust strip’s dispatch lineThe live strip reads “Ordered by 4pm, sent today” with no weekday on it. On a Saturday that sits directly above a live dispatch line reading “dispatched Monday”. Mon–Fri has been added — the qualifier is on Hayati’s own shipping page, so this completes the client’s copy rather than replacing it. The only change to a verified brand string in this build
    Payment methodsReal — the live checkout’s payment step reads Pay with Card (Worldpay), recorded in the checkout brief, and the FAQ adds that payments are “secure and encrypted”. Worldpay card payment is the only method Hayati has — no Apple Pay, Google Pay, PayPal or Klarna, and Hayati have confirmed express checkout is a potential future upgrade rather than a current option. No card or wallet marks are drawn: five of the six benchmarked competitors show them and we are not borrowing theirs. Adding wallets remains the single highest-value change the checkout brief names
    Two contradictions on the live siteThe FAQ still carries unedited template answers: free delivery “over a certain amount (e.g. £20 / £25)” and a “cutoff time (e.g. 3 pm)”, both of which contradict the shipping page’s real £30 and 4pm in the same site. This build uses the shipping page. Worth fixing at source
    Delivery table row orderThe live table lists Special Next Day (£8.95) above DPD Express (£7.95); the delivery choices here are price-ascending. The table’s rows are sorted to match so the two lists on one screen agree. Only the order changes — every service, price, speed and note is the live cell
    Delivery dates on this pageNew here. The basket offered four bare radios and the checkout four dated cards, for the same four services, so the customer chose delivery twice and had less to go on the first time. Both now use one shared table and one shared date rule (build/shipping.py, build/dates.py)
    Crossing the 4pm cut-off mid-sessionEvery quoted date moves. This page did not move them at all — its dates were written only inside a full re-render, which the 30-second tick does not trigger — so it would have announced a change it had not made. Both pages now move them and say so
    The offer stripCollapsed to one line by default, opening on demand. Six product cards under every basket line buried the basket itself. The offer still announces itself, with the money, the progress and the count of what is behind it
    What is still not on this pageSave for later and a low-stock signal. Both need data we do not have: the first needs an account session, the second needs per-product stock counts (WooCommerce has them — one product’s PDP shows stock: 23 — but the archive only exposes in/out of stock). Neither is invented to fill the gap
    Out-of-stock linesKept out of the subtotal, the total and the free-delivery bar, grouped separately, and they block checkout. The earlier build charged them into all three while telling the customer they would be removed — a total the customer could not trust, and the one thing cart and checkout have to agree on
    What an offer strip is worthDerived from what is actually on the shelf under it, not from the best case. It used to quote the dearest qualifying product — “saving up to £1.97” — over a shelf that also offered cheaper ones and another of your own line at £1.47. The strip now gives the range, and where one more item completes the offer each card carries its own figure. A strip is shown only where the offer beats buying singly — the Mini Ultra “5 for £20” never appears
    The free-delivery shelfDerived per tile, by pricing the basket that would result rather than dividing the gap by a shelf price. The header used to take one count off the dearest product and print it over four tiles at four different prices — “Three of these take you there” was false for three of the four. Counting in unit prices is wrong in 352 catalogue cases besides: three of something carrying a “3 for £15” badge adds £15, not £23.97, and the customer arrives short of the threshold they were promised
    The subtotal the £30 threshold is read onNow printed. The edge basket shows £30.42 of goods over “£5.00 to free delivery”, and the number reconciling them — £25.00 after the multibuy saving — appeared nowhere on either page
    “This basket has saved you”Derived arithmetic on real numbers, and every part of it is now printed above it: the multibuy saving, any coupon, and any waived delivery charge. Waived delivery used to be folded into this figure silently, so the summary showed “saved you £6.93” over a single “−£3.98” row. Delivery is now charged at £2.95 and credited back on its own line
    FIRST10 on a multibuyIt does not stack. Hayati confirmed the code must not come off an item that is already on a multibuy, so the discount is worked out on the part of the basket no offer has discounted — unit by unit, not line by line, since four items against a “3 for £15” offer are three discounted units and one at full price. Where that is less than the subtotal, the summary names the amount. Where it is nothing, the page says the code takes nothing off rather than leaving the customer to wonder why no number moved
    “See N other <flavour> options”Real — a count of the in-stock products in our 24-product crawl sharing that flavour. The demo’s link is not filtered to them; the live site would filter
    Free delivery thresholdReal — “Free delivery on UK orders £30 and over”. Calculated here on the discounted subtotal, after any multibuy saving. Which side of the discount the live site calculates on is an open question, and cart and checkout must agree — one benchmarked competitor gets this wrong and drops qualifying baskets below the threshold at checkout
    “Offers drop it under £30”A real edge the brief warns about, now a state you can switch to. That basket is £30.42 before the offers and £25.00 after them, so which side of the discount the threshold is read on decides whether delivery is free. This build reads it after, on both cart and checkout, and the gate compares the two pages on this basket
    The penceEvery figure is derived by summing the pence that are actually printed, not by apportioning a float and rounding at the end. Both templates import one priceBasket() (build/pricing.py) that works in integer pence and hands out a chunk’s saving by largest remainder, so the line prices a customer reads always add up to the subtotal underneath them. The earlier build drifted a penny on real baskets — the same defect as the live site’s £5.00 line under a £5.49 subtotal. build/arith.js checks 391,782 baskets against the real catalogue on every gate run
    CouponsFIRST10 is real — the live promo bar. One implementation for both pages. A code that is not recognised no longer removes the one already applied, the discount is rounded to pence, and the threshold is read before it
    Multibuy arithmeticDerived: the basket is grouped by offer and charged in chunks of n, dearest first. Whether the live site applies multibuy automatically at basket level or needs a coupon is an open question
    Desktop layoutResolved from the live stylesheet rather than guessed: .cart-content-wrapper is a flex row from 1025px with the items at flex:1 0 0 and the totals at flex:.7 0 0, tightening to .5 at 1200px. This build matches those breakpoints
    “Add a points”The live label, grammatically broken, is confirmed in the page source. Fixed here to “Spend your points”
    The loyalty bannerReal copy — “PLACE AN ORDER AND EARN 5 REWARD POINTS FOR EACH £1 SPENT”. Kept, moved out of a full-width crimson band above the basket contents
    Nav, footer, logo, palette, typeReal — verbatim from the live site
    What the demo does not doEvery item links to the same product page. Proceed to checkout carries the basket and the delivery choice through to checkout.html, the other template in this package. Quantities, removals, offers, delivery choice, the progress bar and the totals are all live
    HubCategoryPrefilled pod kitNic salt e-liquidRefillable pod kitNicotine pouchesCartCheckout