# Company Change Monitor (Weekly Signals for Company Lists) (`locaihost/company-change-monitor`) Actor

Weekly change alerts for company lists. Watch competitors, prospects or a portfolio and see what changed at each company (jobs, tech, reviews, ads, pricing), with the reason. Unchanged rows can be free. $6 per 1,000 at basic depth, $25 full.

- **URL**: https://apify.com/locaihost/company-change-monitor.md
- **Developed by:** [locaihost data](https://apify.com/locaihost) (community)
- **Categories:** Lead generation, Business, Marketing
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.30 / 1,000 company update (monitor)s

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Company Change Monitor (Weekly Signals for Company Lists)

Give it the companies you watch, such as competitors, prospects or a portfolio, and run it every week. Each run lists what changed at each company since the last run: open jobs, tech stack, reviews, ads, pricing and key pages. Every signal comes with a plain-English reason. Companies with no changes can cost nothing.

```json
{
    "companies": ["zapier.com", "monzo.com", "gymshark.com"],
    "watchName": "competitors",
    "onlyChanged": true
}
```

Press Start. The first run saves a baseline for each company. From the second run on, every row says `changed` or `unchanged`, and what moved.

### The Monday list

Every Monday you open one table. Say you watch 200 competitors: most rows say `unchanged` and cost nothing. Twelve say `changed`, and each says why. Acme went from 20 to 31 open jobs, 6 of them in Engineering. Initech swapped HubSpot for Salesforce. Globex added a pricing plan and its Trustpilot rating fell from 4.5 to 4.1. Those twelve rows are the week's reading.

### Schedule it weekly

1. Open this Actor, paste your list, set **Watch list name** (for example `competitors`) and turn on **Charge only changed companies**. Click **Start**. That run is the baseline.
2. Click **Save as a new task**, so the same input is used every week.
3. In Apify Console, open **Schedules** in the left menu and click **Create new**. Pick weekly (for example Monday 07:00 in your time zone), then **Add** the task you saved.
4. Optional: on the task's **Integrations** tab, send each finished run to Slack, email, Google Sheets or a webhook.

Each week's run has its own dataset; open the **Changes** view first. Keep the same `watchName` and list: each company is compared with its own last snapshot. A company you add later starts with its own baseline. Different lists (`competitors`, `prospects`) are kept apart, so one account can watch several.

### What you get per company

```json
{
    "name": "Acme",
    "domain": "acme.com",
    "monitorStatus": "changed",
    "changes": [
        { "field": "hiring.openJobs", "label": "Open jobs", "old": 20, "new": 31, "since": "2026-10-28T06:00:00.000Z" },
        { "field": "tech.technologies", "label": "Technologies", "added": ["Salesforce"], "removed": ["HubSpot"] }
    ],
    "signals": [
        { "key": "hiring-fast", "label": "Hiring fast", "reason": "Open jobs 20 → 31 (+55%); +6 Engineering" },
        { "key": "new-tech", "label": "Tech stack changed", "reason": "added Salesforce; removed HubSpot" }
    ],
    "changedSince": "2026-10-28T06:00:00.000Z",
    "snapshotAt": "2026-10-28T06:00:00.000Z",
    "stale": []
}
```

The full company row comes with it (firmographics, web, tech, hiring, reviews, marketing, money, compliance, sources and confidence per field), so a changed company never needs a second lookup.

- `monitorStatus`: `first-run` (baseline saved), `changed`, `unchanged`, or `not-read` (the company could not be read this time: free, and its snapshot is kept).
- `changes`: field, old value, new value and the date of the snapshot it was compared with. Lists give `added` and `removed`.
- `signals`: what is worth acting on, each with its numbers.
- `stale`: fields this run could not read, or that came back empty for the first time. Their last values are kept and they are not reported as changes.
- `siteChanges`: headings added or removed on the home, pricing and about pages, and new pages in the sitemap.

### What counts as a change

| Watched | Counts as a change when |
|---|---|
| Open jobs | It moves 10% and by at least 2 |
| Monthly visits, global rank | It moves 10% |
| Review ratings (Trustpilot, Sitejabber, Google Maps) | It moves 0.1 or more |
| Review counts | They move 1% and by at least 5 |
| Ads seen (Google, Meta, LinkedIn) | The count moves by 2 or more |
| Instagram followers, YouTube subscribers | They move 2% |
| Employees on LinkedIn | It moves 2% and by at least 5 |
| Technologies, pricing plans, customer logos, integrations, certifications | Anything is added or removed (order never matters) |
| Name, HQ city, industry, employee band, jobs platform, email provider, CMS, e-commerce platform, registry status, sanctions screening | The value is different (case and spacing ignored) |

Small moves under these thresholds are not changes, and the baseline is kept, so slow drift still shows once it adds up.

**Signals** sit on top of the changes:

| Signal | When |
|---|---|
| Hiring fast | 10+ open jobs, and up 30% since the last run or +5 in Engineering, Sales, Product, Data or Marketing |
| Hiring slowed | From 5+ open jobs, down by half or to none |
| Hiring in a new country | Jobs in a country the last run didn't have |
| New ads | Google, Meta or LinkedIn ads from none to some, or up 50% and by at least 3 |
| Traffic up or down | Monthly visits move 25% |
| Rating dropped | A review rating falls 0.3 or more, or the Trustpilot reply rate halves (from 20% or more) |
| Tech stack changed, pricing changed, new integrations, new customer logos | Anything added or removed (for prices: a new plan, a dropped plan, or a new price) |
| Website redesigned, new pages | Most homepage headings changed, or 5+ new pages in the sitemap |

Every run also carries the standing signals: raised money (Form D in 90 days), won a public contract, sponsors visas, running ads, in the news, shipping fast.

**No false alarms from outages.** If a source can't be read this run (a site refuses, a request times out), its fields go to `stale`, the old values are kept and nothing is reported as changed. The same goes for a source that depends on one that failed. A value that suddenly comes back empty (a job board that didn't answer this time) is held as `stale` and reported as gone only if the next run finds it empty too. An empty list right after a full one is treated as a read problem, not "everything removed".

