How this was made, and what it cannot prove.
Everything on these pages traces to a public page fetched on 22 Oct 2026, a vendor document with a URL, or a calculation whose code ships in the pack. Where something is inferred or proposed, it says so next to the claim.
Five kinds of statement.
Each page uses the same chips. A number without a chip near it is a public observation from the capture.
| Public observation | Read from a public page, the HTML it served, or the GraphQL responses the shoppure.com menu itself requests. Dated. Reproducible with the scripts in the pack. |
| Vendor documentation | Dutchie, Weedmaps or Leafly’s own published pages, fetched 22 Oct 2026, URL listed below. Paraphrased; at most one short quote per source. |
| Modelled / reasoned | A count computed by a stated rule (the ten checks), or an inference from documented behaviour. The rule and its false-positive risk are stated. |
| Proposed | A change, a measurement or a timeline that has not been applied or measured. Nothing on this site reports an outcome. |
| Requires access | Knowable only from inside Pure’s WordPress, Dutchie, POS, Weedmaps or Search Console. Listed so the first conversation starts with the right questions. |
What was collected, and how.
On 22 Oct 2026 (21:40–21:45 Detroit time) the five store menus were read through the same persisted GraphQL queries the shoppure.com page issues — FilteredProducts, FilteredSpecials, MenuFiltersV2 — as plain GET requests with no login, no cookies and no age-gate interaction. The responses are saved verbatim with SHA-256 hashes in data/raw/manifest.json.
Pages for the entry and visibility sections were fetched with curl using a standard browser user agent, saved, and re-checked for HTTP status without following redirects. Weedmaps and Leafly listings were fetched the same day; what could not be fetched is listed as such.
| Dataset | Rows | Notes |
|---|---|---|
| Products (five stores) | 5,388 | API reported 5,429; the difference is items that appeared or sold out between pages. Every row has a Dutchie id and POS metadata. |
| Current specials | 355 | With display name, description, image flag, type, start and end stamps, platforms, source. |
| Brand-filter entries | 1,264 (472 distinct) | From each store’s MenuFiltersV2.brands. |
| Store links on four WordPress pages | 67 | href and HTTP status, 22 Oct 2026. |
| Served HTML, five flower pages | 5 | Title, description, canonical, robots, byte size, visible text, product links, JSON-LD. |
| Sample shipped to the browser | 688 | Stratified by store and category, plus the five records named in the text. Labelled as a sample wherever it appears; the full capture is in the CSV pack. |
One rule per check, the same in Python and in the browser.
Severity A fires on content that is wrong under any naming standard. Severity B fires on patterns that become wrong once the standard is chosen; they are counted as “review”. Both are tested against known records in tools/tests.mjs.
| Check | Sev. | Fires when | Known false positives |
|---|---|---|---|
| tier-in-brand | A | Brand contains “Tier”, “VIP”, “Private Reserve”, “Reserve”. | A maker literally named “Reserve”. None in the capture. |
| price-in-brand | A | Brand contains “$” followed by a digit. | None. |
| code-in-name | A | A standalone number of 3+ digits not followed by a unit (mg, g, ml, pk, ct, %). | Strain names with numbers (“Gelato 41” is two digits and passes; a hypothetical “Strain 420” would fire). |
| strain-type-missing | A | Flower, pre-roll, vape or concentrate with strain type empty or “N/A”. | Accessories bundled under an inhalable category. |
| whitespace · all-caps | A | Double or stray spaces; names in capitals longer than six characters. | Brand names that are acronyms. |
| size-or-form-in-brand | B | Brand contains a weight, a pack word, or a product-form word (cart, dispo, gummies, rosin…). | Makers whose name is a form word (“Chill Topical”, “Mary Jones Soda”, “Swisher Blunts”). Expect roughly one in ten flags to be a legitimate sub-line; the planner labels these “review”. |
| brand-missing-or-house-label | B | Brand empty, or “Deli”, “Pure”, “Store Merch”, accessory bins. | House products where “Pure” is the honest maker — the standard keeps those. |
| strain-in-name | B | “(H)”, “(I)”, “(S)”, “- Hybrid”, “- Indica/Hybrid”, trailing “Hybrid/Indica/Sativa”. | A strain actually named “Sativa Something”. None seen. |
| format-prefix-in-name | B | Name starts “Deli - ” or “<Maker> Prepack … - ”. | None by design; the prefix is always redundant with brand + category. |
Cross-store matching uses Dutchie’s enterpriseProductId, present on 5,367 of 5,388 records. Specials checks: description empty, shorthand tokens in the name, no image, ending within 48 hours of the capture.
Three decisions, three downsides.
Alternatives: start with the record standard (biggest), or with deals (fastest to sell). Constraint: the record work needs the inventory team; the entry fix needs only WordPress. Chosen: entry first, because it is the only change that is entirely in the website owner’s hands and it is where shoppers are lost before any record matters. Downside: it is the least visible improvement to management. What would change it: if Pure already has a header fix scheduled, start with deals.
Alternatives: tag/sub-category, name suffix, drop. Constraint: the deli counter must stay browsable by tier. Chosen: tag. Downside: depends on the POS exposing a tag to the menu. What would change it: the inventory lead confirming no such field exists → use the suffix; or Pure deciding tiers are internal → drop.
Alternatives: ship every record (1.5 MB) or a sample. Constraint: the Record Lens must load on a phone. Chosen: a stratified sample for the interactive tools, with every aggregate computed over the full capture and the full data in the pack. Downside: the batch generator ranks within the sample. What would change it: a request to run the lens over the whole capture — the Python tool already does.
What this is, and what it cannot prove.
What this is: an independent, uninvited study of a public website, built to show how I work. Pure Cannabis Outlet did not ask for it, see it in advance, or approve it. No private data was accessed; no account was created; no purchase was attempted.
What the data is: the public menu and public pages as they were on 22 Oct 2026. Menus change daily; specials change weekly. Counts here are a snapshot, not a trend.
- Which POS Pure runs and whether the five stores share an item master. The LeafLogix storage URLs point to Dutchie POS; that is an inference.
- Who owns product naming today, and whether a convention exists on paper.
- Any effect on sales, conversion, support calls or search traffic. None is claimed anywhere on this site.
- Whether Google has indexed the rendered menus (Search Console).
- Whether the Weedmaps “happy hour” card and the store banners are current — they carried dates, some already past, but the people who typed them were not asked.
- The two Leafly profiles that could not be found may exist under other names.
Every page this study leans on.
Pure Cannabis public pages public observation
- shoppure.com homepage; /locations; /loyalty; /mi/warren/; robots.txt; sitemap_index.xml, page-sitemap.xml, post-sitemap.xml.
- Dutchie menu routes on shoppure.com:
/stores/{pure-dixie-monroe-rec, pure-chesterfield-new-baltimore-rec, pure-new-buffalo, pure-oxford-rec, pure-warren-rec}/with/products/flower,/products/concetrates,/products/vapes,/brands,/specials; and the empty-slug variants/stores//…. - GraphQL:
https://shoppure.com/api-1/graphql, operations FilteredProducts, FilteredSpecials, MenuFiltersV2 (persisted-query hashes recorded intools/capture.py). - Weedmaps listings: Warren, Monroe, New Baltimore, Oxford, New Buffalo.
- Leafly profiles: Monroe, Oxford, New Baltimore; Warren and New Buffalo not found on leafly.com/dispensaries/michigan/warren or …/new-buffalo.
Dutchie vendor documentation
- Discount Sync V2: specials managed in POS Backoffice, “Available on eCommerce”, per-discount menu design
- Ecommerce “View Menu Design” becomes read-only under V2
- Strain- and vendor-restricted discounts sync under V2
- Future-dated POS discounts show as Pending
- POS categories as the source of truth; separate “Online title”
- LeafLogix inventory sync every 60 seconds
- Specials card badges and the countdown toggle; redesigned Specials page; “Hide all discount promotions” setting
- Embed SDK overview and menus and carousels; Dutchie SEO page.
- Not read (bot check on 22 Oct): Dutchie Help Center “E-Commerce SEO: frequently asked questions” and “Set up a custom domain”.
Weedmaps and Leafly vendor documentation
- Weedmaps: multiple menus; POS integration; Dutchie integration guide; where to edit menu items; sale pricing vs deals; creating and scheduling deals; in-person deals; expired promo codes; deleting a deal.
- Leafly: Menu Manager; plan tiers; POS connection (Headset partner guide); consumer deals disclaimer. Not read: Leafly Help Center deal-creation articles (loading shell).
Michigan rules primary sources
- Marihuana Rules R 420.1–R 420.1004 (LARA): R 420.507 marketing and advertising (subsection 2: no deceptive, false or misleading advertising); R 420.506(3): 2.5 oz per transaction, not more than 15 g concentrate. Also at LII R 420.507.
- MCL 333.27955 (MRTMA §5). No rule in the compilation addresses advertised-price accuracy specifically.
- CRA laws, rules and resources.
Design references viewed 22 Oct 2026
Directive: PURE field notes (my own earlier study; palette, type and the FIG. labelling carry over; the layout here is new). References studied: The Surfer’s Journal Archives (oversized corner numerals, one colour field per item), Oath Biome (scientific-editorial serif, evidence before claims), Maison Les Grands Chênes (figure numbering, mono eyebrows, calm reading pace). Found through SiteInspire’s minimal category. Nothing was copied; the specimen-tag device and fragment colouring are original to this study.
The workbook and the pack.
Two files. The workbook is for the person who will run the audit and the deal sheet; the pack is for whoever wants to re-run or check the study.
Sizes and checksums are listed in downloads/CHECKSUMS.txt.
| Workbook sheet | What it holds |
|---|---|
| README | How to use it, where numbers come from, what is a sample. |
| Naming standard | One rule per field, with examples from the capture. |
| Scorecard | Five stores × ten checks, computed with COUNTIFS formulas over the Record audit sheet (live, not pasted). |
| Record audit (sample) | 688 sampled records with every check as a column and a severity score. |
| Rename list (demo) | 25 records ranked by severity with proposed name, brand, strain, tier, POS fields, decision, owner, done. |
| Rename list (blank) | The same columns, empty, with the scoring formula in place. |
| Cross-store | 40 enterprise products named or branded differently across stores. |
| Specials (all) | 355 current specials with the four specials checks. |
| Deal sheet (template) | The weekly sheet: one row per discount, surfaces, last checked, checked by. |
| Entry links | All 67 store links on four pages with HTTP status. |
| QA checklist · Decision log · Sources | Pass conditions per section; decisions with tradeoffs; every URL with its date. |
The pack: data/raw/ (verbatim API responses, HTML, manifest with hashes), data/export/ (records-all.csv, specials-all.csv, brands-all.csv), tools/ (capture.py, entry_links.py, analyze.py, make_leaf.py, build_workbook.py, tests.mjs) and a README.
Three engagements, in the order they should run.
Question: can every header and footer link reach the right shelf for the shopper’s store?
Needs: an editor login to WordPress/Breakdance; a 20-minute call on how the store choice is stored.
You get: a store-aware header, two corrected slugs, one address per store with the sitemap decision written down, and the link check re-run with zero 404s.
Excluded: any change inside the Dutchie embed; design changes.
Price: outside my fixed menu, so by the hour — $75/hour, $300 minimum, written scope first. proposal
Question: does every live deal say the same thing on shoppure.com, Dutchie and Weedmaps?
Needs: one deal sheet (or this week’s discount export), a WordPress editor login, Weedmaps read access or screenshots.
You get: a real /deals/ page from one sheet, a dated accuracy check with the mismatch list, expired deals removed, a last-checked stamp, a weekly template and a one-page how-to.
Excluded: edits in the POS, Dutchie or Weedmaps admin; Leafly claiming; compliance review of claims.
Price: $450 fixed for one deals page from one deal sheet, half up front and the balance on delivery; five stores get a written quote first — the terms of my published service.
Question: which POS fields carry what, and in what order do we rename 5,388 records across five stores?
Needs: a 30-minute call with whoever keys products into the POS; an export of the item master (or confirmation the chain shares one); the decision on tier placement.
You get: the naming standard signed off, the full audit over the current menu, a ranked rename list by store with POS fields per row, and the re-check run after the first batch.
Excluded: doing the renames in the POS (Pure’s admin, Pure’s staff); product photography; copywriting.
Price: quoted in writing after the call; $75/hour, $300 minimum. proposal
How you would know any of it was useful: each engagement ends with the same check that opens its page on this site — the link check at zero 404s, ten deals verified against the live menu, the re-check tool showing A-checks at zero for the batch. If the check does not pass, the work is not done.
Mousa Batarseh
E-commerce specialist in Warren, Michigan. Seven years running multi-SKU storefronts: two Shopify and WordPress stores for a wholesaler and its textile brand in parallel, with catalogs past 14,000 SKUs, platform migrations with redirect maps, and promotion calendars; then the corporate sites and wholesale B2B store of a multi-location tobacco retailer — catalog, inventory, pricing, descriptions, imagery, campaign pages. Since mid-2025, independent: WordPress, WooCommerce and Shopify builds, bilingual Arabic/English sites, and my own catalog tools — a CSV mapper and import checker, a storefront scoring rubric, a cutover checker.
Bachelor’s in Accounting Information Systems. The credentials that matter here are in the method: the capture, the checks and the tests are on this site to be read.
- Reading a menu platform from its public API and HTML rather than from screenshots.
- Writing field-level data rules that a non-technical team can apply, with their false positives named.
- Separating the website owner’s levers (templates, pages, sitemap) from the inventory team’s (the item master) and the vendors’ (sync).
- Building the measurement before proposing the change.
Why it looks like this.
Art direction
A botanist’s field notebook applied to data: deep green ground, cream paper, lime for what is alive, numbered figures, and a specimen tag for every record. The subject of the study is a text field, so the hero figure is the one thing on the site that is not a text field.
One device, carried through
The specimen tag (a framed label with a header row and a footer row) holds the leaf, each tool’s result, every evidence figure, and the workbook’s layout. Fragments inside a record are coloured by the field they belong to, the same ten colours on every page and in the workbook legend.
Type
Aclonica for headings (display, one weight), Instrument Serif italic for the one emphasised phrase per heading, IBM Plex Sans 17px/1.6 for reading, IBM Plex Mono 12–13px for labels and codes, Barlow Condensed for large numerals. All SIL Open Font License, self-hosted. Scale: 17 → 20 (lead) → 1.3rem → clamp(1.85–2.9rem) → clamp(2.5–5.1rem). Reading width 56–68 characters.
Colour
Ink #14251C, paper #F1F0E6, lime #CDF478. Text on ink is cream (contrast 14:1); lime on ink 12:1; ink on lime 12:1. Fragment colours all carry ink text at 7:1 or better.
Grid and rhythm
1200px maximum, 12-column grid with 5/7 and 7/5 splits, gutters 16–48px, section rhythm 96px (64px tight). Mobile collapses to one column at 980px and 640px; tables scroll inside their frame.
Motion
The hero leaf unfolds and draws its veins on arrival and turns with the scroll; the footer leaf draws, fills and sways when it comes into view. Paragraphs rise 26px and sharpen from a blur, then brighten near the middle of the screen and dim slightly away from it. Cards, rows and bars enter in sequence, figures count up, the shorter of two columns follows the scroll, and a faint smoke layer drifts behind everything. “Pause motion” in the header stops all of it and remembers the choice; prefers-reduced-motion disables it without asking. Native scrolling throughout. Borders are four-sided or absent.
Tested before publishing.
- Loading…
- Loading…