# X (Twitter) Trends Scraper & Monitor - Countries & Cities (`neverempty/x-twitter-trends-monitor`) Actor

X (Twitter) trending topics for 400+ countries and cities, with the snapshot time, rank, previous rank and how long each trend has been on the list. Watch mode returns only trends that entered the list since the last run. No login, no API key.

- **URL**: https://apify.com/neverempty/x-twitter-trends-monitor.md
- **Developed by:** [NeverEmpty](https://apify.com/neverempty) (community)
- **Categories:** Social media, Marketing, News
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.15 / 1,000 trend returneds

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

## X (Twitter) Trends Scraper & Monitor - Countries & Cities

Get the **X (Twitter) trending topics** for any of 400+ countries and cities (plus Worldwide): the rank, the exact time of each hourly snapshot, the rank in the snapshot before, and how long each trend has been on the list. **Watch mode** returns only the trends that entered the list since your last run, so a schedule can send alerts without duplicates. Built for social media managers, newsrooms, marketers, traders and AI agents that need to know what is trending on X right now.

- **Countries and cities by name.** Type `Japan`, `Tokyo`, `London, United Kingdom`, `US` or `japan/tokyo`. No WOEID numbers to look up. A place that is not available comes back as a free row with suggestions.
- **Every row has its snapshot time** (`snapshotAt`, UTC), not just the time the run happened.
- **Only new trends, on a schedule.** With `onlyNew`, later runs read every snapshot published since the last run and return only trends that were not in the snapshot just before (`changeType: "new"`).
- **How long it has been trending.** `consecutiveSnapshots`, `trendingSince` and `trendingForHours`, plus `previousRank` to see what is climbing.
- **History.** `hoursBack` returns the hourly snapshots of up to the last ~20 hours.
- **Nothing is guessed.** Tweet counts are `null` when the source does not show them (it showed none for 6,000 trends checked on 2026-10-09), never `0`. A blocked or unreadable page is a free row that says why.
- **No login, no API key, no browser.**

Data comes from the public pages of trends24.in, which records X's trending list for each place about once an hour. Unofficial: not affiliated with X Corp. or trends24.in.

### What you get

One row per trend per snapshot:

| Field | Example | Meaning |
|---|---|---|
| `location` | `Tokyo, Japan` | The place |
| `locationSlug` | `japan/tokyo` | The same as a slug (`worldwide` for Worldwide). You can paste it back into `locations` |
| `country`, `city` | `Japan`, `Tokyo` | `city` is `null` for a country; both are `null` for Worldwide |
| `snapshotAt` | `2026-10-08T19:08:06.092Z` | When this snapshot of the list was taken (UTC) |
| `rank` | `1` | Position in that snapshot (1-50) |
| `trend` | `#DevDayCommunity` | The trending topic or hashtag |
| `isHashtag` | `true` | The trend starts with `#` |
| `previousRank` | `26` | Rank in the snapshot before; `null` if it was not in it (or this is the oldest snapshot) |
| `consecutiveSnapshots` | `8` | Snapshots in a row, ending with this one, that have this trend |
| `trendingSince`, `trendingForHours` | `2026-10-08T12:58:00.321Z`, `6.2` | When that run of snapshots started. `null` when it started before the oldest snapshot on the page (`streakStartsBeforePage: true`) |
| `tweetCount`, `tweetCountText` | `null` | Tweet count as a number and as shown, when the source shows one |
| `xSearchUrl` | `https://x.com/search?q=...` | Opens the trend on X |
| `sourceUrl` | `https://trends24.in/japan/tokyo/` | The page that was read |
| `changeType` | `first-check` / `new` | Watch mode only; `null` otherwise |
| `checkedAt` | ISO time | When this run read the page |

A snapshot has 50 trends. Snapshots are about 52 minutes apart. When the site stores two snapshots a few seconds apart, only the newer one is used, so the same trend is never returned (or charged) twice for one hour.

#### Free rows (not charged)

| `status` | When |
|---|---|
| `bad-input` | The place is not on the list (with suggestions), matches two places (`Birmingham`: use `united-kingdom/birmingham`), or watch mode was started without a location |
| `unknown-location` | The site has no page for that place (HTTP 404) |
| `no-new-snapshot` | Watch mode: the site has not published a new snapshot since the last run |
| `no-new-trends` | Watch mode: new snapshots, but no trend entered the list |
| `no-trends` | The latest snapshot is empty |
| `blocked`, `unreadable` | The page was refused, showed a check page (never solved), or was not a trends page for that place |
| `robots-disallowed` | The site's robots.txt does not allow the page (it is read on every run) |
| `timed-out` | The run was about to reach its timeout |
| `budget-reached` | The run reached its maximum total charge; the row lists what was not returned |

If no location could be read, the run is not charged and ends with an error so your schedule notices.

### Input

| Field | Default | Notes |
|---|---|---|
| `locations` | empty = Worldwide (watch mode needs at least one) | Names, short codes (`US`, `UK`, `JP`), slugs or trends24.in addresses. Up to 50 per run. Duplicates are read once |
| `hoursBack` | 0 = latest snapshot only | Also the snapshots taken up to N hours before the latest (max 24). Ignored in watch mode |
| `maxRank` | 50 | Only the top N of each snapshot. In watch mode, "new" means new in this top N |
| `onlyNew` | off | Watch mode (below) |
| `watchName` | empty | Separate memory for separate schedules |
| `resetMonitoringState` | off | Forget the watch memory at the start of this run |

Example: `{ "locations": ["united-states", "japan"] }` returns 100 rows (the latest 50 trends of each).

### Watch mode

1. Run once with `onlyNew: true` and your locations: the latest snapshot of each comes back with `changeType: "first-check"`.
2. Create a **Schedule** with the same input (every hour fits how often the site updates).
3. Later runs return only trends that entered the list since the last run (`changeType: "new"`), each with the snapshot it entered in. Send them to Slack, email or a webhook with an Apify integration.

Trends not returned because the run hit its maximum total charge are not remembered, so the next run returns them. Do not run two schedules with the same `watchName` at the same time.

### Pricing

Pay per event:

- **Run start** - once per run, only when at least one location's trends were read. This includes watch-mode runs that find nothing new. Not charged when every location is a free row, or when the run's maximum total charge has no room for the start fee plus one row (then nothing is requested at all).
- **Trend** - one per `ok` row. Free rows are never charged.

The exact prices are shown on the Pricing tab.

### How it reads the site

One page per location, at most 50 pages per run, with a pause between pages. robots.txt is read on every run and checked before each page. Check pages are never solved or bypassed.

### Thanks for using this Actor

We build these tools for people who run them every day, and we improve them from what users tell us.

- **Missing a field, or need another filter?** Tell us in the **Issues** tab. If the data is there, we add it.
- **Found a bug or a wrong value?** Post the run ID in the **Issues** tab. Wrong data is the thing we fix first.

If this Actor saved you time, a short review helps other people find it.

# Actor input Schema

## `locations` (type: `array`):

Countries or cities, one per line: a name (Japan, Tokyo, "London, United Kingdom"), a short code (US, UK, JP), a slug (japan/tokyo) or a trends24.in address. Worldwide is also accepted. A place the site does not list comes back as a free row with suggestions. Up to 50 per run. Empty = Worldwide (not allowed in watch mode).

## `hoursBack` (type: `integer`):

Optional. 0 or empty = only the latest snapshot of each location. A number = also the earlier hourly snapshots taken up to this many hours before the latest one (the site keeps about 20 hours). Ignored in watch mode.

## `maxRank` (type: `integer`):

Optional. Only trends ranked 1 to N in each snapshot (each snapshot has 50). In watch mode, a trend counts as new when it enters this top N. Empty = all 50.

## `onlyNew` (type: `boolean`):

On = for scheduled runs and alerts. The first run returns the latest snapshot of each location (changeType first-check). Later runs read every snapshot published since the last run and return only trends that were not in the snapshot just before (changeType new). Off (or empty) = always return the snapshots.

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

Optional, used with watch mode. Runs with the same watch name share what has already been returned. Give a different name to each schedule. Letters, digits, dot, dash and underscore.

## `resetMonitoringState` (type: `boolean`):

Forget what this watch remembered at the start of this run, so every location is a first check again. Turn it off again for scheduled runs.

## Actor input object example

```json
{
  "locations": [
    "united-states",
    "japan"
  ]
}
```

# Actor output Schema

## `results` (type: `string`):

One row per trend: location, snapshot time (UTC), rank, previous rank, trend name, X search link, tweet count (null when the source does not show it) and how many consecutive snapshots it has been on the list. In watch mode only trends that entered the list since the last run. A place the site does not list, a blocked page or a run that hit its maximum charge comes back as a free row that says why.

# 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 = {
    "locations": [
        "united-states",
        "japan"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("neverempty/x-twitter-trends-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 = { "locations": [
        "united-states",
        "japan",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("neverempty/x-twitter-trends-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 '{
  "locations": [
    "united-states",
    "japan"
  ]
}' |
apify call neverempty/x-twitter-trends-monitor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,neverempty/x-twitter-trends-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/y4DzCM0Hbx69AA2Ok/builds/bpDAXFLZkAPpsygM4/openapi.json
