# Competitor Change Rollup — Weekly Watch Card (`zinin/competitor-change-rollup`) Actor

Watch one competitor's domain and get a weekly card of what actually changed — tech stack, hiring activity, and funding-filing mentions — rolled up from our own live lead-gen Actors. Run it on a schedule and stop manually re-checking three different tools every Monday.

- **URL**: https://apify.com/zinin/competitor-change-rollup.md
- **Developed by:** [Tim Zinin](https://apify.com/zinin) (community)
- **Categories:** Lead generation, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per event

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Competitor Change Rollup — Weekly Watch Card

Watch one competitor's domain and get a weekly card of what actually changed —
tech stack, hiring activity, and funding-filing mentions — rolled up from three of our
own live lead-gen Actors. Schedule it weekly and stop manually re-checking three
different tools every Monday.

### What you get

- One card per check: the first run establishes a baseline, every run after that
  reports ONLY what moved since last time — never a full re-summary you have to
  compare yourself.
- Three signals combined in one watch: tech-stack changes (new tools, CMS, ecommerce
  platform), hiring momentum shifts, and new SEC funding-filing mentions.
- Honest about uncertainty: a guessed hiring board is checked against its public
  owner signal when available. A confirmed mismatch is excluded from the snapshot
  and cannot create a paid change. Funding name matches remain unverified.
- A quiet week costs nothing — the "no changes" notice is free, you only pay when
  something real actually moved.
- Runs on Apify: schedule it weekly, call it from the API, export to JSON/CSV/Excel or
  push straight into your competitive-intel pipeline.

### How to run it

1. Click **Try for free** — no card needed on the free plan.
2. Paste the competitor's domain into **Competitor domain**.
3. Optionally set **Role keywords** to flag hiring for specific roles.
4. Hit **Start**. The first run creates the baseline; schedule it weekly to get a
   stream of change cards.

### Pricing

Pay-per-event: **$0.005 per run start + $0.05 per baseline
established / change detected**. The "no changes this week" notice and any error row
are never charged. 10 changes detected cost about $0.51 (the one-time start fee plus 10 billed rows).

### Input

| Field | Required | What it does |
|---|---|---|
| `domain` | yes | The competitor's domain to watch, e.g. `"stripe.com"`. |
| `role_keywords` | no | Words to match against open job titles (default: `["sales","marketing"]`). |
| `company_name_override` | no | Override our guessed ATS token/company name (see limitation below). |
| `baseline_key` | no | Name for this watch, in case you run more than one on the same domain. Defaults to the domain itself. |

```json
{
    "domain": "stripe.com",
    "role_keywords": ["sales", "marketing"]
}
```

### ⚠️ Important limitation: guessed company identity for 2 of the 3 signals

The tech-stack signal works directly off the domain — no ambiguity. The hiring and
funding signals need a company NAME or ATS token, not a domain, so by default we guess
one from the domain itself. **This guess can attach an unrelated company's data to your
watch — every week.** Verified live (same underlying issue as our own
lead-list-qualifier Actor): guessing
"example" as a company slug for `example.com` returned real hiring data for a
completely unrelated company that happens to sit under that token on one of the job
boards we check. Every row exposes `matchBasis`, `attributionConfirmed` (`true`,
`false`, or `null`), and `attributionEvidence`. A `false` hiring match is excluded and
any legacy misattributed hiring values are removed from the baseline without charging
for that correction. `null` means ownership evidence was unavailable, not confirmed. If you know
the competitor's real ATS token or legal entity name, set `company_name_override` to
remove the guesswork.

### Output

Baseline established (first run — real output, live run 30.07.2026):

```json
{
    "domain": "stripe.com",
    "baselineKey": "selftest-live-run",
    "found": true,
    "baselineCreated": true,
    "changed": false,
    "changedFields": [],
    "techStack": "Next.js,Nginx",
    "hiringMomentum": "aggressive hiring",
    "openRolesCount": 539,
    "matchedRolesCount": 112,
    "fundingFilingsSeenCount": 11,
    "companySlugUsed": "stripe",
    "identityConfidence": "guessed",
    "matchBasis": "guessed-domain",
    "attributionConfirmed": true,
    "error": "",
    "summary": "First check for \"stripe.com\" (watch \"selftest-live-run\") — baseline established (hiring/funding signals here are UNVERIFIED — guessed company slug, see README). Future weekly runs report only what changed.",
    "checkedAt": "2026-07-30T10:48:45.157Z"
}
```

Change detected (real output, live run 30.07.2026 — reproduced via a controlled
baseline change to prove the diff engine catches it, since a competitor's real headcount
doesn't reliably shift within seconds):

```json
{
    "domain": "stripe.com",
    "baselineKey": "selftest-live-run",
    "found": true,
    "baselineCreated": false,
    "changed": true,
    "changedFields": [
        { "field": "openRolesCount", "from": 1, "to": 539 }
    ],
    "newFundingFilingsCount": 0,
    "newFundingFilings": [],
    "identityConfidence": "guessed",
    "error": "",
    "summary": "Change detected for \"stripe.com\" (watch \"selftest-live-run\") (hiring/funding signals here are UNVERIFIED — guessed company slug, see README): openRolesCount: \"1\" -> \"539\".",
    "checkedAt": "2026-07-30T10:49:19.857Z"
}
```

| Field | Meaning |
|---|---|
| `found` | `true` for a real, billable result (baseline established or a real change); `false` for a notice/error row. |
| `baselineCreated` | `true` only on the first-ever run for this watch. |
| `changed` / `changedFields` | Whether anything moved since the last check, and exactly which field(s) with old/new values. |
| `techStack`, `ecommerce`, `cms` | Current tech-stack snapshot. |
| `hiringMomentum`, `openRolesCount`, `matchedRolesCount` | Current hiring snapshot, keyed on `companySlugUsed`. |
| `fundingFilingsSeenCount`, `newFundingFilingsCount`, `newFundingFilings` | Cumulative SEC filings seen for this watch, and any new ones this run — always check `newFundingFilings` yourself, see the limitation above. |
| `identityConfidence` | `"guessed"` or `"override"` — see the limitation above. |
| `matchBasis`, `attributionConfirmed`, `attributionEvidence` | How the hiring token was chosen and whether the board owner's public signal matched this domain. `null` is unknown. |
| `partial` / `partialReason` | `true` when some (not all) of the three sources failed to respond this run — whatever DID answer is still reported/billed. |
| `error` | Empty string when the check completed (including "nothing changed"); non-empty only when ALL THREE sources failed to respond. |

### Other tools we built

#### Related tools

Related tools for adjacent workflows in B2B lead generation and data enrichment, e-commerce.

| Actor | What it does |
|---|---|
| [Tech Stack Change Detector](https://apify.com/zinin/tech-stack-change-detector) | Pair it in the B2B lead generation and data enrichment workflow: Detect a website's current technologies (CMS, ecommerce, analytics, marketing/CRM, framework, hosting/CDN,... |
| [Company Profile Lookup](https://apify.com/zinin/company-lookup) | Pair it in the B2B lead generation and data enrichment workflow: Turn a domain or company name into one unified company card: website tech stack (CMS, ecommerce, key tech)... |
| [Company Hiring Radar](https://apify.com/zinin/company-hiring-radar) | Pair it in the B2B lead generation and data enrichment workflow: Pull every open role a company is hiring for from its public job board (Greenhouse, Lever, Ashby) and turn... |
| [Shopify Price Change Monitor](https://apify.com/zinin/shopify-price-change-monitor) | Pair it in the e-commerce workflow: Watch a list of Shopify stores and get alerted when their price range, catalog size, or estimated revenue... |
| [B2B Lead Enricher](https://apify.com/zinin/b2b-lead-enricher) | Pair it in the B2B lead generation and data enrichment workflow: Turn a list of company websites into sales-qualified lead cards: detected tech stack, a rough revenue... |

### FAQ / Limitations

**Can I watch several competitors?** Yes — run one watch per domain (each gets its own
`domain`/`baseline_key`); this Actor scores one competitor per run.

**What happens if I change `role_keywords` or `company_name_override` for an existing
watch?** The watch keeps comparing against whatever it last saw, so changing settings
can produce a "change detected" row that simply reflects the new settings, not a real
change at the competitor. Use a new `baseline_key` for an intentionally different watch.

**What this is NOT.** This is not a verified company database and does not confirm
that the domain and a matched hiring board or funding filing are the same legal
entity — see the limitation section above. It is a change-tracking heuristic, not proof.

Found a bug or need another signal rolled into the card? Issues on the Actor's page.

# Actor input Schema

## `domain` (type: `string`):

The competitor's domain to watch, e.g. "stripe.com".

## `role_keywords` (type: `array`):

Highlight when this competitor is hiring for roles matching these words (passed to our company-hiring-radar Actor).

## `company_name_override` (type: `string`):

By default this Actor guesses the company's ATS token / name from the domain itself (e.g. "stripe.com" -> "stripe") for the hiring and funding checks — this is a best-effort heuristic, not a verified identity, and CAN be wrong (see README). Set this if you know the real ATS token or legal name.

## `baseline_key` (type: `string`):

A name for this watch, in case you want to run more than one watch on the same domain with different settings. Defaults to the domain itself.

## Actor input object example

```json
{
  "domain": "stripe.com",
  "role_keywords": [
    "sales",
    "marketing"
  ]
}
```

# 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 = {
    "domain": "stripe.com",
    "role_keywords": [
        "sales",
        "marketing"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("zinin/competitor-change-rollup").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 = {
    "domain": "stripe.com",
    "role_keywords": [
        "sales",
        "marketing",
    ],
}

# Run the Actor and wait for it to finish
run = client.actor("zinin/competitor-change-rollup").call(run_input=run_input)

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

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

```

## CLI example

```bash
echo '{
  "domain": "stripe.com",
  "role_keywords": [
    "sales",
    "marketing"
  ]
}' |
apify call zinin/competitor-change-rollup --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=zinin/competitor-change-rollup",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/9NyKsYNMgsPu4eSqp/builds/WsF9TpERBaEwUtaah/openapi.json
