Scraped SaaS: stopping a copycat from arbitraging a free tier

How a subscription search product used Prosopo to stop a competitor scraping its results through the free tier and reselling them as a copycat service.

Chris Taylor
Chris Taylor

Updated 6 min read

In short
Customer
A subscription search product. Free to try, paid to use properly.
Problem
A competitor consuming the free-tier API at scale and reselling the results as a copycat service.
  • Copycat scraping stopped at the API
  • Detection that does not depend on request rate
  • Patterns promoted into standing rules automatically
  • 7.8M sessions scored in 30 days

This customer runs a subscription search product. Search is free to try and paid to use properly, the standard model for this kind of business: the free tier is how people discover whether the product works for them.

That model has a specific failure mode. If somebody automates the free tier at scale, they are not a heavy user. They are a competitor whose cost of goods is your marketing budget.

The problem

A competing service was scraping this customer's results and presenting them as its own product. The scrape ran against the API rather than the web form, as it normally does. There is no reason to automate a form when the endpoint behind it is available.

Subscription founders report this attack more than any other, and it rarely appears as a security incident. It appears as a conversion problem, a bandwidth bill, or a competitor whose results look familiar.

What we did

The first job was separating automated search sessions from real ones. That is where most tools stop. A scraper running one search every few seconds from a residential IP does not look unusual on volume alone.

What separated them was an environment that did not hold together. The client's worker thread and main thread reported different environments, and the processor characteristics it reported did not match the rest of the session. Neither is something a scraper can avoid by slowing down.

Once the pattern was established, the anomaly detectors promoted it into standing Access Rules on the ASN and IP ranges the traffic came from. Those rules block on a cheap comparison at the edge and carry an expiry, so they follow the attacker without accumulating stale entries.

Behavioural collection on the client side did the rest of the work on sessions that came through a browser. Real people searching behave differently from a harvester: they hesitate, they scroll results, they refine.

Why the rules matter as much as the detection

The detectors identify the automation. The rules are what makes stopping it cheap: once a pattern is established, an ASN or IP-range rule rejects matching traffic on a comparison at the edge, rather than running the full scoring path on every request from a source already known to be bad.

When the operator moved infrastructure, the ASN rules followed, because the detectors kept generating them from what they were seeing.

Results

Automated sessions stopped
315,766
out of 7,824,429 scored
30 days to
1 September 2026

Sessions scored
7,824,429
Free-tier and paid search traffic across the API and the site.

Stopped as automated
4.0%
Low by design. Most traffic here is real people running searches.

Real visitors who solved nothing
79%
Resolved by proof of work, which the browser completes on its own.

The blocked share is the lowest of the three deployments in these case studies, and that is the correct outcome. A consumer search product is mostly real people. The job is not to block a large fraction of traffic, it is to find the automated fraction inside it without taxing everybody else: of the 7.5 million sessions that were not blocked, 79% were cleared by proof of work and never saw a puzzle.

Top named block reasons

30 days

Address already known for abuse163,170

Connected through a network used to hide traffic157,036

Claimed one operating system, behaved like another18,214

Replayed an old request12,147

Claimed a device it was not running on7,068

Clicks produced by a script, not a hand1,902

Browser could not keep its story straight1,186

Request built in a way no real browser builds it651

Named reasons only, with related network-origin reasons grouped into one row. A further share of blocks carry a triggered detector rather than a reason string.

The bottom half of that list is the part that matters against a copycat. A scraper running slowly from residential addresses will not trip a rate limit, and it will not appear in the top two rows until it has already been caught once. What catches it the first time is the client contradicting itself: network behaviour that does not match the operating system it claims, processor speed that does not match the device it claims, a click pattern produced by a script rather than a hand. None of those depend on how fast the requests arrive.

What we would tell a founder in the same position

Look at your API before you look at your forms. If your product has a free tier and a public endpoint, the endpoint is where the abuse is.

Then ask your current vendor what a block tells you. If the answer is a score, you will be able to see that something was stopped and not what it was, so the next attack is harder to recognise than it needs to be.

Is your free tier funding a competitor?

A Bot Exposure Assessment is a 30-minute call with an engineer. We look at your traffic, show where your current setup leaves gaps, and agree how a trial would be judged. Nothing to install first.

Questions

Something else? Ask an engineer.

What problem was this customer solving?

A competitor was scraping their search results through the free tier and reselling them as a copycat product. The free tier is the acquisition channel for a subscription business, so an automated client consuming it at scale converts a marketing cost into a competitor's cost of goods.

How do you stop a scraper that looks like a normal user?

By looking at what the client cannot keep consistent. The automated client reported an environment that did not hold together: the worker thread and the main thread disagreed, and the reported processor characteristics did not match the rest of the session. Those are properties of a scripted or patched browser rather than of request volume, so they hold against a scraper deliberately running slowly. Enforcement was then a standing Access Rule on the ASN and IP ranges the traffic came from, generated automatically by the anomaly detectors once the pattern was established.

Why is a CAPTCHA on the search form not enough?

Because the scraper does not use the form. It calls the API the form calls. Protecting a subscription product against copycat scraping means scoring every request to the API, not adding a challenge to the page a human sees.

Why does free-tier scraping rarely look like a security incident?

Because nothing breaks. There is no outage, no data breach and no fraud alert. It shows up as a conversion problem, a bandwidth bill, or a competitor whose results look familiar, so it is often found late.