Attract Group Logo
Attract Group Logo
Portfolio/Price Tracker

Every scraper breaks.
The question is what happens next.

A price-tracking service that reads what ten electronics marketplaces charge for every handset a retailer sells or buys back. The interesting engineering is not the collecting. It is what the system does on the night a marketplace quietly redesigns its product page.

10 marketplaces

Watched daily across three catalogues

15% overnight

A price move that size is flagged the same night

2 failure modes

A site being down and a site being redesigned are told apart

Per request

Collection cost metered and capped on screen

The problem

The retailer sells refurbished phones and buys customers' old handsets through a trade-in flow. Both halves depend on one number: what the rest of the market is charging today.

List a refurbished handset €40 above the market and it sits in stock. Offer a customer €40 more than the high-street chains pay for the same trade-in, and the margin is gone before the device has even been graded.

Until this was built, keeping track meant somebody opening a dozen competitor product pages, copying prices into a spreadsheet, then doing it again the following week. That stops working past a few dozen SKUs. It also leaves no history, and it tells nobody when a competitor moves.

What it does

Every night the service visits the competitor page for each tracked device on each marketplace, reads today's price off the page, files it, and works out which marketplace is currently cheapest. If a price jumps sharply, the pricing team gets an email the same night.

The answer is also available over an API, so the retailer's own operational systems can ask what a handset is worth right now and get a live number instead of a stale spreadsheet cell.

Competitor pricing stops being a research task somebody has to remember to do, and becomes a data feed the business runs on.

One row, ten markets, one winner

What the pricing team opens in the morning

Four prices side by side, the cheapest one marked, and every figure carrying its movement since the previous reading. That is what makes a hundred-row table readable at a glance.

Marketplace labels and every figure on this illustration are invented. No competitor prices are reproduced.

The hard part is not the collecting

Anyone can fetch a page and read a number off it. The difficulty in this kind of system is that you control none of your data sources, and they change without telling you.

A marketplace redesigns its product page, your selector matches nothing, and overnight one column of your pricing table quietly goes empty.

The failure that hurts is not the crash. It is the silence. A system reporting nothing looks exactly like a system where nothing moved.

So the failure handling is the product. It has three parts.

Failures are told apart, not counted together

The morning report separates the page returned 404 from the page loaded but held no price. Those are different problems. The first usually means the product was delisted. The second means the page changed shape.

A rising failure rate is itself a signal

When enough readings fail on the same marketplace on the same night, the report says so. Instead of listing broken rows, it tells you a source has probably been redesigned and needs attention before tomorrow’s prices go out wrong.

A run is safe to fail

The nightly command takes an exclusive lock, so two runs can never overlap. It then stamps the devices it intends to process with a one-time token, claiming them as a batch, and releases them at the end whether the run succeeded or not. A crashed run leaves no devices stuck waiting for a human to notice.

The night a source changes shape

Two failures that look identical and are not

Nightly runfetch, read, filePage returned 404the URL is goneReported as: product delistedOne device, one marketplace. Someone re-links it.Nothing else is wrong.Page loaded, no pricethe page changed shapeReported as: extraction failureand counted per marketplace. When the count for one sourcecrosses the threshold on the same night, the report adds:“Market C: 34 of 41 readings failed.Source has probably been redesigned.”devices claimedwith a one-time token,released either way
A delisted product and a redesigned page both produce an empty cell. Telling them apart is the difference between a five-minute fix and a week of quietly wrong prices.

Reading the price without writing a rule per retailer

The obvious implementation is a hand-written extraction rule per marketplace. Ten marketplaces, ten brittle selectors, and ten things to fix every time one of them redesigns a page.

Instead, each connector sends the collection service the same instruction in plain English: extract the product price as a decimal number, return only the numeric value, use a dot as the decimal separator. Alongside it goes a hint about where on the page to look.

The differences that remain between marketplaces are real ones. One source keeps its price in the structured data embedded in the page. Another needs a couple of seconds for the page to settle before the number appears at all.

The extraction problem was solved once, not eleven times.

