SaaS Competitor Monitor: Pricing, Changelog & Positioning
Track a competitor's SaaS pricing, changelog and positioning on a schedule. You get only what changed, sent to Slack. $0.01 per page checked.
How it works
- 1Open it on Apify
Hit Run on Apify — it opens the tool in the cloud, no install.
- 2Set the inputs
Adjust
competitors,watch,weeklyBrief(sensible defaults are pre-filled). - 3Click Run
The tool runs on Apify’s cloud and collects the data for you.
- 4Export the results
Download as JSON, CSV or Excel, or pipe straight into your app, Google Sheets, or an AI agent.
Pricing
$0.01 per page checked = $10 per 1,000
| You are charged for | When | Price |
|---|---|---|
| Page checked | A page was checked | $0.01 |
| Weekly brief generated | A weekly brief was generated | $0.3 |
| AI signal generated | An AI signal was generated | $0.035 |
| Change detected | A change was detected | $0.015 |
Pay-per-event pricing: you are billed per result, not per subscription. Billing is handled by Apify on your own account. These are the live Apify store prices, in effect since 2026-06-09, and they are what you are actually charged.
Inputs
| Field | What it does | Type |
|---|---|---|
competitors | The competitors to monitor. For each, provide a name and the URLs you want watched. Leave a URL empty to skip that page type for that competitor. | array |
watch | Which page types to monitor. 'pricing' tracks tiers/prices/CTAs/features, 'changelog' tracks release entries, 'positioning' tracks homepage hero & CTA, 'integrations' scans docs/changelog for new integrations. | array |
weeklyBrief | Produce a readable HTML/Markdown brief summarizing every competitor move this run, stored in the Key-Value Store and linked in the dataset. | boolean |
onlyNewSinceLastRun | Emit only the deltas (new/changed targets) instead of a full re-dump every run. This is what makes scheduled runs cheap and useful. | boolean |
generateAiSignals | Use a small LLM to sharpen the 'why it matters' analysis on each detected change. Runs ONLY on changed pages (never on unchanged ones). Requires the ANTHROPIC_API_KEY environment variable; falls back to deterministic rules if absent. | boolean |
webhookUrl | Slack, Discord, or generic webhook to receive a compact summary of new signals. Slack/Discord formatting is auto-detected. | string |
What you get
A structured dataset — each result includes fields like:
change_recordscompetitorpage_typesignalsstatussync_statustarget_keyurlExport every run as JSON, CSV or Excel, or send it to your app, a database, Google Sheets, or an AI agent.
4 ready-to-run use cases
Competitor Price Tracking for Notion and Linear
Watches both pricing pages and flags the tier, number or call-to-action that moved. Typed signals, not a screenshot diff you have to read yourself.
Website Change Monitoring for a Rival's Changelog
Reads a competitor's changelog each run and posts only the new entries to your Slack or Discord webhook. Paste your own webhook URL to switch it on.
Competitive Intelligence Tool: One Rival, Every Page
Pricing, changelog, homepage and integrations for a single company in one scan. The first run stores a baseline, so changes show from run two.
Competitor Monitoring Tool: Weekly Brief on 5 Rivals
Every move five competitors made this week, pricing through homepage, in one digest. Run it Monday morning and the standup writes itself.
Related tools in Monitors & Alerts
Other ready-to-run tools in the same category — all pay-per-use on the Apify cloud.
RFP & Tender Fit Monitor — Bid/No-Bid Scoring & Alerts
Watch TED, UK Find a Tender and SAM.gov for new tenders. You get a bid/no-bid fit score, deadlines and eligibility flags.
Structured Product Price & Stock Monitor — JSON-LD / Shopify
Track product price and stock from a store's own JSON-LD or Shopify data. Restock, price-drop and sale alerts into Slack or Discord. No API key.
Google Reviews Monitor — Multi-Location Alerts & Reports
Watch Google reviews for every location on a schedule. Get only the new ones, rating-drop alerts in Slack and AI reply drafts. $1.00 per 1,000 reviews.
YouTube Channel Monitor — New Upload Tracker
Watch YouTube channels and get only their new uploads: title, URL, publish date, views, thumbnail. $0.01 per new video.
App Review Triage Monitor — App Store & Google Play Alerts
Sort new App Store and Google Play reviews into bugs, billing and feature requests. Get alerts on rating drops in Slack. $0.40 per 1,000 reviews.
Where this tool sits
SaaS Competitor Monitor: see when a rival's pricing, changelog or homepage changes
Give it your competitors' pricing, changelog, homepage and docs URLs, run it on a schedule, and it tells you what moved since last time: a price that went up, a plan that appeared, a new release, a rewritten headline. Each change comes back as a typed signal with its before and after, ready for a brief or a Slack or Discord alert. Know two things first: the first run only records a baseline, so changes start on the second, and the page reading is heuristic, so a page that shows different prices on different loads can read as a change that never happened.
| Input | Competitor names with their pricing, changelog, homepage and docs URLs |
| Output | One row per page that is new, changed or failed, plus one brief row per run |
| Ceiling | No page cap: every URL you list is checked, within the run's time limit |
| Account needed | None on the sites you watch, and pages behind a login cannot be watched |
| Price | $0.01 per page checked, $0.015 per change, $0.30 per brief. Signals the built-in rules write are free |
🔍 What SaaS Competitor Monitor does
It reads four kinds of page for each competitor:
| Page | What it reads |
|---|---|
Pricing (pricingUrl) | Plan names, prices, buttons and features, and plans added or removed |
Changelog (changelogUrl) | Release entries |
Positioning (homepageUrl) | The main headline, the hero text and the primary button |
Integrations (docsUrl) | New integrations named on the page |
Every page is compared with the copy saved from the last run. That copy lives in a key-value store called saas-competitor-change-monitor-state, in your own Apify account, one record per competitor and page. Records are keyed by the competitor's name, so two tasks using the same name share one history, and renaming a competitor starts its history again.
A page that cannot be read comes back failed and is not charged, and the last good copy stays the baseline. Pages that only fill in after scripts run are drawn in a browser, which waits until the text stops growing; a page still drawing after 30 seconds fails, unbilled.
The "why it matters" line on each signal is written by built-in rules. The Generate AI insights switch is meant to have a language model sharpen it, but it needs a model key this actor does not have and you cannot supply, so the rules write it every time. A signal the rules wrote is not charged.
When page reading is improved, a page saved by the older reader shows as new once, so a better reading is never billed as a change.
📥 What you give it
{
"competitors": [
{
"name": "Acme",
"pricingUrl": "https://acme.com/pricing",
"changelogUrl": "https://acme.com/changelog",
"homepageUrl": "https://acme.com",
"docsUrl": ""
}
],
"watch": ["pricing", "changelog", "positioning", "integrations"],
"onlyNewSinceLastRun": true,
"weeklyBrief": true
}
| Field | Default | What it is |
|---|---|---|
competitors | none, required | Each competitor: a name, plus pricingUrl, changelogUrl, homepageUrl and docsUrl. Leave a URL empty to skip that page. The form arrives with an example called Acme; replace it. |
watch | all four | pricing, changelog, positioning, integrations. Which pages to check. |
weeklyBrief | true | Writes a Markdown and an HTML brief of the run's signals. It is $0.30 on every run it is on for, a quiet one included. |
onlyNewSinceLastRun | true | Rows only for pages that are new, changed or failed. Off, every page checked gets a row. |
generateAiSignals | true | Falls back to the built-in rules on every run, as explained above. It has no effect on the price. |
webhookUrl | empty | A Slack, Discord or other webhook. It gets a short summary, and only on runs that found a signal. |
proxyConfiguration | {"useApifyProxy": true} | Leave it as it is, or add your own servers here if you want pages fetched through them. |
📤 What you get back
A real row from a test run on 30 September 2026. Before that run the saved Growth price had been edited to $12, so Plausible's live $14 came back as a rise. The two text values are cut short:
{
"target_key": "zz-fix-test-plausible::pricing",
"competitor": "ZZ Fix Test Plausible",
"page_type": "pricing",
"url": "https://plausible.io/#pricing",
"status": "changed",
"sync_status": "ok",
"signals": [
{
"competitor": "ZZ Fix Test Plausible",
"signal_type": "price_change",
"detail": "Growth: $12/month ...",
"before": "$12",
"after": "$14",
"why_it_matters": "ZZ Fix Test Plausible raised Growth by +17% ...",
"page_type": "pricing",
"url": "https://plausible.io/#pricing",
"detected_at": "2026-09-30T04:58:17.608841+00:00",
"is_new": false,
"is_changed": true,
"ai_written": false
}
],
"change_records": [
{
"target": "zz-fix-test-plausible::pricing",
"change_type": "modified",
"path": "tiers.Growth.price",
"before": "$12",
"after": "$14",
"detected_at": "2026-09-30T04:58:17.609156+00:00"
},
{
"target": "zz-fix-test-plausible::pricing",
"change_type": "modified",
"path": "tiers.Growth.price_amount",
"before": 12,
"after": 14,
"detected_at": "2026-09-30T04:58:17.609156+00:00"
}
]
}
And the brief row from a run on 30 September, with its link cut short:
{
"type": "weekly_brief",
"generated_at": "2026-09-30T02:33:59.840901+00:00",
"signal_count": 0,
"brief_kv_key": "weekly-brief-html",
"brief_url": "https://api.apify.com/v2/key-value-stores/.../records/weekly-brief-html?signature=..."
}
| Field | What it is |
|---|---|
target_key | <competitor>::<page>, where the page is pricing, changelog, homepage or docs. |
status, sync_status | new, changed, unchanged or failed; and ok or failed for the reading itself. |
signals | The typed changes: price_change, plan_added, plan_removed, feature_moved, cta_change, positioning_shift, new_integration or changelog_entry, each with detail, before, after and why_it_matters. ai_written is true only when a language model wrote the why_it_matters line, the one case where a signal is charged. |
change_records | Every field that moved, by path, such as tiers.Growth.price, with its before and after. |
signal_count, brief_url | On the brief row: how many signals the run found, and a link to the HTML brief. The Markdown version is in the run's key-value store under weekly-brief. |
🧾 Reading the output
There is no sample row and no error code. Every row is either a page or the brief:
| Row | How to spot it | Charged |
|---|---|---|
| A page seen for the first time | status: "new". No signals: this is the baseline | as a page check |
| A page that moved | status: "changed", with change_records and usually signals | a page check and a change, plus each signal marked ai_written: true |
| A page that did not move | status: "unchanged". Only written with onlyNewSinceLastRun off | as a page check |
| A page that could not be read | status: "failed". url is empty and competitor holds the lower-case short name, so go by target_key; the run log says why | no |
| The brief | type: "weekly_brief" | $0.30 |
Not every change becomes a signal. A field that moved without matching a rule shows up in change_records only, and still counts as a change. For news you would act on, keep the rows where status is changed.
▶️ How to run it
1. Open SaaS Competitor Monitor and click Try for free. 2. In Competitors, replace the Acme example with your own: a name and the URLs to watch. 3. Choose What to watch, and untick Generate weekly competitive brief on runs where you do not want the $0.30 brief. 4. Paste a Slack or Discord address into Webhook URL (optional) if you want alerts. 5. Click Start once to record the baseline, then put the same input on a schedule.
💰 How much does it cost?
$0.01 per page checked, $0.015 per page that changed and $0.30 per brief, flat on every Apify plan.
Signals cost nothing while the built-in rules write them, and today they write every one. A signal is only charged, at $0.035, when a language model wrote its "why it matters" line, and that signal carries ai_written: true.
Every page read is charged, changed or not; a failed page is not. The brief is billed on every run it is on for, so a daily schedule with the brief on is $2.10 a week in briefs alone. Switch it on for one run a week instead.
If you set a maximum charge for a run, it checks only the pages it can still pay for, leaves the rest for the next run, and skips the brief if it no longer fits.
💡 What people use it for
- Knowing the week a rival raises a plan, before a customer brings it up on a sales call.
- Keeping a battlecard's pricing column honest without anyone opening five pricing pages on Monday.
- Reading a competitor's releases in one weekly brief instead of following four changelogs.
- Catching a homepage rewrite, which can be the first public sign they are chasing a different buyer.
🚧 What it does not do
- No AI. The "why it matters" line comes from rules, whatever the switch says.
- No pages behind a login. A page that answers with an error or a holding screen instead of
content comes back failed too.
- No screenshots or visual diff. It compares the text and structure it reads.
- No perfect reading of pricing pages. Plans are found by rules. Scored on 40 real pricing pages,
it found 135 of 144 plans; it can mistake a menu item or a calculator for a plan, miss a free plan shown only as the word "Free", and read part of a tabbed plan layout.
- No defence against A/B tests. A page that shows a price on some loads and not on others reads
as a change, and the change is billed.
- No archive. Only the latest good copy of each page is kept. The dataset of each run holds
what changed on that run.
🧭 Which competitor monitor do you need?
| If you want | Use |
|---|---|
| Changes on a rival SaaS site's pricing, changelog, homepage and docs | This one |
| Price and stock moves on product pages | Product Price & Stock Monitor |
| What reviewers say about a rival's software | G2 Reviews Scraper |
| A rival's Facebook and Instagram ads | Meta Ad Library Scraper |
| A rival's traffic, rank and audience | Similarweb Traffic and Rank Scraper |
❓ Questions people ask
Why did the first run report everything as new? There was nothing to compare against yet. The first run saves a copy of each page; from the second run on you get real changes.
Where does it keep last week's pages? In the saas-competitor-change-monitor-state store in your own account. Delete it to start over, and the next run builds a fresh baseline.
Will I be charged when nothing changes? For the page checks, yes, and for the brief if it is on. A change is only charged when a page reads differently from last time.
How do I get alerts in Slack? Put your Slack incoming-webhook address in webhookUrl. Discord and other webhooks work the same way. Nothing is sent on a run that found no signal.
🆘 If something breaks
Open the Issues tab on the actor page. Send the run ID and the competitor URL that misbehaved, and say what the page showed that the row did not.