How to Build an Automated Price Monitoring System
Build an automated price monitoring system with rotating proxies: pick the right proxy type, size threads to your SKU count, and cost it out before you buy.

Automated price monitoring fails for boring reasons. Not clever anti-bot defences, usually: it fails because someone bought residential bandwidth for a job that streams 700 GB a month, or provisioned 1,000 threads for a workload that needs 40, or built the whole thing on a single IP and watched it die in week three. This guide works backwards from the purchase decision. You get the sizing arithmetic, the proxy-type call, the rotation model, working code, and a monthly cost you can defend in a budget meeting.
Key Takeaways
- Price monitoring is bandwidth-heavy and thread-light. Most catalogues under 100,000 SKUs need fewer than 50 concurrent connections, so buying a big thread tier for "scale" is the most common overspend.
- Per-GB residential billing is the wrong meter for this workload. Repeatedly pulling the same product pages is exactly the pattern that makes unlimited-bandwidth datacenter proxies cheaper by an order of magnitude.
- On an unlimited plan, the Fair Usage speed cap is your real bandwidth budget. Convert Mbps to GB/day before you pick a tier.
- Use rotating exits for stateless catalogue sweeps and sticky sessions only for cart, login, and region-selector flows. Mixing the two on the wrong requests is what silently corrupts price accuracy.
Decide First: Build, API, or Off-the-Shelf
Three routes exist, and the right one depends almost entirely on how many targets you track and how much engineering time you can spend keeping parsers alive.
| Route | What you buy | Engineering load | Best when | Real weakness |
|---|---|---|---|---|
| Raw proxies plus your own code | Proxy access, priced by threads or bandwidth | High: fetching, retries, parsing, scheduling, storage | You track 5,000+ SKUs, need custom fields, and have a developer | Parser maintenance never ends. Sites change layout without warning |
| Scraping API | Managed fetching, rendering, and unblocking per request | Medium: you still parse and store | Mid-size catalogues, JS-heavy targets, small teams | Per-credit billing gets expensive once rendering is mandatory |
| Off-the-shelf price monitoring SaaS | A finished dashboard | Low | Under a few hundred competitor SKUs, non-technical buyer | Fixed schema, per-SKU pricing, no coverage for targets they do not support |
The honest split: SaaS wins below roughly 500 tracked products, because per-SKU pricing is still cheap there and you skip all the plumbing. Between 500 and about 50,000 products, a scraping API plus a small parsing service is usually the lowest total cost once salary is included. Above that, or wherever the same pages get pulled several times a day, raw proxies with unlimited bandwidth pull decisively ahead, because your marginal cost per check drops to nearly zero while every per-request meter keeps ticking.
This is not a permanent decision, which buyers often miss. Plenty of teams start on a scraping API to prove the business case, then move the high-frequency, easy-to-parse targets onto raw proxies once volume justifies the engineering. Keep the fetch layer behind an interface and switching later costs an afternoon.
Size the System Before You Price It
Concurrency is the number every proxy plan is sold on, and almost nobody calculates it. The formula is short:
threads = ceil( requests_per_run x avg_seconds_per_request / window_seconds )
Then provision about 3x that, because retries, slow targets, and uneven scheduling all eat headroom. Run the numbers for a few realistic catalogues:
| Catalogue | Checks/day | Requests/day | Run window | Avg round trip | Threads needed | Provision 3x | Fits plan |
|---|---|---|---|---|---|---|---|
| 2,000 SKUs | 4 | 8,000 | 1 h | 2.5 s | 6 | 20 | Starter, 100 threads |
| 20,000 SKUs | 4 | 80,000 | 4 h | 2.5 s | 14 | 45 | Starter, 100 threads |
| 20,000 SKUs, JS rendered | 4 | 80,000 | 4 h | 7 s | 39 | 120 | Core, 250 threads |
| 200,000 SKUs | 2 | 400,000 | 6 h | 2.5 s | 47 | 140 | Core, 250 threads |
| 200,000 SKUs | 4 | 800,000 | 6 h | 2.5 s | 93 | 280 | Boost, 500 threads |
| 1,000,000 SKUs | 2 | 2,000,000 | 8 h | 2.5 s | 174 | 520 | Plus, 1000 threads |
Look at the fourth row. Four hundred thousand requests a day, a catalogue most teams would call large, and the theoretical requirement is 47 concurrent connections. This is why "how many proxies do I need" is the wrong opening question for price monitoring. The binding constraint is rarely your thread count. It is per-domain politeness, because hammering one retailer with 200 parallel requests gets you blocked no matter how many IPs sit behind them.
SparkProxy's published tiers map onto that table directly: Starter at $75/mo for 100 threads and 5 whitelist slots, Core at $140/mo for 250 threads and 10 slots, Boost at $240/mo for 500 threads and 15 slots, and Plus at $440/mo for 1000 threads and 25 slots. All four carry unlimited bandwidth and 30 days validity. Pro and Pro+ tiers exist for higher thread counts under the Fair Usage Policy but are quoted rather than listed publicly.
Scraping at scale? Skip the blocks.
Fast, unblockable datacentre proxies with unlimited bandwidth.
Choosing a Proxy Type for Price Data
Product listing pages are public, cacheable, and mostly served to anonymous visitors. That profile favours datacenter IPs far more than the residential-by-default advice you will read elsewhere.
| Factor | Datacenter | Residential | Mobile |
|---|---|---|---|
| Typical billing | Threads, flat monthly, unlimited bandwidth | Per GB | Per GB, highest rate |
| Cost behaviour at high re-fetch rates | Flat, marginal cost near zero | Scales linearly with every check | Scales linearly, painfully |
| Latency | Lowest, hosted in datacenters | Higher, real consumer links | Highest, carrier-dependent |
| Geo granularity | Country and city level | Household level | Carrier and region |
| Blocked by aggressive retailers | Sometimes, subnet-dependent | Rarely | Almost never |
| Right job in price monitoring | The default sweep across most retailers | The subset of targets that reject datacenter ranges | Rarely justified for price data |
Start datacenter-first and escalate only the domains that actually fail. In most catalogues that escalation set is a handful of aggressive marketplaces, not the whole target list. The reason is arithmetic, not preference. If you check 20,000 products four times a day and each page transfers roughly 300 KB, you move about 24 GB a day, or 720 GB a month. On a flat unlimited plan that number is free. On a per-GB meter it is the entire budget.
Competitor per-GB rates are published on each vendor's own pricing pages and change frequently. As of September 2026, the major residential networks (Bright Data, Oxylabs, Decodo, IPRoyal) publish entry residential rates in the single-digit dollars per GB, falling with volume commitment. Those are each vendor's own published figures, including their pool-size claims, so check the current pages before you model anything.
For a deeper split of the three families and where each earns its price, see the comparison of residential, datacenter, and mobile proxy types.
Turning the Speed Cap Into a Bandwidth Budget
"Unlimited bandwidth" still has a ceiling, and it is the speed cap. This is the calculation that should decide your tier, and virtually no buyer runs it. A Mbps cap converts to a daily transfer ceiling at full saturation:
| Plan | Fair Usage speed cap | Theoretical ceiling per day | Product pages/day at 300 KB |
|---|---|---|---|
| Starter | 25 Mbps | 270 GB | ~900,000 |
| Core | 50 Mbps | 540 GB | ~1,800,000 |
| Boost | 100 Mbps | 1,080 GB | ~3,600,000 |
| Plus | 150 Mbps | 1,620 GB | ~5,400,000 |
Two caveats, both important. The cap is a ceiling, not a guaranteed rate, and no real workload saturates a link continuously, so plan against 30 to 50 percent of these numbers. Even so, the point holds: a 20,000 SKU catalogue checked four times daily uses roughly 9 percent of a Starter plan's theoretical ceiling. Bandwidth is almost never the reason to upgrade in this use case. Threads and whitelist slots usually are.
The Rotation Model That Matters
Two behaviours, two ports, and the difference decides whether your prices are correct.
| Need | Endpoint | Behaviour |
|---|---|---|
| Stateless catalogue sweep, one page per request | `gateway.sparkproxy.io:11000` | New exit IP per request |
| Multi-step flow: region selector, login, add to cart | `gateway.sparkproxy.io:11002` | Sticky exit held across the session |
| Non-HTTP clients or tooling that prefers SOCKS | `gateway.sparkproxy.io:13000` | SOCKS5 |
Rotating per request is right for the bulk of the work. Where it goes wrong is any page whose price depends on state you established earlier. If you set a delivery postcode, then rotate to a new IP for the product page, you get a price for the wrong region and silently poison your dataset. Keep those flows on a sticky session for their whole lifetime.
The rotation mechanics themselves, including retry handling and thread-safe pools, are covered in what proxy rotation is and how it works and in the Python patterns in how to rotate proxies in Python.
System Architecture in Five Parts
Keep these as separate components. Teams that fuse fetching and parsing into one script end up re-scraping every time a selector changes, which is both slow and rude to the target.
- Scheduler. Decides what gets checked and when. Cron is fine to start; a queue such as Celery or BullMQ scales better once you need per-domain rate control.
- Fetcher. The only component that touches proxies. Returns raw HTML plus status code, timing, and the exit IP used.
- Raw store. Persist the fetched HTML, compressed, keyed by URL and timestamp. This is the single highest-value habit in the whole system: when a parser breaks you re-parse history instead of re-scraping it.
- Parser. Extracts price, currency, availability, seller, and shipping into a normalised record.
- Change detector and alerter. Compares against the previous observation and emits only real movements.
Tier your check frequency instead of sweeping everything at one cadence. Roughly: hourly for the top 1 to 2 percent of revenue SKUs, four times daily for the competitive core, daily for the long tail, weekly for discontinued or low-velocity items. That single decision often cuts total request volume by 60 to 80 percent against a flat hourly sweep, with no loss of usable signal. If you need the scheduling layer in more depth, see how to schedule and automate web scrapers.
The Fetch Layer With Rotating Proxies
A minimal fetcher with per-domain politeness, retries, and rotation. Rotation happens server-side, so the client simply points at the rotating port.
import time, random, threading, requests
from collections import defaultdict
PROXY = "http://USER:PASS@gateway.sparkproxy.io:11000"
PROXIES = {"http": PROXY, "https": PROXY}
HEADERS = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
"AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0 Safari/537.36",
"Accept-Language": "en-US,en;q=0.9",
}
_last_hit = defaultdict(float)
_lock = threading.Lock()
MIN_GAP = 1.2 # seconds between requests to the same host
def _throttle(host):
with _lock:
wait = MIN_GAP - (time.time() - _last_hit[host])
if wait > 0:
time.sleep(wait)
_last_hit[host] = time.time()
def fetch(url, host, attempts=3):
for i in range(attempts):
_throttle(host)
try:
r = requests.get(url, proxies=PROXIES, headers=HEADERS, timeout=30)
if r.status_code == 200:
return r.text
if r.status_code in (403, 429, 503):
time.sleep((2 ** i) + random.random())
continue
return None
except requests.RequestException:
time.sleep((2 ** i) + random.random())
return None
Verify rotation is live before you trust any of it. Two calls, two different exits:
curl -s -x http://USER:PASS@gateway.sparkproxy.io:11000 https://ipinfo.io/json
curl -s -x http://USER:PASS@gateway.sparkproxy.io:11000 https://ipinfo.io/json
For a postcode-bound or logged-in flow, switch to the sticky port and hold one session for the whole sequence:
curl -s -x http://USER:PASS@gateway.sparkproxy.io:11002 https://ipinfo.io/json
Success rate per domain is the metric to watch here, not raw throughput. If a given retailer drops below roughly 90 percent on datacenter IPs, that domain is a candidate for escalation, not the whole system. Detecting when your scraper is blocked covers the soft-block signals that never show up as a non-200 status.
Using the Scraping API Instead of Raw Proxies
When targets render prices in JavaScript and you would rather not run a browser fleet, the managed route removes an entire category of work.
import requests
API = "https://scrape.sparkproxy.io/api/v1"
API_KEY = "sk-xxxxxxxxxxxxxxxx"
def fetch_price_page(url, country="US", render=False):
r = requests.get(
API,
params={
"url": url,
"country_code": country, # ISO alpha-2
"render_js": str(render).lower(),
"format": "json",
},
headers={"X-API-Key": API_KEY},
timeout=90,
)
d = r.json()
return d["status_code"], d["body"], d.get("credits_used")
The billing model is what decides this, so do the arithmetic openly. A plain fetch costs 1 credit, JS rendering costs 5, and a screenshot or PDF costs 10. Published tiers: Starter $49 for 250,000 credits at 50 concurrent, Growth $99 for 1,000,000 at 100 concurrent, Pro $249 for 3,000,000 at 200 concurrent, Scale $599 for 8,000,000 at 400 concurrent. There are 1,000 free credits with no card, which is enough to validate parsers against your real target list before spending anything.
Apply it to the 20,000 SKU example: 80,000 requests a day is 2.4 million a month. As plain fetches that lands inside Pro at $249. Turn on rendering for every request and the same workload needs 12 million credits, which is past the largest published tier. That crossover is the most useful number in this article. Rendering everything on a per-credit meter does not scale; rendering selectively does. Most retail product pages ship the price in the initial HTML or in an embedded JSON blob, so check first and render only the domains that genuinely need it. Practical recipes for that extraction step are in how to scrape ecommerce prices.
Change Detection, Storage, and Alerts
Store observations, not current state. An append-only table lets you answer "when did they drop it" months later, which is the question that actually drives pricing decisions.
CREATE TABLE price_observation (
id BIGSERIAL PRIMARY KEY,
sku TEXT NOT NULL,
competitor TEXT NOT NULL,
url TEXT NOT NULL,
price_cents INTEGER,
currency CHAR(3),
in_stock BOOLEAN,
seller TEXT,
observed_at TIMESTAMPTZ NOT NULL DEFAULT now(),
exit_ip INET,
http_status SMALLINT
);
CREATE INDEX ON price_observation (sku, competitor, observed_at DESC);
Then gate alerts so the channel stays credible:
def should_alert(prev, curr, floor_cents=100, pct=3.0):
if prev is None or curr is None:
return False
delta = abs(curr - prev)
if delta < floor_cents:
return False
return (delta / prev) * 100 >= pct
Two guards worth adding on day one. First, treat a parse returning None as a fetch failure, never as a price of zero, because a single null written as 0 fires a "competitor dropped 100 percent" alert at 3 a.m. and burns trust in the system. Second, require two consecutive observations to agree before alerting on a large move. Retailers do briefly serve broken or test prices, and a confirm-on-repeat rule removes nearly all of that noise at the cost of one extra check cycle.
What This Actually Costs Per Month
Take the 20,000 SKU, four-checks-daily workload: 2.4 million requests and roughly 720 GB a month.
| Approach | Monthly cost | Notes |
|---|---|---|
| Unlimited-bandwidth datacenter, Starter | $75 | 100 threads covers the 45 needed. Bandwidth free. You build and maintain the code |
| Unlimited-bandwidth datacenter, Core | $140 | Headroom for JS rendering on your own browsers, or a second catalogue |
| Scraping API, Pro | $249 | Plain fetches only. No proxy management, no unblocking work |
| Per-GB residential at $3/GB | $2,160 | Illustrative arithmetic on 720 GB, not a quote from any vendor |
| Per-GB residential at $6/GB | $4,320 | Same volume, different rate point |
The residential rows are arithmetic, not a price quote. They show what any per-GB meter does to a re-fetch-heavy workload. That gap, roughly $75 against a four-figure bill for identical data, is why proxy type matters more than any other decision in this build. Residential IPs remain the correct answer for the specific domains that reject datacenter ranges. They are the wrong default for the other 90 percent of your target list.
Add engineering honestly when you compare. A working system is a week or two of initial build plus a few hours a month of parser maintenance. If that time is scarce, the $249 API line is cheaper than the $75 proxy line once salary is in the model. Teams already running competitive intelligence programmes will recognise the pattern from how ecommerce companies use proxies for competitive intelligence.
Mistakes That Kill Price Monitoring Projects
- Flat cadence for everything. Hourly checks across an entire catalogue multiply cost by 6 to 24x for signal nobody uses. Tier by revenue.
- No raw HTML archive. Parsers break often. Without stored HTML, every break costs a full re-scrape and leaves a permanent hole in the history.
- Rotating IPs mid-session. Region and cart flows need sticky exits. Rotating through them yields prices from the wrong locale, and nothing in the data will tell you.
- Ignoring currency and tax presentation. The same SKU shows ex-VAT in one market and inclusive in another. Store currency and a tax flag or your comparisons are meaningless.
- Alerting on every movement. Untuned alerts get muted within a fortnight, and the mute is permanent.
- Buying threads instead of measuring them. Run the concurrency formula. Most teams need a fraction of what they were sold.
- Scraping behind a login you agreed not to automate. Public listing pages are one thing; an account whose terms you accepted is a different risk profile. Get that reviewed before you build it, not after.
Related reading if your targets are marketplaces rather than direct retailers: how to scrape Amazon product data. If the job is enforcing your own pricing policy rather than watching competitors, proxies for MAP monitoring covers that variant.
Frequently asked questions
Frequently Asked Questions
Fewer than you think. Multiply requests per run by average seconds per request, divide by your run window in seconds, then triple it for headroom. A 20,000 SKU catalogue checked four times daily needs roughly 45 concurrent connections, which fits comfortably inside a 100-thread entry plan.
Datacenter proxies are the right default, because price monitoring re-fetches the same public pages constantly and per-GB residential billing punishes exactly that pattern. Escalate to residential only for the specific domains that block datacenter ranges.
Use a scraping API when JavaScript rendering is unavoidable, the team is small, or you want a working pipeline in days. Move to raw proxies with unlimited bandwidth once volume is high and the pages parse from static HTML, because the marginal cost per check then drops to almost nothing.
Tier it. Hourly for the top 1 to 2 percent of SKUs by revenue, four times daily for the competitive core, daily for the long tail, weekly for slow movers. Flat hourly sweeps typically cost several times more for no extra decision value.
Collecting publicly displayed prices is generally accepted in most jurisdictions, and courts have been reluctant to treat access to public pages as unauthorised. This is not legal advice, and the picture changes once you are behind a login, ignoring robots directives, or republishing copyrighted content, so have your specific programme reviewed by counsel.
Parsers, by a wide margin. Retailers change markup without notice, so store the raw HTML for every fetch, alert on parse-failure rate as well as on price movement, and never let a failed parse write a zero into your price table.
Get 20% off your first month
Premium datacentre proxies with unlimited bandwidth. Use the code at checkout.
Save up to 15% more on quarterly, half-yearly and yearly plans
Related articles

Proxies for Threat Intelligence: Building SOC Infrastructure
Buying proxies for threat intelligence: a tiering table by collection task, concurrency sizing math, build-vs-buy costs, and vendor questions for SOC teams.

Best Proxies for Dropshipping and Product Research
Which dropshipping proxies to buy for supplier scouting, competitor teardowns and price tracking, with cost math, sizing tables and honest trade-offs.

Best Proxies for Amazon Sellers: Buy Box, Rank and MAP
Amazon seller proxies compared for Buy Box, keyword rank and MAP tracking: which proxy type to buy, how many threads you need, and what each option costs.
