How Deals and Price History Work

SexToysDB tracks retailer offers separately from the catalog’s stored list price. The /deals page and the price-check block on product pages only surface a “sale” when the numbers on file support it. We do not invent discounts, convert foreign currencies into fake USD bargains, or treat a $0 scrape as a free product.

Two different price ideas

Catalog list (price_usd_min / display)

A catalog baseline we store on the product — typically from manufacturer or import data when the listing was built or updated. It is useful as a reference “list” level. It is not guaranteed to be the current street price everywhere, and it does not auto-rewrite every time a retailer runs a promo.

Live offers

Rows in our offers table: a retailer, a URL, a price (when we have one in USD), optional stock signal, and last checked time. Product pages can show multiple offers. Deals and “vs list” math use these live prices, not a hand-edited sale badge.

If there is no live-priced offer yet, you will not see a manufactured deal card. Coverage grows as offers are added and the checker runs.

How a “drop” is detected

On /deals we compare each live offer price to the product’s catalog list (price_usd_min):

  • Below list only when live price is under catalog list and we can compute a percent drop.
  • We highlight drops at about 5% or more vs list. Smaller gaps stay in the broader “live prices” set without a dramatic sale framing.
  • Cards show retailer, last checked, and stock when known. “vs list” copy is omitted when catalog list is missing or the live price is not actually lower.

That is intentionally conservative. A retailer price above list is still a live price worth showing; it is not a “deal.”

Price history (what the checker records)

A scheduled price check re-fetches offer pages (about every six hours in normal operation), reads structured price/availability when present, and updates the offer.

History behavior in plain terms:

  • A price_history point is stored when there is a real change worth recording — not a row spam on every identical recheck.
  • USD only for numeric price_usd. Non-USD prices are not converted with a made-up FX rate.
  • Zero or negative scraped prices are rejected. Multi-offer product pages sometimes expose a $0 accessory or gift-card node; we treat that as “could not determine,” not a flash freebie.
  • Failed fetches rotate the offer’s check time so one blocked retailer does not monopolize the batch; they do not fabricate a new low.

On a product page, the price check insight may compare live price to catalog list and/or the high/low of recorded history. Wording stays cautious when history is short (“lowest we’ve recorded so far,” not “lowest ever on the internet”).

Honesty rules (read before trusting a red tag elsewhere)

We do We don’t
Show live offer price when scraped/stored Invent a % off from marketing strikethrough HTML we can’t verify
Say “below catalog list” when math says so Claim MSRP we never stored
Show last checked / sparse history caveats Promise the price won’t change after you click out
Keep affiliate links disclosed as sponsored where used Let commissions change the drop formula

Affiliate “View at store” links never change whether a drop qualifies. Specs and catalog scores are independent of deals.

How to use this as a shopper

  1. Open /deals for a cross-catalog snapshot of live prices and true-below-list rows.
  2. Open the product for multi-retailer offers, sparkline/history when present, and full specs.
  3. Treat catalog list as our baseline, live offer as what we last saw at that URL, history as what we’ve recorded over time — three related signals, not one magical “fair price.”
  4. For budget browsing without a sale claim, use facets like under $50 and guides such as how much to spend.

Bottom line

Deals on SexToysDB mean live offer vs data we actually hold, refreshed by automation with boring edge cases handled in code. If the checker has not run or coverage is thin, the honest UI is empty or plain — not a fake countdown timer.

Related reading