How to Monitor Twitter Keywords in Real Time (Without Refreshing Search All Day)

11 min readSocialAPI Engineering

How to Monitor Twitter Keywords in Real Time (Without Refreshing Search All Day)

Someone just posted about your company. Or your competitor announced something. Or a token you're watching started trending.

You'd like to know now — not tomorrow morning when you happen to check.

X gives you a search box. It doesn't give you alerts. So most people end up with a browser tab they refresh out of habit, and they still miss the thing that mattered because it happened at 3am.

This is how to set up monitoring that tells you instead.


Two ways to do it, and they're not equivalent

Everything in keyword monitoring comes down to one architectural choice:

Polling — you ask "anything new?" on a timer. Simple, works everywhere, and your latency is however long your interval is. Check every five minutes and you find out, on average, two and a half minutes late.

Streaming — you hold a connection open and get pushed the moment something matches. More setup, but you find out in seconds.

Which one you need depends entirely on what you do with the alert:

Your use case What's good enough
Weekly report on brand mentions Polling, hourly
Responding to customer complaints Polling, every few minutes
Reacting to breaking news Streaming
Anything where being second is worthless Streaming

⚠️ The mistake to avoid: building a poller with a 30-second interval because you want it "fast". That's the worst of both — you're making 2,880 requests a day, and you're still up to 30 seconds behind. If you need seconds, stream. If minutes are fine, poll every few minutes and save the requests.

We provide both paths — search for polling, WebSocket for streaming — so this choice stays a design decision rather than a constraint.


Start here: get the query right

Before any code, spend ten minutes on the query. A bad query is the reason most monitoring gets abandoned — it either floods you until you mute it, or it's so narrow it never fires.

X's search operators work through the API, and they're the difference between signal and noise:

Operator Effect When you want it
"exact phrase" Match the phrase, not the words Multi-word brand names
from:username Only that account Watching a specific person
to:username Only replies to them Complaint monitoring
-word Exclude Killing a known false positive
-filter:replies Original posts only Cutting reply chains
min_faves:100 Only posts above a like count Catching things once they've spread
lang:en One language Ambiguous brand names
#hashtag Tag, not plain text Campaign tracking

We tested each of these against the live API while writing this — they all work as documented.

A worked example. Say you're monitoring a company called Nova. Searching nova gives you cars, Latin homework, and a PBS series.

"nova" -car -chevy -pbs lang:en -filter:replies

That one line removes most of the noise. Add min_faves:5 and you drop the posts nobody saw at all.

Build your query incrementally. Run it as a plain search first, look at what comes back, add exclusions for whatever's wrong, and repeat. Ten minutes here saves you from an alert channel you learn to ignore.


Polling: the version most people need

Here's a complete monitor. It tracks what it's already seen so you're alerted once per post, not once per poll.

import time, requests

BASE  = "https://api.socialapi.tech"
KEY   = "your_api_key"
QUERY = '"nova" -car -chevy lang:en -filter:replies'

seen = set()

def check():
    r = requests.get(
        f"{BASE}/v1/search/advanced",
        params={"query": QUERY, "limit": 50},
        headers={"X-API-Key": KEY},
        timeout=60,
    )
    r.raise_for_status()

    fresh = []
    for tweet in r.json()["data"]:
        if tweet["id"] not in seen:
            seen.add(tweet["id"])
            fresh.append(tweet)

    return fresh

# First run: prime the cache without alerting on history
check()
print("Baseline set. Watching...")

while True:
    for tweet in check():
        author = tweet["author"]["username"]
        print(f"@{author}: {tweet['text'][:120]}")
        # send_to_slack(tweet)
    time.sleep(300)   # five minutes

Three details that matter more than they look:

Prime the cache first. That initial check() before the loop stops you firing 50 alerts about posts from last week the first time you run it.

Deduplicate on ID, not on text. People post near-identical things. IDs are unique; text isn't.

Bound the seen set. Left alone it grows forever. In production, cap it — keep the last few thousand IDs and drop the rest, or use a TTL cache.

That's the whole poller. What's left is the reliability underneath it, which is the part we run.


Streaming: when seconds matter

Polling has a floor: your interval. If you need to know within seconds, you need something pushing to you.

import json, websocket

WS = "wss://api.socialapi.tech/v1/stream/ws?api_key=your_api_key"

def on_message(ws, raw):
    msg = json.loads(raw)

    if msg.get("type") == "connected":
        print("Watching:", msg.get("subscribed"))
        return
    # Any other control frame — e.g. "lagged", sent when the server drops
    # messages under backpressure — has no user/content fields. Bail out
    # before touching them, or a busy stream will throw KeyError at 3am.
    if msg.get("type"):
        return

    text = msg.get("content", "")
    if "nova" in text.lower():
        print(f"@{msg['user']}: {text[:120]}")

websocket.WebSocketApp(WS, on_message=on_message).run_forever()

The trade-off is where the filtering happens. A stream delivers posts from accounts you've subscribed to, and you filter for keywords on your side — good for watching a defined set of accounts closely. Search polling filters server-side across all of X — good for catching mentions from anyone.