Adding the eleventh marketplace is one class

The parts of this system are separated by interchangeable connectors rather than by a network boundary. Each connector registers itself at start-up.

A connector declares which catalogues it belongs to, how to fetch a price, and how it should appear in tables, exports and charts. Everything downstream simply loops over the registered connectors.

So adding a marketplace does not mean editing eleven screens. Each connector contributes its own table column, export column and chart series on its own. The whole change fits in one small class.

Cost is a first-class metric

The retailer buys collection instead of running it. A commercial service fetches the pages through managed proxies and charges per request.

People usually frame that decision as convenience. The bigger reason is visibility. Every fetch has a known price, so the console can show how much of the month's collection budget is gone, and turn the figure red once the quota is nearly used up.

A background job that silently costs more every month is one of the easiest ways to lose money in software. Here the number sits on the same screen as the data it paid for.

This is the second product where we treated cost of goods as a product requirement rather than an infrastructure detail. That is not a coincidence, and it is worth asking for by name.

The console is fast because nothing is computed when you look at it

Once prices come back, the work runs through a chain of internal events. The system writes prices to history in bulk, recomputes the device's summary of latest values and cheapest marketplace, then runs the volatility check against that summary and sends any alerts. The chart data and every cached table cell for that device are rebuilt in the background.

By the time anyone opens the console, the expensive work has already been done. The screen reads almost entirely from cache.

Every price row gets a time-ordered unique identifier, which keeps a fast-growing history table quick to insert into and quick to read back in order. It is the unglamorous decision that stops a price-history product from getting slower every month it succeeds.

The security gate really blocks

Static analysis, dependency scanning and container-image scanning all run inside the deployment pipeline and report into a central register.

The check is a gate rather than a report: a High or Critical finding fails the build. At deploy time the pipeline pulls secrets from a managed parameter store, separately per project and environment, and keeps the most sensitive values under a restricted path. Nothing sensitive is ever baked into an image.

That is unusual for a system this small, and it is deliberate. An internal tool with an API that other systems trust is exactly the kind of thing that gets forgotten and then exploited.

Transferable

Three things worth copying

1

Design for the silence, not the crash

A pipeline reading sources you do not control will fail. Make the failures tellable apart, count them per source, and let a rising rate act as its own alarm. The expensive outcome is an empty cell nobody was told about.

2

Claim work, and release it either way

An exclusive lock plus a one-time claim token means a crashed run leaves nothing stuck. Batch jobs that clean up only on success are the ones needing a human every few weeks.

3

Put the running cost on the same screen as the data

Metered collection makes the cost per request visible, and a visible cost makes a budget meter possible. An expensive month becomes something you watch happening rather than something you discover later.

Questions we get asked

Before you commission a price-intelligence build

Is scraping legal?

It depends on the source, the jurisdiction and what you do with the data, and it is a question for your lawyers rather than your developers. What we can speak to is the engineering. This system reads publicly displayed prices, for a company’s own commercial decisions, at a low request rate, through a service that respects the target’s load. We do not build systems that harvest personal data or get around access controls.

What happens when a source changes its page?

You find out that morning. The report separates the failure from a delisted product, and flags the source if enough readings failed on it to suggest a redesign. The fix is a detail on that one source rather than a rewrite, because every connector shares the same extraction instruction.

Why buy the collection rather than run it?

Because running scrapers against large retail sites is a maintenance treadmill, and because buying collection makes the cost visible per request. The second reason matters more than the first. An invisible cost is one you find out about in a quarterly review.

How much of this is reusable for a different market?

The catalogue model, the connector registry, the alerting and the cost metering are not specific to phones. What is specific is deciding what counts as the same product across ten sources. That is the hard modelling problem in any price-intelligence build, and the part worth spending discovery time on.

Build a price-intelligence pipeline

Tell us how many sources you watch and how often they matter. We come back with a free project estimate: scope, approach, timeline, and a fixed-price range.

Or call us directly:+1 888-438-4988

Request a free estimate

Your data will never be shared with anyone.