# X / Twitter Account Monitor - Track Accounts (`datalayer/twitter-account-monitor`) Actor

Latest posts with full engagement counts from a list of X accounts, plus the part nobody else sells: what is new since your last run and which older posts are still gaining. Schedule it for a feed instead of a snapshot. The spend cap stops the run, it does not trim after.

- **URL**: https://apify.com/datalayer/twitter-account-monitor.md
- **Developed by:** [Datalayer](https://apify.com/datalayer) (community)
- **Categories:** Social media, Lead generation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.35 / 1,000 posts

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?

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 / Twitter Account Monitor — watch accounts, see what changed

Point it at a list of X accounts and get their latest posts with full engagement counts. Run it on a schedule and it also tells you **what is new since last time, and which older posts are still gaining** — the difference between a snapshot and a feed.

### What this is, and what it is not

**It monitors accounts. It does not search X.**

X's public timeline endpoint returns the **20 most recent posts per account**, and its public search endpoint no longer exists. So if you need "every post mentioning a keyword across all of X", this is the wrong tool and you should know that now rather than after paying — there are search scrapers on this store that do that job.

What this does instead, and does properly: watch a defined list of accounts — competitors, clients, journalists, a portfolio — closely and cheaply.

### The limit you set is the limit you get

The most-used scrapers on this store are rated in the 3s, and their reviews all say the same thing:

> *"I set the limit but this actor fetched a lot of records and I spent hundreds of USD in vain"*

> *"The Actor ignores onlyTotal, resultsLimit, onlyAdsNewerThan, and onlyAdsOlderThan"*

> *"filtering tweets based on time is not working... both giving results outside the executed time range"*

So here:

- **`maxTweets` and `maxCostUsd` stop the run**, they do not trim the results after your money is spent. The cap counts every row, including change rows, so your bill cannot be doubled by a feature you turned on.
- **Date ranges are applied, and an unreadable date stops the run** rather than being silently ignored.
- **Filtered-out posts are never charged for** — replies you excluded and posts below your engagement floor cost nothing.
- **The first run never bills you twice.** With change tracking on, every post would technically be "new" on run one. Rather than charge for the same post as both a post and a change, run one quietly stores the baseline and run two starts reporting changes.

### What you get

Per post: `text`, `createdAt`, `likes`, `retweets`, `replies`, `quotes`, a combined `engagement` total, `hashtags`, `mentions`, `links`, `mediaCount`, `mediaType`, `isReply`, `tweetUrl`, plus `authorFollowers` and `authorVerified`.

With `trackChanges` on, extra rows carry `changeType`:

- **`new`** — posted since your last run
- **`gained`** — an older post still climbing, with `engagementGained`, `likesGained` and `retweetsGained` since you last looked

### What it is for

- **Competitor monitoring** — what a rival posted this week and what actually landed
- **Client reporting** — engagement per post, pulled the same way every week
- **Journalist and analyst tracking** — a watchlist of accounts in one table
- **Spotting sleepers** — the `gained` rows show posts still growing hours after publishing

### Input

```json
{
  "accounts": ["nasa", "@spacex", "https://x.com/bbcbreaking"],
  "maxTweets": 200,
  "maxCostUsd": 5,
  "trackChanges": true,
  "excludeReplies": true,
  "minEngagement": 100
}
```

Handles, `@handles` and full URLs all work, so a column pasted from a spreadsheet is fine.

### Reliability

**One bad handle never fails the run.** An account that is suspended, protected or renamed is recorded in the run summary with the reason while the rest continue.

Requests go through Apify Proxy residential, which is what X answers reliably. Every run writes a summary of what was delivered, what your filters removed, what failed, and what it cost against your cap.

### Notes

Reads only public posts, logged out — the same content any visitor sees without an account. No login, no cookies, none of your accounts involved. Protected accounts return nothing by design. Unofficial and not affiliated with X Corp. Posts belong to the people who wrote them; use them in line with applicable laws and terms.

# Actor input Schema

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

Handles, @handles or profile URLs. X publishes the 20 most recent posts per account, which is what this returns.

## `trackChanges` (type: `boolean`):

Compares against the previous run and flags posts that are new, or older ones still gaining engagement. Run it on a schedule to get a feed instead of a snapshot.

## `maxTweets` (type: `integer`):

Hard stop on TOTAL rows, counting both posts and change rows. The run stops collecting at this number rather than gathering everything and trimming afterwards. If you want the change feed as well, set this comfortably above the number of posts you expect (about 20 per account).

## `maxCostUsd` (type: `integer`):

Hard ceiling on what this run may cost. Leave empty for no cost ceiling.

## `postedFrom` (type: `string`):

Only keep posts on or after this date. Posts outside the range are never charged for. An unreadable date stops the run instead of being ignored.

## `postedTo` (type: `string`):

Only keep posts on or before this date.

## `minEngagement` (type: `integer`):

Skip posts below this combined total of likes, retweets, replies and quotes. Skipped posts are not charged for.

## `excludeReplies` (type: `boolean`):

Keep only the account's own posts, not its replies to other people.

## `proxyConfiguration` (type: `object`):

X only answers residential addresses reliably, so this defaults to Apify Proxy residential.

## Actor input object example

```json
{
  "accounts": [
    "nasa",
    "@bbcbreaking",
    "https://x.com/spacex"
  ],
  "trackChanges": true,
  "maxTweets": 200,
  "maxCostUsd": 5,
  "postedFrom": "",
  "postedTo": "",
  "minEngagement": 0,
  "excludeReplies": false,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}
```

# Actor output Schema

## `posts` (type: `string`):

Every post returned by this run as clean JSON.

## `postsCsv` (type: `string`):

The same rows as a CSV download.

## `runSummary` (type: `string`):

What was delivered, filtered, failed, and what it cost against your cap.

# 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": [
        "nasa",
        "@bbcbreaking",
        "https://x.com/spacex"
    ],
    "maxTweets": 200,
    "maxCostUsd": 5
};

// Run the Actor and wait for it to finish
const run = await client.actor("datalayer/twitter-account-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": [
        "nasa",
        "@bbcbreaking",
        "https://x.com/spacex",
    ],
    "maxTweets": 200,
    "maxCostUsd": 5,
}

# Run the Actor and wait for it to finish
run = client.actor("datalayer/twitter-account-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": [
    "nasa",
    "@bbcbreaking",
    "https://x.com/spacex"
  ],
  "maxTweets": 200,
  "maxCostUsd": 5
}' |
apify call datalayer/twitter-account-monitor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,datalayer/twitter-account-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/YQrca37T2qvcStYlj/builds/qc04VSaxVTOWEFPwL/openapi.json
