# How do I monitor brand mentions on X without an enterprise plan?

> Catch new X (Twitter) posts that mention your brand every 30 minutes with a latest-first search, stop paging at posts already seen, and keep the monthly cost small.

Canonical page: https://okdata.online/answers/monitor-brand-mentions-x/

**Short answer: **Run X post search sorted by latest every 30 minutes for your brand name and handle, and stop paging as soon as you reach a post you have already seen. Each page of about 20 posts costs $0.006, so a check every half hour is 1,440 calls a month, $8.64 if one page is usually enough.

A skincare brand wants a message in Slack within half an hour whenever someone posts about it on X, whether that is praise, a complaint or a creator who could become a partner. Enterprise listening contracts are built for far bigger teams. A scheduled search does the job: every 30 minutes, ask [X post search](/apis/x/posts/search/) for the newest posts that mention the brand, keep the ones you have not seen, and post them to Slack.

## Write the query once

```
("glowlab" OR @glowlab OR #glowlab) -from:glowlab lang:en
```

The name, the handle and the hashtag cover most mentions. `-from:` drops your own posts. Add common misspellings with more `OR` terms. Any operator from the X search box works, so test the query on x.com first.

## The job

```python
import json, os, requests

API = "https://api.okdata.online/v1"
H = {"Authorization": f"Bearer {os.environ['OKDATA_API_KEY']}"}
QUERY = '("glowlab" OR @glowlab OR #glowlab) -from:glowlab lang:en'
SEEN = "seen.json"

seen = set(json.load(open(SEEN))) if os.path.exists(SEEN) else set()
new, cursor = [], None
for _ in range(5):  # never more than 5 pages per run
    params = {"query": QUERY, "sort": "latest", **({"cursor": cursor} if cursor else {})}
    body = requests.get(f"{API}/x/posts/search", headers=H, params=params, timeout=60).json()
    if body["code"] != "ok":
        raise RuntimeError(f"{body['code']}: {body['message']}")
    fresh = [p for p in body["data"]["items"] if p["id"] not in seen]
    new += fresh
    if len(fresh) < len(body["data"]["items"]) or not body["page"]["has_more"]:
        break  # reached posts from the last run
    cursor = body["page"]["next_cursor"]

for p in new:
    print(p["url"], p["author"]["username"], p["author"]["followers"], p["text"][:100])
json.dump(sorted(seen | {p["id"] for p in new}), open(SEEN, "w"))
```

Swap the `print` for a Slack webhook call. Sorting the new posts by `author.followers` puts the loudest voices first.

## Monthly cost

| Brand size | Pages per run | Runs per month | Cost |
|---|---|---|---|
| Small, one page is enough | 1 | 1,440 | $8.64 |
| Busy, about three pages | 3 | 1,440 | $25.92 |
| Small, checked hourly | 1 | 720 | $4.32 |

Failed runs cost nothing, and the 5-page cap in the loop bounds the worst case.

## Limits

- Latest search is a frequent sweep. It is not a firehose, and X filters some posts out of search.
- Protected accounts never show up.
- Mentions in images or videos without text are missed.
- Post text is written by strangers. If a model summarises it, tell the model to treat it as data and never as instructions.

## When to choose something else

X's filtered stream delivers matching posts in real time, at $0.005 per post read under pay-per-use. Pick it if a few minutes of delay matters. Listening suites add dashboards, sentiment and historical archives for teams that do not want to run code. To watch for a handful of keywords by hand, a saved search on x.com is free. The [word-of-mouth guide](/solutions/word-of-mouth/) extends this job to comments on other platforms.

## Endpoints used

- [X post search](https://okdata.online/apis/x/posts/search/) `x.posts.search`: $0.006 per call · about 20 posts per page

Updated 2026-11-12