### Why unchanged companies are free

With **Charge only changed companies** (`onlyChanged`) on, an unchanged company gets a short row (who, `unchanged`, since when) and no charge. A quiet week costs almost nothing, and you pay for the companies that moved. The thresholds above keep small wobbles out, so `changed` means a real change. First runs and changed companies are full rows and are charged.

### Price

Pay per company checked, on the Starter tier. Scale pays 25% less and Business 45% less.

| Event | When it is charged | Price per 1,000 |
|---|---|---|
| `company-update` | A company checked: first run, changed, or unchanged with `onlyChanged` off | $6 |
| `company-full` | The same, at full depth (the default) when a full-depth source (traffic, LinkedIn, Google Maps, Meta or LinkedIn ads) returned data; charged instead of `company-update` | $25 |
| `name-lookup` | Add-on: a company given by name only that needed a web search to find its website (domains never pay it) | $4 |
| `review-insights` | Add-on, only with the API input `includeReviewInsights: true`: a company that has review insights | $3 |
| `apify-actor-start` | Once per run | $0.05 (so $0.00005 a run) |

**Free:** unchanged companies with `onlyChanged` on, companies not found, not readable this run (`not-read`) or not a company.

The price list also has `company-basic` ($6 per 1,000) for plain enrich runs; this Actor runs in monitor mode, so it charges `company-update` instead.

Example: a weekly schedule over 500 companies given by domain, with `onlyChanged` on, costs at most $3 a week at `"depth": "basic"` and at most $12.50 a week at full depth, and less in quiet weeks.

### Honest limits

- **Organisations only.** No people: no names, personal emails, phone numbers, employee lists, officers or domain registrant details. For decision-makers, use the Company Enrichment Actor below.
- **Logged-out, public data only.** We never log in.
- **A change is only as good as the read.** Some sources refuse requests now and then (LinkedIn, Meta, Google, review sites). That source then shows in `stale` for that company, and a real change there waits until a run can read it.
- **G2 and Capterra** are not read in this version: their pages refuse requests from cloud servers.
- **Estimates are labelled.** Traffic numbers are Similarweb's estimates; a change in them is a change in the estimate.
- **The first run has nothing to compare with.** It saves the baseline and reports no changes.
- **If a run stops early** (time limit or your maximum charge), the companies it did not reach keep their old snapshot and are compared next time. A change is saved only once its row was delivered to you, so you never miss one.
- Snapshots live in a named key-value store in your own account (`company-change-monitor-state`). Deleting it starts every list over.

### FAQ

#### How often should I run it?

Weekly suits most lists: jobs, ads and pricing move on that scale. Daily works too, but most companies will say `unchanged`.

#### Can I add or remove companies later?

Yes. A new company starts with its own baseline; a removed one is simply not checked. Keep the same `watchName`.

#### Can I use it through the API or from an AI agent?

Yes. Call it like any Apify Actor through the Apify API, connect runs to Zapier, Make or n8n, or use it from an AI assistant through Apify's MCP server.

### Lawful use

Use the data lawfully: for B2B research, competitor tracking, account planning and compliance checks. You are responsible for how you use it under the laws that apply to you, including privacy and marketing rules.

