# X Follower Tracker (`automation-lab/x-follower-change-monitor`) Actor

Monitor public X follower and following counts across snapshots. Get profile metadata plus absolute and percentage audience-growth changes without cookies or login.

- **URL**: https://apify.com/automation-lab/x-follower-change-monitor.md
- **Developed by:** [Stas Persiianenko](https://apify.com/automation-lab) (community)
- **Categories:** Social media
- **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.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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

## X Follower Tracker

Monitor public X account follower and following counts across recurring snapshots.

**X Follower Tracker** turns public handles or `x.com` profile URLs into typed audience snapshots.
On the first run it records a baseline.
On later runs with the same `monitorId`, it returns absolute and percentage changes.

Use it for influencer marketing, competitor reporting, brand audience tracking, and scheduled data pipelines.
It reads public profile totals only.
It does not export follower identities, access protected accounts, or require X cookies.

### What does X Follower Tracker do?

For every requested public account, the Actor:

1. validates and normalizes the handle or profile URL;
2. reads the current public X profile;
3. extracts profile identity and follower/following totals;
4. loads the last successful snapshot for the same `monitorId`;
5. calculates absolute and percentage changes;
6. saves the current successful snapshot for the next run;
7. emits one typed dataset record.

A missing or unavailable profile is emitted with `state: "unavailable"`.
The last successful snapshot is preserved, so a temporary outage does not replace a useful baseline.

### Who is it for?

#### Influencer marketing teams

Compare public audience growth before and after campaigns.
Use the absolute delta for reporting and the percentage delta to compare accounts of different sizes.

#### Competitive-intelligence teams

Schedule one Task with a stable list of competitor handles.
Export each run to a spreadsheet, warehouse, webhook, Make, or Zapier workflow.

#### Brand and social teams

Track first-party and competitor account totals without maintaining X API credentials.
A stable `monitorId` keeps each reporting workflow independent.

#### Developers and data teams

Receive predictable JSON through the Apify API, JavaScript client, Python client, or MCP.
Each processed account produces one row, including unavailable accounts.

### Why use this Actor?

- **Stateful change tracking:** it calculates deltas instead of returning only a current count.
- **No cookies or login:** the selected workflow uses publicly visible account data.
- **Handles and URLs:** mix `apify`, `@github`, and `https://x.com/elonmusk` in one input.
- **Availability states:** distinguish a missing profile from a successful zero-change snapshot.
- **Small typed records:** suitable for schedules, alerts, spreadsheets, and warehouses.
- **Count-only scope:** avoids the cost and privacy surface of follower-list exports.

### What data is extracted?

| Field | Meaning |
| --- | --- |
| `handle` | Normalized public X handle |
| `profileUrl` | Canonical `x.com` profile URL |
| `displayName` | Current public display name |
| `userId` | Stable numeric X user ID when available |
| `bio` | Public profile biography |
| `location` | Public profile location |
| `avatarUrl` | Public avatar URL |
| `isVerified` | Public verification flag |
| `followerCount` | Current follower total |
| `followingCount` | Current following total |
| `followerDelta` | Absolute follower change since the previous successful snapshot |
| `followerDeltaPercent` | Percentage follower change since the previous successful snapshot |
| `followingDelta` | Absolute following change |
| `followingDeltaPercent` | Percentage following change |
| `state` | `first_seen`, `changed`, `unchanged`, or `unavailable` |
| `snapshotAt` | Current check time in ISO 8601 format |
| `previousSnapshotAt` | Previous successful snapshot time, or `null` |
| `monitorId` | History namespace selected in the input |
| `error` | Availability note for unavailable profiles, otherwise `null` |

Fields that X does not expose for an unavailable account are `null`.

### How to get started

1. Open the Actor input page.
2. Add one or more public X handles or profile URLs to **X accounts**.
3. Choose a stable **Monitor ID** for this reporting workflow.
4. Enable **Reset baseline** only when you intentionally want a fresh starting point.
5. Click **Start**.
6. Inspect the **Follower changes** dataset view.
7. Run again with the same `monitorId` to receive change values.
8. Create an Apify Schedule when you need daily, weekly, or monthly tracking.

For a clean first measurement, use `resetBaseline: true`.
For normal scheduled runs, keep it `false`.

### Input parameters

| Parameter | Type | Default | Description |
| --- | --- | --- | --- |
| `accounts` | string array | required | Public X handles, `@handles`, or `x.com`/`twitter.com` profile URLs |
| `monitorId` | string | `default` | Stable 1–64 character namespace for snapshot history |
| `resetBaseline` | boolean | `false` | Ignore the previous snapshot and replace the baseline with this run |
| `maxItems` | integer | `10` | Maximum unique accounts processed, from 1 to 500 |

Example input:

```json
{
  "accounts": [
    "apify",
    "@github",
    "https://x.com/elonmusk"
  ],
  "monitorId": "competitor-growth-report",
  "resetBaseline": false,
  "maxItems": 3
}
```

Duplicate handles are processed once.
Handles are case-insensitive.
Non-profile paths and non-X hosts fail input validation.

### Output example

A first successful snapshot looks like this:

```json
{
  "handle": "apify",
  "profileUrl": "https://x.com/apify",
  "displayName": "Apify",
  "userId": "3510729917",
  "bio": "Thousands of Actors to automate your business...",
  "location": "The Interwebz",
  "avatarUrl": "https://pbs.twimg.com/profile_images/..._400x400.png",
  "isVerified": false,
  "followerCount": 10315,
  "followingCount": 296,
  "followerDelta": null,
  "followerDeltaPercent": null,
  "followingDelta": null,
  "followingDeltaPercent": null,
  "state": "first_seen",
  "snapshotAt": "2026-08-01T09:03:07.708Z",
  "previousSnapshotAt": null,
  "monitorId": "competitor-growth-report",
  "error": null
}
```

Counts are a point-in-time example and naturally change.
On a later run, the delta fields contain numbers and `state` is `changed` or `unchanged`.

### Understanding snapshot states

#### `first_seen`

No previous successful snapshot exists in this monitor namespace.
Delta fields are `null`.

#### `changed`

At least one follower or following count differs from the previous successful snapshot.
Absolute and percentage changes are populated.

#### `unchanged`

The current and previous public totals are equal.
Delta values are zero.

#### `unavailable`

The public profile was not found or did not expose usable public profile data.
Current count fields are `null`, and the last successful snapshot remains available for a future comparison.

### How much does it cost to monitor X follower changes?

The Actor uses pay-per-event pricing:

- a **$0.005 start fee** once per run;
- one **item event** for each emitted account record;
- the current BRONZE item price is **$0.004 per account**;
- higher Apify plan tiers receive lower per-item prices.

The charge for a run is the active start price plus the active item price multiplied by the number of emitted account records.
For example, one account creates one start event and one item event; 10 accounts create one start event and 10 item events.
Check the pricing panel for your Apify plan tier before starting a larger run.

Actor charges exclude any separate Apify platform usage charged under your plan.
An unavailable account still produces a useful status record and is charged as one item.
Duplicate handles removed before processing do not create extra item events.

### Scheduling an audience-growth monitor

1. Save the Actor input as an Apify Task.
2. Keep one stable `monitorId` in that Task.
3. Run once with `resetBaseline: true`.
4. Change `resetBaseline` to `false`.
5. Add a daily, weekly, or monthly Apify Schedule.
6. Connect the dataset or run-finished webhook to your reporting destination.

Use different monitor IDs for unrelated reports.
For example, `weekly-influencers` and `monthly-competitors` can track overlapping handles without sharing baselines.

### Spreadsheet and data-pipeline workflows

Export the default dataset as JSON, CSV, Excel, XML, or RSS through Apify Dataset endpoints.
Useful patterns include:

- append each scheduled run to a warehouse table;
- send rows with `state: "changed"` to Slack or email;
- calculate campaign-period growth from weekly snapshots;
- join follower deltas with campaign spend or content metrics;
- flag `unavailable` accounts for manual list cleanup;
- build a dashboard grouped by `monitorId` and `snapshotAt`.

The Actor emits records only.
It does not send alerts itself, but Apify integrations can route results downstream.

### Run with the Apify API

Replace `YOUR_TOKEN` with an Apify API token.

#### cURL

```bash
curl -X POST \
  "https://api.apify.com/v2/acts/automation-lab~x-follower-change-monitor/runs?token=YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "accounts": ["apify", "github"],
    "monitorId": "weekly-brand-watch",
    "resetBaseline": false,
    "maxItems": 2
  }'
```

#### JavaScript

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

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('automation-lab/x-follower-change-monitor').call({
  accounts: ['apify', 'github'],
  monitorId: 'weekly-brand-watch',
  resetBaseline: false,
  maxItems: 2,
});

const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items);
```

#### Python

```python
import os
from apify_client import ApifyClient

