Client build · In delivery

A sourcing engine for a book arbitrage seller · Node + Express · vanilla JS · Chrome DevTools Protocol

The Book Sourcing Engine.

Two thousand listings in, seven verified books out. Every margin is computed from what the listing actually says today, not what an index said last week.

An indexed price, and nothing else.

The client buys used books cheap and resells them on Amazon FBA. He was choosing books by hand from a paid research tool that gave him an indexed price and nothing more. So he was buying copies that had already sold, copies in unsellable condition, and copies from overseas sellers whose postage ate the entire margin. He found all of this himself, checking one list by hand.

A sourcing engine and a morning control panel.

Node and Express on the back; plain HTML, CSS, and vanilla JavaScript on the front. No framework, no build step, no bundler, no database: JSON files on disk are the store. Four dependencies across both halves. About 7,700 lines.

~2,000
listings scanned each morning
~700
distinct books that pass the buying rules
6 to 8
books that fit the $200 daily budget

The narrowing is the product. Each surviving book is opened on the shop that actually sells it, and the last stage (real Amazon fees, per book) is what cuts seven hundred candidates down to single figures.

Four shops, read politely.

One shop serves plain HTML, so a fetch is enough. Three sit behind bot protection, so those go through a real browser driven over the Chrome DevTools Protocol with a throwaway profile. Nothing defeats a challenge: the engine waits for the ones that clear on their own, and reports the ones that do not.

Five bugs that never threw an error.

Every one of these produced confident, wrong numbers. Finding them is most of what the client paid for.

01
“0.00” means “no forecast”
The research tool writes 0.00 when it has no forecast for a book. Read as a real zero, that made a book look like a guaranteed loss. It was silently dropping 44 of 150 books before anyone saw them.
02
Two fees, exactly $0.99 apart
Two of the vendor’s endpoints return a fee for the same book that differ by exactly $0.99. Using the wrong pairing overstated profit by 36 percent.
03
The cookie that moved postage $29
A cookie flag decided whether the shop quoted postage to the buyer’s real destination or guessed from the server’s IP. Set wrong, it quoted $33.00 on a book that costs $3.75 to post domestically.
04
Two definitions of what a book costs
Postage was inside the profit calculation but not inside the code that spent the budget, so the tool overspent by the postage and picked the cheapest sticker price instead of the cheapest landed cost. The fix: one function is the single definition of what a book costs, and every path that touches money routes through it.
05
The config that only looked current
The delivery postcode lived in an env file the server read once at startup. Changing the file wasn’t enough: a running server kept the old value and quoted the wrong city for an entire run while looking completely correct on screen. Every run now records which postcode it used, and says so on screen.

230 checks before any change ships.

The checks pin behaviour, not implementation. A few of them:

  • →Postage is inside the money, on every path that spends it.
  • →The fee constants have not silently drifted.
  • →The spreadsheet export still carries the byte order mark Excel needs.
  • →A row that could not be verified is dropped, not shown.

One gate fails on purpose until changes to the scraping engine are committed deliberately, so the engine can never be edited casually.

An antiquarian bindery, not a dashboard.

One non-technical person reads this once each morning. The visual identity is bottle-green leather, gold tooling, and aged paper, because it is a book business. After the theme change, every text-and-background pair was measured for WCAG AA contrast; the lowest ratio on the page is 4.67:1.

Each row shows the profit subtraction written out in full, so the client can check the arithmetic himself; the condition and the town the copy ships from; and the sales rank expressed as a rough waiting time rather than a raw number.

What I deliberately did not build.

The 25-percent rule
The client asked for a "buy at 25 percent of the Amazon price" rule. That number appears nowhere in his vendor’s published training. It was his own invention. I built it, switched it off, and replaced it with a rule that a book must cost less than its own average price over six months: a price compared to what that book normally goes for, not to an arbitrary percentage.
Automated Amazon sign-in
Signing into his Amazon account automatically would have bought slightly better data. It would also have put the account his business depends on through automated foreign sign-ins. I declined. The marginal gain is not worth the account.

Seven books, to the cent.

Every figure on a saved list recomputes to the cent from the engine’s own functions. A typical morning: 7 books, $196.98 of a $200 budget, $67.78 of estimated profit. Every copy was verified live before it reached the screen.

Stated plainly: no book has sold through yet, so the profit figures are estimates and are described that way. What the engine has already removed are the silent losses (the sold copies, the unsellable conditions, the overseas postage) that used to be discovered by hand, after the money was spent.

Running an Amazon operation on hand-checking?

Tell me what you verify by hand every morning. I’ll tell you which parts a system can verify for you, and which parts it honestly can’t.