Website Change Monitor: Competitor Pricing & Terms avatar

Website Change Monitor: Competitor Pricing & Terms

Pricing

from $0.30 / 1,000 page checkeds

Go to Apify Store
Website Change Monitor: Competitor Pricing & Terms

Website Change Monitor: Competitor Pricing & Terms

Track competitors' pricing, terms and privacy, careers, changelog and sitemap pages on a schedule and get only meaningful changes: plan and price changes, changed legal sections, new pages and roles, each with a plain-English summary, severity and webhook alert. $0.30 per 1,000 page checks.

Pricing

from $0.30 / 1,000 page checkeds

Rating

0.0

(0)

Developer

Fairquery

Fairquery

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

12 days ago

Last modified

Security

Limited permissions

Share

Website Change Monitor: Competitor Pricing, Terms & Careers

What does it do?

This website change monitor tracks your competitors' public pricing, terms and privacy, careers, changelog and sitemap pages on a schedule and reports only the changes that matter, each with a plain-English summary and a severity. Prices are parsed per plan, legal pages are compared section by section, Greenhouse, Lever and Ashby job boards are compared role by role, and sitemaps show new and removed pages. Pin a CSS selector when you only care about one region of a page (a pricing table, a plan grid, a legal section).

Digest mode writes one weekly row per competitor domain. That row combines this Actor's pricing, terms and changelog changes with jobs opened or closed by department (Company Jobs Feed) and technologies added or removed (Website Tech, SEO and AI Readiness), and can post one Slack, Discord or JSON webhook message per domain.

Timestamps, rotating tokens, cookie banners, navigation and footers are ignored, so an unchanged page doesn't raise an alert. Send alerts to a webhook (JSON, Slack or Discord format) or read them from the dataset. It's exactly as fresh as your schedule: each run is one check.

How much does it cost?

Pay per event, no subscription. Prices per 1,000 events (no start fee):

EventFree planStarter (Bronze)Scale (Silver)Business (Gold)
page-checked (primary)$0.30$0.30$0.30$0.30
change-detected$4.90$4.90$4.90$4.90
page-rendered (optional, JS pages)$5.90$5.90$5.90$5.90

The Apify Free plan includes $5 of usage every month, no credit card needed, and this Actor's event charges come out of that $5. That covers 20 pages checked every hour for a 30-day month (14,400 checks = $4.32) with room for about 138 change reports, or about 16,600 page checks in total.

Example (Free-plan prices): 10 pricing pages checked daily: 300 checks a month = $0.09, plus $4.90 per 1,000 changes reported.

The price is the same on every Apify plan. Set a maximum cost per run in the run options and the Actor stops before exceeding it.

How to use it

  1. Add Pages with a type (pricing, terms, privacy, careers, changelog, blog, or product for a sitemap URL or site root), or give Domains and let it find those pages. Optional: set cssSelector on a page, or one selector for the whole run, to compare only that DOM region.
  2. Set a minimum severity and, optionally, a webhook URL for alerts. For a weekly competitor rollup, set mode to digest and schedule the run weekly.
  3. Click Start once to store the baseline, then create an Apify Schedule (hourly, daily or weekly). Later runs report only changes. The first digest run saves jobs and tech baselines; the next run reports openings, closures and stack changes.

Example input

{
"pages": [
{
"url": "https://basecamp.com/pricing",
"type": "pricing"
},
{
"url": "https://linear.app/pricing",
"type": "pricing"
},
{
"url": "https://linear.app/terms",
"type": "terms"
},
{
"url": "https://jobs.ashbyhq.com/linear",
"type": "careers"
}
]
}

Example output (one row from a real run on 2026-10-17, shortened to the main fields). In this test run the stored baseline was edited to simulate the old price:

