Crawling a site that does not want to be crawled

When a platform depends on data it does not own and no API exists, the work is not really about extraction. It is about how often you can reasonably ask, what you do when the answer changes shape, and how you keep the rest of the system honest about how stale its view is.

The extraction itself is the easy part, and the part most likely to be rewritten.

Headless rendering is a cost, not a default

A full browser is heavy. Before reaching for one, check whether the page hydrates from a JSON endpoint you can call directly — very often it does, and that path is faster, more stable and far less likely to break on a style change.

When rendering genuinely is required, running it as a scheduled serverless function rather than a long-lived server keeps the cost proportional to how often the data actually changes.

Treat the shape as untrusted

The source will change without telling you. Validate what comes back against a schema and reject the batch loudly rather than writing half-parsed rows into the database.

A crawler that fails visibly is an inconvenience. One that silently degrades quality is a data problem you will find out about from a user.

Be explicit about freshness

Anything downstream needs to know how old the view is. Storing the observation time alongside the value — and surfacing it — is what lets the product decide whether to show a number, caveat it, or hide it.

That single field prevents most of the arguments that otherwise start with somebody asking why two screens disagree.

Tell us what you need. We will tell you what it takes.

A free first conversation, a written price before anything starts, and a reply within one working day.