client = ApifyClient(os.environ['APIFY_TOKEN'])
run = client.actor('automation-lab/x-follower-change-monitor').call(run_input={
    'accounts': ['apify', 'github'],
    'monitorId': 'weekly-brand-watch',
    'resetBaseline': False,
    'maxItems': 2,
})

items = client.dataset(run['defaultDatasetId']).list_items().items
print(items)
```

### Use with MCP and AI agents

#### Claude Code

Add the Actor to Claude Code:

```bash
claude mcp add --transport http apify \
  "https://mcp.apify.com?tools=automation-lab/x-follower-change-monitor"
```

#### Claude Desktop, Cursor, and VS Code

Desktop and editor clients can use this HTTP MCP configuration:

```json
{
  "mcpServers": {
    "apify": {
      "url": "https://mcp.apify.com?tools=automation-lab/x-follower-change-monitor"
    }
  }
}
```

Example prompts:

- “Create a fresh follower-count baseline for the Apify and GitHub X accounts.”
- “Run my weekly competitor monitor and summarize accounts with positive follower growth.”
- “Return unavailable X profiles separately from unchanged accounts.”
- “Export the latest follower deltas as a compact table.”

### Tips for reliable monitoring

- Keep the same `monitorId` for every run in one time series.
- Do not enable `resetBaseline` on recurring scheduled runs.
- Track stable public profile handles rather than search terms.
- Use smaller groups when you need each group to run on a different schedule.
- Treat public counts as point-in-time values that can change between page requests.
- Check the `state` and `error` fields instead of assuming every account is available.
- Keep historical dataset exports if you need more than the latest comparison.

### Limitations

- Public profiles only.
- Protected, suspended, withheld, deleted, or nonexistent accounts can return `unavailable`.
- The Actor tracks totals, not follower identities or individual follow/unfollow events.
- It does not traverse follower or following lists.
- It does not accept cookies or authenticated X sessions.
- X can change its public profile response, which may temporarily interrupt extraction.
- Percentage change is `null` when the previous count is zero.
- Snapshot storage keeps the last successful value, not a full historical time series.
- Simultaneous runs using the same `monitorId` and handle can race; avoid overlapping schedules for one monitor.
- Public display names, bios, avatars, and counts may change at any time.

### Responsible use and legality

This Actor accesses public profile metadata.
Use it only for lawful purposes and in accordance with applicable terms, privacy rules, and contractual obligations.
Do not use public audience data to harass, discriminate against, or make sensitive decisions about individuals.
Avoid collecting more data than your workflow needs.
Respect deletion, suspension, and availability changes.

The Actor is not affiliated with or endorsed by X Corp.
You are responsible for deciding whether your use case and retention policy are appropriate in your jurisdiction.

### Troubleshooting

#### Why are delta fields `null`?

The record is either `first_seen` or `unavailable`.
Run again with the same `monitorId` and `resetBaseline: false` to compare two successful snapshots.

#### Why does every run say `first_seen`?

Confirm that `monitorId` is identical and that `resetBaseline` is disabled.
Changing the monitor ID intentionally creates an independent baseline.

#### Why is an account unavailable?

Check that the handle points to a public profile and contains at most 15 valid X handle characters.
The account may also be protected, suspended, withheld, deleted, or temporarily unavailable on X.

#### Why did input validation fail?

Use a handle, `@handle`, `https://x.com/handle`, or `https://twitter.com/handle`.
Post URLs, search URLs, list URLs, and other domains are outside this Actor's scope.

