CeX offered £136 cash for my £30 Pi case. It was quoting a different product.

python dev.to

My eBay pricing tool told me to stop. The listing I was about to put up, a used Argon ONE case for a Raspberry Pi, was apparently a mistake:

£79.32 is BELOW the £136 CeX would pay in cash today.
Selling it here loses money against simply trading it in.
Enter fullscreen mode Exit fullscreen mode

A £30 case, and CeX would give me £136 for it? No. CeX had never offered anything for that case. The number belonged to a Raspberry Pi 500+, and my own code had picked it up and presented it as advice about money.

That bug is why I've put the CeX part of that tool on GitHub as a small standalone library: cex-uk-prices. It is MIT-licensed, uses only the standard library, and has no account or key. Getting the prices is the easy part; this post is mostly about why the numbers can't be trusted as they come.

What it gives you

$python -m cexuk "Sony WH-1000XM4" --ask 60
CeX sells it for £170 (grade A) and pays £96 cash / £117 voucher

grade    sells    cash  voucher  stores  online  name
A       170.00   96.00   117.00       2       2  Sony WH-1000XM4 Wireless Noise-Canceling Headphone
B       145.00   82.00   100.00     173      30  Sony WH-1000XM4 Wireless Noise-Canceling Headphone
C       120.00   68.00    82.00      11      11  Sony WH-1000XM4 Wireless Noise-Canceling Headphone

UK stock: in 188 store(s), 62 online
CeX raised it £160 → £170 on 29 Jul 2026
£60.00 is below the £96 CeX would pay in cash today. Selling it for that loses money against trading it in.
Enter fullscreen mode Exit fullscreen mode

That's a real run from this morning, trimmed. For any product CeX stocks you get what it sells it for, what it pays in cash, what it pays in vouchers, which UK stores have it, how many it holds online, and which way it last moved the price.

import cexuk

r = cexuk.lookup("Xiaomi Mi TV Box S 3rd Gen")
r["sell"], r["cash"], r["voucher"]   # (60.0, 26.0, 37.0)
r["price_move"]                      # 'CeX raised it £55 → £60 on 29 Aug 2026'
Enter fullscreen mode Exit fullscreen mode

Where the numbers come from

CeX's website sits behind bot protection and returns 403 to a server. I didn't try to get past that, and the library doesn't either.

The site's search box works differently. It queries an Algolia index, and that index answers an ordinary request with the same rows the website shows. One POST, a JSON body, no key:

curl -s https://search.webuy.io/1/indexes/*/queries \
  -H 'Content-Type: application/json' \
  -A 'your-program/1.0 (+https://example.com)' \
  -d '{"requests":[{"indexName":"prod_cex_uk","params":"query=Sony%20WH-1000XM4&hitsPerPage=6"}]}'
Enter fullscreen mode Exit fullscreen mode

It serves an honest User-Agent, so the library names itself rather than pretending to be Chrome. It paces itself to at most one request a second and never retries. It isn't an official API, and it will change when CeX's front end does. The older public CeX API that earlier open-source scrapers used now returns 403, which is what "no contract" looks like.

Eight ways the numbers mislead you

Getting the JSON took an afternoon. Learning to read it took a week of wrong prices.

1. The search always answers. Algolia is a fuzzy index. Ask about something CeX doesn't stock and it answers confidently about something else. I measured it:

I searched for CeX returned
Raspberry Pi Argon ONE with SSD Raspberry Pi 500+, £136 cash
Argon ONE M.2 case Hercule Poirot: The First Cases, on DVD
Casio FX-CG50 Graphing Calculator the FX-CG20, FX-CG500 and FX-CG10

So the library scores every row against your query and only trusts rows at 0.6 or above. That threshold is measured, not chosen. Genuine matches scored 0.62, 0.67 and 0.86, and every wrong product topped out at 0.50. The model number acts as a veto: FX-CG50 never matches FX-CG20, however much of the rest of the title agrees. --rejected shows you what was thrown away.

2. The condition is in the name. "…Headphones - Black, B" is grade B. The grade isn't always after a comma, though: "Apple iPhone 13 128GB Midnight, Unlocked B" puts the comma three words earlier, and my first regex read every iPhone as ungraded.

3. Three rows can be one product. boxId ends in the grade letter: …117A, …117B and …117C are the same headphones in three conditions. Count them as three pieces of evidence and you overstate how much the market has told you.

4. £0 cash means "won't buy", not "worthless". A Google Nest Mini (2nd Gen) retails at £35 with a cash price of £0. "Trade it in for £0" would be a false statement about a real shop.

5. boxBuyAllowed doesn't mean CeX will buy it. That same Nest Mini has boxBuyAllowed: 1. The refusal is in the cash price, and the reason is discontinued: 1. I checked because the field name looked like exactly what I wanted.

6. Vouchers aren't cash. CeX typically pays around 69% of retail in store credit against 57% in money. Add the two together, or compare the voucher figure with an eBay sale, and "I sold a thing" quietly becomes "I've committed to shopping at CeX".

7. Keep the numbers on one row. If you take the best cash offer from one row and the trade-in percentage from another, you label one grade's money with another grade's ratio. The library takes sell, cash, voucher and both percentages from a single row.

8. A failed request must not look like zero. Any network or parse failure gives no rows, and the result then has no cash key at all. The CLI exits 1 on no match, so a script can tell "no answer" from "£0".

What you might build with it

  • A floor under your asking price. CeX's cash price is a standing offer for the item today. If you're about to list below it, you'd do better walking into a shop.
  • "Trade it in or list it?" Compare CeX's cash offer with what an eBay sale nets after fees and postage, not with the raw asking price. That comparison is where I started.
  • Stock and price watching. Which UK stores hold an item, and whether CeX has just cut or raised its price.

Try it, break it

git clone https://github.com/casareanderson/cex-uk-prices
cd cex-uk-prices
python -m cexuk "your thing here" --rejected
Enter fullscreen mode Exit fullscreen mode

17 tests, no network needed to run them. It's measured on electronics. The match gate is word overlap with a model-number veto, not understanding, so a short title that shares most of your query's words can still fool it. If you find a query that fools it, open an issue with the query and what came back. That's the most useful contribution anyone could make.

It isn't affiliated with CeX. CeX's own terms apply to whatever you build, so read them first, keep the pacing, and say who you are in the User-Agent.

github.com/casareanderson/cex-uk-prices

Source: dev.to

arrow_back Back to Tutorials