{
"type": "change",
"url": "https://basecamp.com/pricing",
"page_type": "pricing",
"severity": "high",
"change_kind": "price_changed",
"summary": "\"Pro\" price changed from $79/month to $99/month (up 25.3%).",
"details": {
"plan": "Pro",
"from": {
"amount": 79,
"currency": "USD",
"period": "month",
"billing": null,
"unit": null,
"raw": "$79"
},
"to": {
"amount": 99,
"currency": "USD",
"period": "month",
"billing": null,
"unit": null,
"raw": "$99"
},
"change_pct": 25.3
},
"checked_at": "2026-10-18T02:45:39.652Z",
"previous_checked_at": "2026-10-18T02:43:49.387Z"
}

FAQ

How do I track a competitor's pricing page for changes?

Add the pricing page with type pricing, run once to save a baseline, then schedule the Actor. You get a row when a plan is added or removed or a price changes, with old and new values.

How often does it check?

As often as your Apify Schedule runs it, for example hourly or daily. It doesn't watch pages continuously, and a change made and reverted between two runs isn't seen.

They're filtered out, along with rotating tokens, navigation and footers, and changes are re-read before reporting to cut A/B-test noise. Some variant noise can still get through.

Can it watch JavaScript-only pages?

Yes. Set renderJs to auto (render only pages whose plain HTML has no readable prices or almost no text) or always, and run with at least 1 GB memory; each rendered page adds $5.90 per 1,000.

Limits

Plan parsing is heuristic; usage-based pricing pages and calculators can produce odd plan names. Runs use Apify datacenter IPs, so prices may differ by country. Sites that block automated access are skipped. Fairquery is not affiliated with any tracked site.

When to use this Actor (LLM / tool selection)