#### Where is the full history?

The dataset from each run is the historical record you can export or retain.
The internal snapshot store keeps only the latest successful baseline needed for the next comparison.

### Related Automation Lab Actors

- [Twitter Scraper](https://apify.com/automation-lab/twitter-scraper) extracts broader X posts and public profile data when a count-only monitor is not enough.

Choose X Follower Tracker for small recurring audience snapshots and deltas.
Choose Twitter Scraper when the workflow needs posts or broader X records.

### FAQ

#### Does it need an X API key?

No.
The supported public-profile workflow does not require an X API key, cookie, or login.

#### Can it show exactly who followed or unfollowed?

No.
It compares public totals and does not export follower lists or identities.

#### Can I monitor many accounts?

Yes, up to 500 unique accounts per run.
Start with a representative list and use schedules that do not overlap for the same monitor.

#### Can two reports track the same account independently?

Yes.
Give each report a different `monitorId`.

#### Does an unavailable run erase my baseline?

No.
Only a successful public profile snapshot replaces the saved baseline.

#### Can I reset one report?

Yes.
Run its account list once with `resetBaseline: true`, then disable the option for later runs.

# Actor input Schema

## `accounts` (type: `array`):

Public X handles or profile URLs. Examples: apify, @crawlee\_dev, https://x.com/elonmusk.

## `monitorId` (type: `string`):

Stable namespace for snapshot history. Reuse the same ID on scheduled runs; use a different ID for an independent baseline.

## `resetBaseline` (type: `boolean`):

Treat this run as the first snapshot and replace saved counts for the selected monitor.

## `maxItems` (type: `integer`):

Maximum number of unique accounts processed in this run.

## Actor input object example

```json
{
  "accounts": [
    "apify",
    "github"
  ],
  "monitorId": "brand-watch",
  "resetBaseline": false,
  "maxItems": 2
}
```

# Actor output Schema

## `dataset` (type: `string`):

Dataset containing one typed snapshot record per processed account.

# 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 = {
    "accounts": [
        "apify",
        "github"
    ],
    "monitorId": "brand-watch",
    "maxItems": 2
};

// Run the Actor and wait for it to finish
const run = await client.actor("automation-lab/x-follower-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 = {
    "accounts": [
        "apify",
        "github",
    ],
    "monitorId": "brand-watch",
    "maxItems": 2,
}

# Run the Actor and wait for it to finish
run = client.actor("automation-lab/x-follower-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 '{
  "accounts": [
    "apify",
    "github"
  ],
  "monitorId": "brand-watch",
  "maxItems": 2
}' |
apify call automation-lab/x-follower-change-monitor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,automation-lab/x-follower-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/dm7yBfcjg7fxWAzjc/builds/K13A2POnluTF8QLbH/openapi.json