Need one-off rows with no comparison, or decision-makers with work emails? Use [Company Enrichment by Domain or Name](https://apify.com/locaihost/company-enrichment): same data, same sources.

Did it help? A rating helps others find it.

Questions or a correction: apify@locaihost.org

# Changelog

This Actor's version history is a separate document: https://apify.com/locaihost/company-change-monitor/changelog.md

# Actor input Schema

## `companies` (type: `array`):

The companies to watch: a website domain ("stripe.com"), a website address, or a company name ("Monzo"). Keep the same list on every run: each company is compared with its own last snapshot. For several companies with the same name, add the country: {"name": "Sage", "country": "GB"}.

## `watchName` (type: `string`):

Keeps separate lists apart in your account: "competitors" and "prospects" each remember their own companies. Use the same name on every run of a list. Leave empty for one default list.

## `onlyChanged` (type: `boolean`):

Companies with no change since the last run get a short free row (who, unchanged, since when) instead of a full charged one. First runs and changed companies are full rows. Turn it on for weekly schedules.

## `companiesFile` (type: `string`):

A public CSV link, a Google Sheet shared as "anyone with the link", or the key of a CSV in this run's key-value store. Columns are found by their header: domain (or website, url), company (or name) and country. Its companies are added to the list above.

## `depth` (type: `string`):

Basic reads the sources a plain web request can reach (about 10 seconds a company). Full adds website traffic estimates, the LinkedIn company page (employee band, industry), Google Maps (rating, locations), Meta and LinkedIn ad counts and the competitors section (up to 30 seconds a company). Basic checks cost $6 per 1,000; a check is charged the full price ($25 per 1,000) only when a full-depth source returned data. G2 and Capterra are not read in this version.

## `sources` (type: `array`):

Leave empty for all. Basic: site, dns, jobs, visa, trustpilot, sitejabber, googleAds, youtube, instagram, apps, sec, formD, registry, ukContracts. Full depth: traffic, linkedin, metaAds, linkedinAds, maps. Section keys (see Sections) work here too. Sources another one needs are added automatically (jobs needs site).

## `icp` (type: `object`):

Optional. Scores every company 0 to 100 against who you sell to, with the reasons. Fields: industries, countries (ISO codes), employeesMin, employeesMax, requiredTech, forbiddenTech, minMonthlyVisits. Unknown facts count half, a ruled-out technology scores 0.

## `maxCompanies` (type: `integer`):

Stop after this many companies (0 = all, up to 5,000 per run). Companies past the limit keep their last snapshot.

## `concurrency` (type: `integer`):

How many companies are read at the same time (1 to 16). Lower it if you run on less memory.

## `mode` (type: `string`):

Monitor compares each company with its last snapshot. Enrich gives plain rows with no comparison. Always "monitor" in this Actor.

## `includePeople` (type: `boolean`):

Not used by the monitor: people come from the Company Enrichment Actor. Always off here.

## Actor input object example

```json
{
  "companies": [
    "zapier.com",
    "monzo.com",
    {
      "domain": "gymshark.com",
      "name": "Gymshark"
    }
  ],
  "watchName": "competitors",
  "onlyChanged": false,
  "depth": "full",
  "sources": [],
  "icp": {
    "countries": [
      "US",
      "GB"
    ],
    "requiredTech": [
      "HubSpot"
    ],
    "forbiddenTech": [
      "Salesforce"
    ]
  },
  "maxCompanies": 0,
  "concurrency": 6,
  "mode": "monitor",
  "includePeople": false
}
```

# Actor output Schema

## `changes` (type: `string`):

One row per company: changed, unchanged or first run, what changed (old and new) and the signals.

## `companies` (type: `string`):

The same rows with every section and its sources.

## `hubspot` (type: `string`):

Charged companies under HubSpot company property names.

## `salesforce` (type: `string`):

Charged companies under Salesforce Account field names.

## `summary` (type: `string`):

How many changed, which fields changed most, which sources answered, and the measured cost.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "companies": [
        "zapier.com",
        "monzo.com",
        "gymshark.com"
    ],
    "watchName": "competitors"
};

// Run the Actor and wait for it to finish
const run = await client.actor("locaihost/company-change-monitor").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "companies": [
        "zapier.com",
        "monzo.com",
        "gymshark.com",
    ],
    "watchName": "competitors",
}

# Run the Actor and wait for it to finish
run = client.actor("locaihost/company-change-monitor").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "companies": [
    "zapier.com",
    "monzo.com",
    "gymshark.com"
  ],
  "watchName": "competitors"
}' |
apify call locaihost/company-change-monitor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,locaihost/company-change-monitor"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/DxWS49gAqcm1spjad/builds/CcEFQG62tqKcplqWK/openapi.json