Use it when a person, agent or workflow needs to:

  • Know when a competitor changes a price, adds or removes a plan, or switches monthly/annual billing
  • See which sections of a Terms of Service or Privacy Policy changed, with the removed and added sentences
  • Spot new or removed product, feature or integration pages (sitemap diff)
  • Follow hiring signals: new and closed roles by department from Greenhouse, Lever or Ashby boards, or keyword counts on a plain careers page
  • Get one weekly digest per competitor domain: pricing, terms and changelog changes, jobs opened or closed by department, and tech-stack additions or removals (mode: "digest")
  • Watch one DOM region of a page with a CSS selector (#pricing, main .plans) instead of the whole document
  • Get new changelog or blog entries with their links
  • Send alerts to Slack, Discord or any HTTPS webhook, filtered by severity

Do not use it for: pages behind a login, paywall or CAPTCHA (never accessed), visual/pixel comparison of designs, minute-by-minute monitoring, or sites whose robots.txt disallows the page (skipped and reported).

What counts as a change

Page typeWhat is comparedExample summary (from test runs)
pricingPlans: name, price, currency, period (month/year/hour), per-user units, billed annually"Pro" price changed from $79/month to $99/month (up 25.3%). · New plan "Studio" ($59/month).
terms, privacySections (by heading), sentence-level diff, renamed sectionsTerms of service: 2 sections changed: "Terms of Service" (modified: +1/−1 sentences), "Linear’s Ownership" (added). Removed: “…” Added: “…”
careersJob board (Greenhouse/Lever/Ashby) roles by id, or careers-page text and keyword counts3 new roles (3 Product); 1 role closed (1 Engineering). Open roles: 27 → 29 (+7%).
changelog, blogEntry headings and links2 new changelog entries: “Stacked pull requests”, …
product (site root)sitemap.xml URLs (index files and .gz supported)2 pages removed from the sitemap (2 product/feature-like), e.g. /features/…
genericPage text by sectionPage: 1 section changed …

Severities: high (price/plan changes, substantive legal edits about liability, data, AI, arbitration, fees, termination and similar), medium (larger text changes, product pages added/removed, notable hiring shifts, watched keywords), low (small edits, routine sitemap churn, a page switching back to a version seen before).

Noise filtering

  • Strips scripts, styles, nav, footer, cookie/consent banners and hidden templates; reads the main content.
  • Masks timestamps, dates, "x minutes ago", session tokens, UUIDs, hashes, cache-busting parameters, copyright years and live counters. Numbers are masked except on pricing and legal pages, where they matter.
  • Ignores reordered sentences, small edits under minChangeChars, and your own ignorePatterns.
  • Confirms each change with a second read (after the polite delay; not charged) so A/B variants that come and go within seconds are not reported.
  • Remembers recent versions: a page alternating between two versions across runs alerts once, then only as one low-severity "switched back" item.
  • Small edits accumulate against the old baseline until they cross the threshold, so a slow drip of edits is not lost.

Input

You can give exact pages, plain URLs (type guessed from the path), or domains plus the page types to find.

FieldDefaultWhat it does
modewatchwatch writes one row per change. digest also writes one weekly row per domain (pricing/terms/changelog + jobs by department + tech-stack add/remove) and posts one webhook payload per domain
digestJobs / digestTechtrue / trueIn digest mode, call Company Jobs Feed and Website Tech, SEO and AI Readiness. Each bills your account at its own per-1,000 price. Set either to false to leave that signal out
cssSelectorCSS selector applied to every page that does not set its own. Only that region is compared
pagesList of { "url": "...", "type": "pricing", "cssSelector": "#pricing" } (types: pricing, product, terms, privacy, careers, changelog, blog, generic). cssSelector is optional
urlsPlain URL list; type guessed from the path (/pricing → pricing, /terms → terms, …)
domainsCompetitor domains; the Actor finds the requested page types via homepage links and a few common paths (cached 30 days, discovery requests are free)
pageTypespricing, terms, privacy, careers, changelog, productPage types to find for domains
watchlistNamedefaultName of this watchlist. Baselines are stored per watchlist, so different lists don't interfere
maxPages50 (≤ 200)Cap per run
minSeveritylowChanges below it are not output or charged
careersKeywords / watchKeywordsWords to count on careers pages / anywhere (e.g. "AI", "SOC 2", "enterprise")
ignorePatternsExtra regexes to ignore (ReDoS-checked)
minChangeChars20Smallest text change worth reporting (legal pages use a lower floor)
includeDifftrueInclude removed/added sentences in details
webhookUrl, webhookFormat, webhookMinSeverity, json, mediumHTTPS webhook for alerts: json, slack or discord (stored as a secret input)
renderJsneverauto: render with a headless browser only when plain HTML has no readable prices or almost no text; always: render all. Needs ≥ 1024 MB memory; robots.txt still applies
confirmChangestrueRe-read a page once before reporting a change
sitemapInclude / sitemapExclude / maxSitemapFiles/ / 10Filter sitemap URLs by regex; cap sitemap files read
requestDelaySecs1.5 (1–30)Minimum gap between requests to the same host (a larger robots.txt Crawl-delay wins)
stateStoreNamefairquery-competitor-trackerNamed key-value store in your account holding baselines
resetBaselinefalseStart over: this run becomes the new baseline

Example input

{
"watchlistName": "saas-competitors",
"pages": [
{ "url": "https://basecamp.com/pricing", "type": "pricing" },
{ "url": "https://linear.app/pricing", "type": "pricing" },
{ "url": "https://github.com/site/terms", "type": "terms" },
{ "url": "https://jobs.ashbyhq.com/linear", "type": "careers" }
],
"domains": ["cal.com"],
"careersKeywords": ["AI", "enterprise"],
"webhookUrl": "https://hooks.slack.com/services/…",
"webhookFormat": "slack"
}

Weekly digest (one dataset row and, when webhookUrl is set, one Slack/Discord/JSON message per domain):

{
"mode": "digest",
"watchlistName": "saas-competitors",
"domains": ["linear.app", "cal.com"],
"pageTypes": ["pricing", "terms", "changelog"],
"cssSelector": "main",
"webhookUrl": "https://hooks.slack.com/services/…",
"webhookFormat": "slack"
}

Then add an Apify Schedule (for example hourly or daily, or weekly for digest) with the same input. The first run stores baselines; every later run reports changes.

Output

One dataset row per change (view Changes), plus baseline, skipped and error rows so you can see what happened to every page. A summary goes to the OUTPUT record.

Change row (from a test run; the old price was simulated by editing the stored baseline)

{
"type": "change",
"watchlist": "fq-test-main",
"checked_at": "2026-10-18T02:15:41.208Z",
"url": "https://basecamp.com/pricing",
"page_type": "pricing",
"domain": "basecamp.com",
"severity": "high",
"change_kind": "price_changed",
"summary": "\"Pro\" price changed from $79/month to $99/month (up 25.3%).",
"details": {
"plan": "Pro",
"from": { "amount": 79, "currency": "USD", "period": "month", "raw": "$79" },
"to": { "amount": 99, "currency": "USD", "period": "month", "raw": "$99" },
"change_pct": 25.3
},
"previous_checked_at": "2026-10-18T02:10:52.136Z"
}

change_kind values: price_changed, plan_prices_changed, plan_added, plan_removed, pricing_restructured, pricing_unparsed, pricing_text_changed, legal_text_changed, content_changed, pages_added, pages_removed, jobs_changed, careers_keywords_changed, new_entries, keyword_changed, reverted_to_seen_version, digest.

Digest row (mode: "digest", one per domain)

{
"type": "digest",
"change_kind": "digest",
"domain": "linear.app",
"severity": "high",
"summary": "linear.app weekly digest: \"Pro\" price changed from $12/month to $15/month. jobs: opened 2 in Engineering (Backend Engineer, Product Designer); closed 1 in Sales (Account Executive). tech: added Segment; removed Google Analytics.",
"details": {
"page_changes": [
{ "page_type": "pricing", "severity": "high", "change_kind": "price_changed", "summary": "…" }
],
"jobs": {
"status": "ok",
"opened": 2,
"closed": 1,
"opened_by_department": [{ "department": "Engineering", "count": 2, "titles": ["Backend Engineer"] }],
"closed_by_department": [{ "department": "Sales", "count": 1, "titles": ["Account Executive"] }]
},
"tech": {
"status": "ok",
"added": [{ "name": "Segment", "category": "Analytics" }],
"removed": [{ "name": "Google Analytics", "category": "Analytics" }],
"current_count": 12
}
}
}

jobs.status and tech.status are ok, baseline (first successful read; nothing is reported as opened, closed, added or removed yet), error or skipped. A quiet week is still one row. Page-change rows are still written alongside the digest. The digest row itself is not a separate charge.

Run summary (OUTPUT)

status, pages_checked, baselines, changes, changes_by_severity, unchanged, skipped, errors, requests, bytes_downloaded, browser_renders, events, webhook, duration_secs and a per-page list with notes such as 304 Not Modified or ROBOTS_DISALLOWED.

Pricing (pay per event)

EventPrice
Page checked (each page, job-board read or sitemap file fetched)$0.30 per 1,000
Change reported (at or above minSeverity)$4.90 per 1,000
Page rendered with the headless browser (optional)$5.90 per 1,000

Free: baselines beyond the page check, robots-blocked/skipped/error rows, discovery requests, confirmation re-reads, filtered A/B flips below minSeverity, and the digest row itself. Set a maximum cost per run in the run options and the Actor stops before exceeding it (baselines are not saved for pages it could not pay for, so nothing is lost).

Digest mode also starts Company Jobs Feed ($0.99 per 1,000 jobs and $0.50 per 1,000 boards on the free plan) and Website Tech, SEO and AI Readiness ($1.50 per 1,000 sites on the free plan). Those charges land on the same Apify account. Turn digestJobs or digestTech off to skip one of them. The jobs call uses onlyNew, so after the baseline you pay for new jobs, not for every open role.

ExampleChecks per monthCost
10 pages, daily300≈ $0.09 + changes
20 pages, hourly14,400≈ $4.32 + changes
100 pages, hourly72,000≈ $21.60 + changes

How it behaves (politeness and safety)

  • Public, no-login pages only. No cookies or sessions are kept, no logins, no CAPTCHA solving, no proxies to get around blocks.
  • robots.txt is respected (RFC 9309, longest match, Crawl-delay honoured; a host asking for more than 30 s is skipped). Disallowed pages are skipped and reported. 5xx/unreachable robots.txt = not crawled. Every redirect hop is re-checked.
  • Honest user agent: FairqueryChangeTracker/1.0 (+https://getfairquery.com; info@getfairquery.com).
  • Polite rate: one request at a time per host, at least 1.5 s apart (configurable, never below 1 s), at most 4 hosts in parallel. Conditional requests (ETag / If-Modified-Since) so unchanged pages often cost the site nothing.
  • Kill switch: an HTTP 403 or 429 stops all further requests to that host for the run.
  • Plain HTTP first. The headless browser is opt-in, only for JavaScript-rendered pages, still checks robots.txt, blocks images/fonts/media and keeps no state between pages.
  • Job boards are read through their documented public APIs (Greenhouse Job Board API, Lever Postings API, Ashby Public Job Posting API).
  • Private/internal addresses are refused (SSRF protection with DNS pinning; ports 80/443 only).

Memory / runtime

256 MB is enough for plain HTTP checks (a 24-page rerun took about 7–30 s in tests). Browser rendering needs 1024 MB or more. Default timeout 30 minutes.

Limitations

  • Plan parsing is heuristic. It works on most server-rendered pricing pages (tested on Basecamp, Linear, GitHub, GitLab, Zapier, Slack, Notion, Dropbox, Netlify, Tailscale and more), but usage-based pricing pages and calculators can produce odd plan names. Even then, changes are still caught by the section text comparison, and unchanged pages produce no false alerts.
  • Prices may vary by country, currency and A/B tests. Runs use Apify datacenter IPs (usually US). The confirmation re-read and version memory reduce, but cannot fully remove, variant noise.
  • JavaScript-only pricing pages need renderJs and 1 GB memory. Sites that block automated access are skipped, never worked around.
  • Freshness equals your schedule. Changes made and reverted between two runs are not seen.
  • If the same watchlist is run twice at the same time, the runs can overwrite each other's baselines. Schedule one run per watchlist at a time.
  • Baselines live in a named key-value store in your account until you delete it.

FAQ

How is this different from Visualping or Distill? Visualping and Distill are general-purpose website change monitors for almost any page; Visualping, for example, adds screenshots, AI change summaries and an important-or-not flag to every change. This Actor is narrower: it understands page types and returns, as structured rows, which plan's price moved and by how much, which legal section changed and which roles opened, ignoring dates, tokens and banners. It runs on your Apify schedule and is billed per check, with no monthly plan.

Does the first run report anything? No. It stores a baseline per page and outputs one baseline row per page (charged as a page check only).

Can I get alerts in Slack? Yes: set webhookUrl to a Slack incoming webhook and webhookFormat to slack. In watch mode, only changes at or above webhookMinSeverity (default medium) are sent, as one message per run. In digest mode, the run posts one message per domain; page lines in that message still respect webhookMinSeverity, and jobs and tech are always included.

Can I watch only part of a page? Yes. Set cssSelector on a page ("#pricing", "main .plans") or once for the whole run. The Actor compares that region only. A selector that matches nothing is reported as SELECTOR_NOT_FOUND and is not charged. Changing the selector saves a new baseline for the new region instead of diffing it against the old one. Job-board API URLs ignore the selector, because those pages are not read as HTML.

What is digest mode? Set mode to digest and schedule it weekly. Each domain gets one dataset row and, if you set a webhook, one payload: pricing, terms and changelog changes from this Actor, jobs opened and closed by department from Company Jobs Feed, and technologies added or removed since the previous digest. The first digest saves baselines and does not pretend every current job or technology is new.

Will it get my IP banned? It sends roughly one request per page per run, with honest identification, robots.txt and delays. If a site answers 403 or 429, the Actor stops contacting it for the rest of the run.

Is it real-time? No. It checks when it runs. Use an Apify Schedule for the frequency you need.

Fairquery family

Other Fairquery tools on the Apify Store. Each one returns structured rows with machine-readable error codes, and error rows are never charged:

All Fairquery Actors: https://apify.com/fairquery

Disclaimer

Fairquery is not affiliated with any of the sites mentioned. Page content belongs to its owners. Use the Actor only for public pages and in line with the sites' terms.