[{"data":1,"prerenderedAt":227},["ShallowReactive",2],{"learn-lesson-matching-products-across-sites-variants-bundles-and-multipacks":3},{"course":4,"lesson":67,"index":194,"outline":195,"prev":225,"next":226},{"slug":5,"order":6,"level":7,"time":8,"card_text":9,"seo":10,"hero":16,"outcomes":26,"who":35,"syllabus":46,"faq":49,"lessonCount":66},"matching-products-across-sites",5,"You have data from more than one site","6 lessons, about 70 minutes","Collecting prices is the easy half. Deciding that this product on your site and that product on a competitor's are the same thing is where price monitoring actually succeeds or fails. Identifiers, fuzzy matching, variants, confidence scores and how to measure your match rate without flattering yourself.",{"title":11,"description":12,"keywords":13,"og_title":14,"og_description":15},"Matching Products Across Sites: A Free 6-Lesson Course","How to match the same product across different retailers. GTIN and EAN matching, fuzzy title matching, variants and multipacks, confidence scoring, review queues, and measuring match rate honestly. Free, ungated.","product matching, product data matching, gtin matching, ean barcode matching, fuzzy product matching, sku mapping, competitor price matching, product catalogue matching","A free course on matching the same product across different retailers","Six written lessons on product matching: identifiers first, fuzzy matching when there is no barcode, variants and multipacks, confidence scores and review queues.",{"badge":17,"title":18,"subtitle":19,"cta_primary":20,"cta_secondary":23},"Course five","Match the same product across different sites","A price comparison is a claim that two things are the same thing. Almost every disappointing price monitoring project fails here rather than at collection: the prices were fine and the matches were not. This course is about doing the matching properly — leaning on identifiers where they exist, being honest about confidence where they do not, and measuring the result in a way that does not flatter you.",{"label":21,"url":22},"Start with lesson one","/learn/matching-products-across-sites/why-matching-is-the-hard-part",{"label":24,"url":25},"See the data a run returns","/custom-scrapers",{"title":27,"items":28},"What you will be able to do",[29,30,31,32,33,34],"Explain why matching, not collection, is where price monitoring projects fail","Use GTIN, EAN, UPC and MPN correctly, including the checks that stop a bad identifier poisoning a match","Build a defensible fuzzy match for the majority of products that carry no usable barcode","Handle variants, bundles and multipacks without silently comparing a three-pack to a single unit","Attach a confidence score to every match and route the uncertain ones to a human","Measure your match rate with a denominator that tells the truth",{"title":36,"for_title":37,"for":38,"not_title":42,"not_for":43},"Who this is for","Written for",[39,40,41],"Pricing and e-commerce teams who have competitor data and cannot trust the comparisons","Developers building the matching layer and looking for the failure modes before they find them in production","Anyone evaluating a price monitoring vendor who wants to ask better questions than \"how many sites do you cover\"","Not written for",[44,45],"Teams who do not yet have data from more than one source — collection comes first, see course one or three","Anyone expecting a machine learning tutorial. The techniques here are mostly deterministic, because deterministic matches are the ones you can defend to a pricing manager.",{"title":47,"intro":48},"The six lessons","Lessons two and three are the mechanics. Lesson four is the one that catches most teams out, and lesson six is the one that stops you believing your own numbers.",{"badge":50,"title":51,"description":52,"items":53},"FAQ","Before you start","The questions that come up as soon as somebody looks closely at a match table.",[54,57,60,63],{"title":55,"description":56},"What match rate should I expect?","It depends almost entirely on the category, and anyone who quotes you a single number across all categories is not being careful. Electronics and groceries carry barcodes and match well. Fashion, furniture and bikes are hard because the same frame is sold under different model names with different component specs. We have seen a real project stall at 18% on bicycles, which was a correct measurement of a genuinely hard category rather than a broken system.",{"title":58,"description":59},"Can I just match on product title?","You can, and you will get a result that looks plausible and is wrong often enough to be dangerous. Lesson three is about doing it properly when there is no alternative, which there frequently is not. The important part is not the string algorithm — it is attaching a confidence score and refusing to auto-publish the weak ones.",{"title":61,"description":62},"Should a human be in the loop?","Yes, for the middle band. The strong matches do not need a person and the hopeless ones do not deserve one. The value of a review queue is entirely in how well you have sorted it, which is lesson five.",{"title":64,"description":65},"Is this specific to Scrapewise?","No. Lesson five mentions how we structure a review queue, and that lesson is labelled. The rest is method and applies to a spreadsheet, a Python script or any vendor's matching engine.",6,{"slug":68,"nav_title":69,"title":70,"summary":71,"time":72,"needs_account":73,"seo":74,"blocks":78,"takeaways":185,"next_step":190},"variants-bundles-and-multipacks","Variants and packs","Variants, bundles and multipacks","The highest-scoring wrong matches all live here. Normalising to a comparable unit, and knowing when two things are genuinely not comparable.","12 min",false,{"title":75,"description":76,"keywords":77},"Matching Product Variants, Bundles and Multipacks","Why pack size and variant differences produce the most dangerous false matches in price comparison, how to normalise to a unit price, and when to refuse to compare.","product variant matching, multipack price comparison, unit price normalisation, bundle pricing comparison, pack size data",[79,84,113,118,124,131,137,166,177],{"type":80,"paragraphs":81},"prose",[82,83],"Everything in the previous lesson can be done well and you will still produce confidently wrong matches, because the hardest cases are the ones where the titles genuinely almost agree. A six-pack and a single can. A drill with batteries and the same drill without. A 500ml bottle and a 750ml bottle of the identical product.","These are the matches that score highest and are most wrong, and they are the reason a price monitoring feed loses credibility in one afternoon.",{"type":85,"title":86,"headers":87,"rows":92},"table","The four shapes, and what each one requires",[88,89,90,91],"Shape","Example","Comparable?","What to do",[93,98,103,108],[94,95,96,97],"Multipack","6x330ml vs 1x330ml","Yes, per unit","Normalise to a unit price and compare that",[99,100,101,102],"Size variant","500ml vs 750ml of the same product","Per unit, with care","Unit price, but flag — bigger packs are priced differently on purpose",[104,105,106,107],"Non-price variant","Same shoe, different colour","Yes, directly","Treat as one product unless the price actually differs by colour",[109,110,111,112],"Bundle","Drill + case + 2 batteries vs drill body","No","Different products. Do not compare, and say why.",{"type":114,"variant":115,"title":116,"text":117},"callout","warning","The bundle row is not a normalisation problem","The first three rows can be solved with arithmetic. The fourth cannot. A kit and a bare body are different purchasable things and no unit conversion makes them comparable. The correct output is \"no match\", with a note. Teams that try to solve bundles by discounting the accessories are inventing a number, and an invented number in a price feed is worse than a gap in one.",{"type":80,"title":119,"paragraphs":120},"Normalise to a unit, and keep the raw value too",[121,122,123],"For packs and sizes the operation is mechanical: extract the pack count and the unit size from the title or the specifications, compute price per unit, and compare on that.","Two disciplines make this survive contact with reality. First, scrape the raw values and derive the unit price as a separate step, rather than trying to extract a computed value from the page. The page gives you price, currency and pack size; the division is yours. If you conflate them, a change in how the site formats its price becomes a change in your unit price with no visible cause.","Second, never discard the original. A pricing manager looking at a surprising row needs to see the shelf price and the pack size, not only the derived number. A unit price with no provenance is unauditable, and the first question anyone asks about a surprising comparison is \"what was the actual price on the page\".",{"type":125,"title":126,"intro":127,"language":128,"code":129,"caption":130},"code","Pack size extraction","Deliberately conservative. It returns nothing rather than guessing, because a wrong pack count is a wrong price.","python","import re\n\n# 6x330ml, 6 x 330 ml, 24-pack, pack of 12\nPACK = re.compile(\n    r\"(?:(\\d+)\\s*[x\\u00d7]\\s*(\\d+(?:[.,]\\d+)?)\\s*(ml|l|g|kg|cl))\"\n    r\"|(?:(\\d+)[\\s-]*pack)\"\n    r\"|(?:pack\\s+of\\s+(\\d+))\",\n    re.I,\n)\n\n\ndef pack_size(title: str):\n    \"\"\"Return (count, unit_size, unit) or None. None means ask a human.\"\"\"\n    m = PACK.search(title)\n    if not m:\n        return None\n    if m.group(1):\n        return int(m.group(1)), float(m.group(2).replace(\",\", \".\")), m.group(3).lower()\n    count = m.group(4) or m.group(5)\n    return int(count), None, None\n\n\ndef unit_price(price, title):\n    pack = pack_size(title)\n    if pack is None:\n        return None          # unknown pack size is not the same as a pack of one\n    return round(price / pack[0], 4)","The important line is the last return of None. Defaulting an unknown pack size to one is how a six-pack gets compared to a single can.",{"type":80,"title":132,"paragraphs":133},"Variants are a modelling decision, not a matching one",[134,135,136],"Retailers disagree about what a product is. One publishes a single page with a size selector; another publishes eleven separate pages. Your matcher sees one row on one side and eleven on the other, and no amount of string comparison resolves that, because the disagreement is structural.","Decide the grain explicitly and hold it everywhere. Matching at the variant level is correct when price genuinely varies by variant — clothing sizes, phone storage capacity. Matching at the parent level is correct when it does not — colour variants of the same shoe at one price.","The failure mode to avoid is being inconsistent, where some sources are matched at parent level and others at variant level. That inflates your match count and silently double-counts a competitor in any index you compute. We have seen a run return a hundred rows that covered only forty-four distinct URLs, for exactly this reason, and the row count looked healthy the whole time.",{"type":85,"title":138,"intro":139,"headers":140,"rows":145},"Worked example: four listings that all look like a 50% undercut","Each row is a competitor listing scoring highly against the same product of yours — a 6-pack of 500 ml bottles at €11.94, which is €0.398 per 100 ml. Three of the four become comparable once the arithmetic is done. The fourth is not comparable at any price, and no amount of normalisation will make it so.",[141,142,143,144],"Their listing","Their price","Per 100 ml","Verdict",[146,151,156,161],[147,148,149,150],"6 × 500 ml","€11.94","€0.398","identical — you are level",[152,153,154,155],"1 × 500 ml","€2.49","€0.498","comparable — they are 25% dearer per unit, not 79% cheaper",[157,158,159,160],"12 × 500 ml","€20.28","€0.338","comparable — genuinely 15% under you",[162,163,164,165],"Starter kit: 2 × 500 ml plus a dispenser","€14.99","not computable","no match, with a reason — the dispenser has no price of its own",{"type":167,"title":168,"intro":169,"items":170},"list","What usually goes wrong","Beyond the guards above, these are the decisions that let a pack-size problem reach a price.",[171,172,173,174,175,176],"Mixing grains across sources. If one competitor is tracked at variant level and another at parent level, the match count inflates and the same product is counted twice in every average you compute.","Storing the unit price and discarding the raw one. When a figure looks wrong, seeing both numbers side by side is the only way to separate a bad extraction from a bad conversion.","Letting the normalised figure move a price directly. A per-litre number is a comparison aid, not a shelf price; derive it, show it, and reprice from the comparison the rule actually intends.","Scraping a column with the same name as a derived one. A scraped unit_price blocks the rule meant to produce unit_price, and the rule then never runs — silently.","Treating \"no match\" as a failure to be engineered away. The starter-kit row is the correct output: unmatched with a reason is the only honest answer when one side includes something the other does not sell.","Falling back to headline price when the per-unit figure is unavailable. That second row reads as a 79% undercut and is in fact a 25% premium.",{"type":167,"title":178,"items":179},"Guards worth having before any of this reaches a dashboard",[180,181,182,183,184],"Refuse to compare when either side's pack size is unknown. Unknown is not one.","Flag any match where the pack counts differ by more than a factor of four, even after normalisation","Detect bundle words — kit, set, bundle, with, plus, includes, body only, bare tool — and require them to agree on both sides","Record pack count and unit size as their own columns, so a bad extraction is visible rather than baked into a derived number","Carry a provenance note on every normalised comparison so a surprising row can be audited in one click",[186,187,188,189],"The highest-scoring false matches are pack, variant and bundle cases, because the titles genuinely almost agree.","Packs and sizes normalise with arithmetic. Bundles do not — the honest output is no match plus a reason.","Scrape raw price, currency and pack size; derive the unit price separately and keep the original visible.","Pick a grain — variant level or parent level — and hold it across every source, or your match count inflates and double-counts.",{"text":191,"label":192,"url":193},"Next: what to do with everything that landed in the middle band.","Lesson 5: confidence scores and review queues","/learn/matching-products-across-sites/score-confidence-and-build-a-review-queue",3,[196,202,208,213,214,220],{"slug":197,"navTitle":198,"title":199,"summary":200,"time":201,"needsAccount":73},"why-matching-is-the-hard-part","Why matching is hard","Why matching is the hard part","The same object is described differently by every retailer that sells it, and the differences are not noise — they are deliberate.","10 min",{"slug":203,"navTitle":204,"title":205,"summary":206,"time":207,"needsAccount":73},"identifiers-first-gtin-ean-mpn","Identifiers first","Identifiers first: GTIN, EAN, UPC and MPN","What each identifier means, how to validate one before trusting it, and the three ways a correct-looking barcode still produces a wrong match.","11 min",{"slug":209,"navTitle":210,"title":211,"summary":212,"time":72,"needsAccount":73},"when-there-is-no-barcode","No barcode","Matching when there is no barcode","Normalisation, blocking, scoring on multiple signals, and why the string similarity algorithm matters far less than everyone assumes.",{"slug":68,"navTitle":69,"title":70,"summary":71,"time":72,"needsAccount":73},{"slug":215,"navTitle":216,"title":217,"summary":218,"time":207,"needsAccount":219},"score-confidence-and-build-a-review-queue","Confidence and review","Confidence scores and a review queue worth using","Why one score is not enough, how to set the two thresholds, and how to order a queue so an hour of human attention is worth having.",true,{"slug":221,"navTitle":222,"title":223,"summary":224,"time":207,"needsAccount":73},"measure-your-match-rate-honestly","Measure it honestly","Measure your match rate honestly","The denominator everyone picks is the flattering one. Precision, recall, a hand-labelled sample, and what to do with a number you do not like.",{"slug":209,"navTitle":210,"title":211,"summary":212,"time":72,"needsAccount":73},{"slug":215,"navTitle":216,"title":217,"summary":218,"time":207,"needsAccount":219},1791047867342]