Most real setups use both: stream the handful of accounts you care about most, poll search for everything else.


What to do with an alert

The monitoring is the easy half. The half that decides whether anyone keeps using it:

Route by importance, not by volume. A mention from a 200,000-follower account and one from a fresh account with three followers are not the same event. Check author.followers_count and send them to different places.

Batch the low-priority ones. Twenty Slack pings an hour trains everyone to mute the channel. One digest every few hours keeps it readable.

Include enough context to act. The text, the author, their follower count, and a link. Anything less and you'll open X anyway, which defeats the point.

Log everything, alert on some of it. Store all matches; only notify on the ones that clear your bar. You'll want the full history when someone asks "when did this start?"


Common monitoring setups

Brand mentions — your name plus common misspellings, minus known collisions. Most valuable when it catches complaints early.

Competitor watchingfrom:competitor for their announcements, plus their brand name to see what people say back.

Crypto and finance — cashtags like $SOL work as search terms. Volume is high, so min_faves: is nearly mandatory unless you want everything.

Hiring and lead gen — phrases like "looking for a" plus your category. Narrow, but high intent when it fires.

Reputation on a launch day — set it up beforehand, not during. You want the baseline from before, or you can't tell what changed.


Questions people ask

How do I monitor keywords on Twitter? Run a search query on a schedule and alert on results you haven't seen before, or hold a stream open for pushed posts. The code above does both.

Can I get notified when someone tweets a keyword? Not from X directly — it has no keyword alerts. You build it, or use a service that has.

How do I track mentions of my brand on X? Search your brand name with exclusions for unrelated meanings. Add to:yourhandle separately to catch direct replies.

What's the fastest way to find out about a new tweet? Streaming. Polling can't beat its own interval; a stream delivers as posts arrive.

How often should I poll? As slowly as your use case tolerates. Every few minutes covers most needs. Sub-minute polling costs a lot of requests for little gain — if you need that, stream instead.

Can I monitor multiple keywords at once? Yes. Either combine them with OR in one query, or run separate queries per keyword if you want separate alert routing.

Does X notify people when I monitor their keywords? No. Searching public posts is not visible to anyone.

Can I monitor a specific account's tweets? Yes — from:username in search, or subscribe to that account on a stream for lower latency.

How do I avoid duplicate alerts? Track tweet IDs you've already handled. Deduplicate on ID rather than text, since near-identical posts are common.

Why does my monitor miss tweets? Usually the query is too narrow, or your poll interval is longer than the window in which the post was findable. Test the query manually before trusting it.

Can I monitor hashtags? Yes, #hashtag works as a search term. Worth pairing with a minimum engagement filter — hashtags attract a lot of low-value posts.

How do I filter out spam and bots? Combine min_faves: with a check on author.followers_count. Neither is perfect alone; together they remove most of it.

Can I search tweets from a specific date range? Yes, with since: and until: in the query. Useful for backfilling before you start live monitoring.

What's the difference between monitoring and social listening? Scale and framing. Monitoring is "tell me when this phrase appears". Listening usually means aggregate analysis across a lot of mentions. Same data underneath.

Do I need my own X developer account? Not if you use an API that provides the data. X's own API requires its own account and pricing tier.

Can I monitor tweets in other languages? Yes. lang: restricts to one; omit it to catch everything.

How do I monitor without writing code? Some hosted tools do this with a UI. The trade-off is usually flexibility on the query and where alerts can go.

Can I get alerts in Slack or Discord? Yes — replace the print in the loop with a webhook call. That's the only change needed.

How much history can I search? Search skews recent rather than reaching far back. If you need long history, capture continuously from now on rather than trying to reconstruct it later.

What is social listening? Watching what people say about a subject over time. ★The mechanism is a saved query polled on a schedule★ — the sophistication is in what you do with the results.

How do I monitor a Twitter account? Poll their timeline on an interval and diff against what you already have. ★New posts are the difference between polls.★

What is the best free monitoring tool? A scheduled query plus storage. ★Most paid tools are that, with a dashboard on top★ — the value is the history you accumulate.

How do I count mentions of my brand? Search the brand terms and count what returns. ⚠️ ★Report it as "mentions found", not "mentions existing"★ — search returns a window, not a complete set.

Can I monitor in real time? Near it. ★"Real time" is your polling interval or a stream★ — what a live feed involves.

How often should I poll? Match the interval to how fast the subject moves. ★A constant interval matters more than a short one★, because changing it corrupts your own trend line.

Do I need alerts or monitoring? Alerts tell you something happened; monitoring builds the record. ★Most people want both, and they are the same pipeline★ — alerting specifics.


If you'd rather not run the plumbing

The monitor above is thirty lines. What takes the time is everything around it: retries that distinguish a rate limit from a transient failure, dedup that survives a restart, and pacing that doesn't burn your quota in the first minute of every window.

That's what our API handles — search with the full operator set, plus a WebSocket stream for the accounts you want at low latency. Flat price per call, no rate limit of your own to manage.

Two things we don't bill for: requests we reject before they leave us — a malformed query, say — and errors on our side.

Related reading: what to do when X returns a rate limit error · tracking followers and unfollows · removing followers you don't want.