twitterapi.io is an independent third-party service. Not affiliated with X Corp.

Blogmonitoring twitter via api

Monitoring Twitter (X) Tweets via API — A Developer's Guide

By Sarah Wong10 min read

Monitoring a Twitter (X) account, a brand mention, or a keyword in close-to-real-time is one of the most common production uses of the X API. Marketing teams set up brand-mention alerts; trading desks watch for market-moving tweets; brand-safety platforms scan for crisis signals; analytics teams capture timeline data for downstream analysis. Each use case has a different latency requirement and a different cost profile, and the architectural choice you make at the start — polling versus streaming versus webhook — locks in those properties for the life of the system.

This guide walks through the three monitoring architectures with their trade-offs, gives a runnable Python example for the most common pattern (timeline polling with engagement re-fetch), and covers the cost economics that determine whether the official X API or a third-party API like TwitterAPI.io is the right fit for your scale. It assumes you know what an HTTP API is; everything else is in-context.

By the end, you'll have: a clear answer to which monitoring pattern fits your use case, a ~70-line Python reference implementation you can copy and adapt, and a concrete monthly-cost estimate for 1 / 10 / 100 / 1,000 accounts at the recommended cadence.

01 — Section

Three architectural patterns — pick the right one before you write code

There are three architecturally distinct ways to monitor Twitter (X) in production. Picking one is the single highest-leverage decision in a monitoring system; switching between them after you've shipped is significantly more work than picking right the first time.

PatternLatencyOperational costBest for
1. Timeline polling (pull)30 s - 5 minStateless, runs on cron / serverlessSingle-account watch, analytics, low-medium urgency
2. Filtered stream (push, WebSocket)sub-secondPersistent worker requiredReal-time alerting, high-stakes use cases
3. Webhook callbacks (push)1-10 sStateless HTTP endpoint, serverless-friendlyBrand mention alerts, customer support detection

1. Timeline polling. Periodically fetch a user's recent tweets or a search result, diff against your last-known state, write new items to storage. Simplest to operate; freshness limited by your poll interval. Most third-party APIs make this the cheapest path. Right answer for ~80% of monitoring use cases.

2. Filtered stream. Subscribe to a filter rule (e.g. from:elonmusk or "product launch") and receive matching tweets via a long-lived WebSocket. Sub-second freshness; requires you to operate a persistent worker (not serverless-friendly). On TwitterAPI.io: oapi/tweet_filter/add_rule + a wss:// connection. On official X API: the Filtered Stream endpoint, Pro tier and up.

3. Webhook callbacks. Same push pattern but stateless on your side — the API service hits your HTTPS endpoint with each matching tweet. Operationally easiest for serverless deploys (Vercel/Cloudflare Workers/Lambda); slightly higher per-event cost than the WebSocket stream. Pattern of choice when you don't want to run anything 24/7.

A simple decision rule: if you can tolerate 60-second latency, polling. If you need sub-5-second and don't want to run a persistent worker, webhooks. If you need sub-second for high-stakes alerting, filtered stream.

02 — Section

The Twitter (X) API surface you'll use — endpoints, auth, and the official-vs-third-party choice

For each monitoring pattern, there's a specific subset of the X API surface that gets used. Knowing the names up front saves time when you're debugging.

Timeline polling endpoints:

- GET /twitter/user/info — resolve a handle to a user ID (TwitterAPI.io). Equivalent: GET /2/users/by/username/:username on official X API.

- GET /twitter/user/last_tweets — most recent ~20 tweets for a user (TwitterAPI.io). Equivalent: GET /2/users/:id/tweets.

- GET /twitter/tweet/advanced_search — keyword/operator search (TwitterAPI.io). Equivalent: GET /2/tweets/search/recent.

Filtered stream endpoints:

- POST /oapi/tweet_filter/add_rule + wss://ws.twitterapi.io/twitter/tweet/stream (TwitterAPI.io).

- POST /2/tweets/search/stream/rules + GET /2/tweets/search/stream (official X API; Pro tier).

Authentication. TwitterAPI.io uses a single X-API-Key HTTP header — no OAuth flow, no project approval. Official X API uses OAuth (4 keys + signed requests for User context, or a Bearer Token for App context). The 4-key OAuth signing is a real source of bugs when you're prototyping; the third-party single-header path is what most teams use to move fast and migrate later if needed.

Cost comparison at the per-call level (2026 docs.x.com):

PathPer-call read costApprox setup timeProject approval
Official X API (pay-per-use, post read)$0.0051-2 weeksRequired
TwitterAPI.io$0.000155 minNot required

The per-call gap is roughly 33× — TwitterAPI.io reads cost about 1/33 of the official X API rate. For high-volume monitoring (the use case this whole guide is about), that cost gap usually determines which path is economically viable at scale.

03 — Section

Runnable Python — a timeline-polling monitor with engagement re-fetch

Below is a working Python implementation of the recommended pattern (timeline polling with engagement re-fetch) targeting a single account. It polls every 60 seconds, dedupes against local state, appends new tweets to JSONL, and schedules engagement-velocity re-fetches at T+15m, T+1h, T+6h, T+24h. Total cost at this cadence: roughly $1/month per account on TwitterAPI.io.

Key implementation notes embedded in the script:

- We resolve the handle once via user/info and cache the user_id locally — saves one call per poll across restarts.

- We dedupe on tweet.id against a local file so restarts don't replay tweets.

- Engagement velocity (likes/min in the first 15 minutes) is widely cited as a leading indicator of viral potential — often more diagnostic than the final engagement count alone, since the final count is reached well after the decision-relevant window. Capturing it at multiple time points lets you measure the velocity curve rather than relying on a single point estimate.

- The script writes events with a kind field (new_tweet vs velocity_checkpoint) so downstream consumers can join them with a single GROUP BY.

- Replace HANDLE = "elonmusk" with your target. For multi-account watch, run one process per account (cheap) or refactor into a single loop iterating a handle list (slightly more code, same behavior).

Drop-in alerting hook. The print("SPIKE: ...") line at the bottom of the engagement check is where you'd integrate Slack/PagerDuty/SES/whatever. The condition engagement > median * SPIKE_MULTIPLIER is the simplest spike detector that doesn't fire on baseline noise; tune SPIKE_MULTIPLIER per account.

04 — Section

Filtered stream — when polling isn't fast enough

Switch from polling to filtered stream when one of these conditions holds:

- Latency requirement < 5 seconds (alerting products, trading bots)

- You're watching keywords/operators rather than specific accounts, and the keyword volume is high enough that polling search every minute would miss tweets that get deleted in seconds

- You need to capture tweets before deletions land (e.g. high-profile accounts that delete frequently)

The trade-off. Filtered stream requires you to run a persistent process that keeps the WebSocket open. That excludes serverless (Vercel/Lambda) and adds operational complexity (process supervisor, connection retry, monitoring the monitor). For real-time alerting it's worth it; for analytics archiving it usually isn't.

Rule design. On both TwitterAPI.io and the official X API, you POST a filter rule with operators like from:userid or "product launch" OR "new release" -is:retweet. The rule language is shared X API search-operator syntax; the same query that works on Search Tweets works on Filtered Stream. Limit yourself to 5-10 rules per process at first; complex rule sets get expensive to debug.

Reconnection. WebSocket disconnects happen. Build in an exponential-backoff reconnect, and after reconnect, query the stream for the last N minutes via Search Tweets to fill any gap. That gap-filling step is the difference between a streaming system that's almost always live and one you can actually deploy.

05 — Section

Webhooks — the stateless push pattern for serverless deploys

If you want push semantics but don't want to run a persistent worker, webhooks are the right answer. TwitterAPI.io's webhook pattern: register your HTTPS endpoint + a filter rule via oapi/tweet_filter/add_rule, and the API hits your endpoint with each matching tweet within a few seconds of publication.

Why webhooks fit serverless well. Each tweet is a single HTTP POST to your endpoint, your function handles it, returns 2xx, exits. No long-lived process. Vercel Functions, Cloudflare Workers, AWS Lambda — all native fit. You scale to zero between tweets and pay only when one fires.

Per-event cost. Slightly higher than WebSocket stream (the API service is doing the HTTP delivery work for you), but for low-volume filters (single brand mentions, single VIP account watches) the cost difference is negligible — and the operational savings of not running anything 24/7 usually dominate.

Webhook design rules.

- Always return 2xx within ~10 seconds; do downstream work asynchronously (queue → worker). A slow webhook gets retried, which means duplicate processing.

- Verify the webhook signature on every request. Otherwise an attacker can spoof tweets into your alerting stream.

- De-dupe on tweet_id server-side — webhooks have at-least-once delivery semantics.

06 — Section

Cost economics at scale — when each path stops working

The monitoring path that's right for 1 account is rarely the same path that's right for 1,000 accounts. The per-call cost difference compounds.

Scenario: timeline polling at 60-second cadence per account.

AccountsCalls/monthOfficial X API ($0.005)TwitterAPI.io ($0.00015)
143,200$216$6.50
10432,000$2,160$65
1004,320,000$21,600$650
1,00043,200,000$216,000$6,500

At 100 accounts on the official X API, you're spending more than most teams' entire monitoring budget. At 1,000 accounts, the official path is closed unless you have a contract sizable enough to negotiate enterprise rates — and even then, the third-party path is typically much cheaper because there's no comparable enterprise-tier on the TwitterAPI.io side; the per-call rate stays flat.

A practical rule. If you're monitoring fewer than 10 accounts and need < $30/month total, either path works. If you're monitoring 50+ accounts or need < $100/month total, the third-party path is usually the only economically viable choice for monitoring at production scale. See [our X API cost breakdown for the underlying per-call math](/blog/x-api-cost-breakdown-2026) and [the 2026 official pricing docs](/blog/twitter-api-pricing) for the exact official-API rate card.

07 — Section

Operational notes — rate limits, deletion archives, alerting design

Three operational notes that matter once you're past the prototype stage:

- Rate limits behave differently per path. Official X API has per-endpoint 15-minute caps (75-900 requests per 15 min depending on endpoint). TwitterAPI.io has no equivalent strict 15-minute window — you get spending-limit control instead. See [our JP rate-limit reference for the cap table](/blog/twitter-rate-limit-exceeded) for the exact official numbers.

- Deletion archives. Tweets sometimes vanish within seconds of posting (especially on high-deletion-rate accounts). Timeline polling will miss those; only filtered stream captures them. If you need a deletion-aware archive, layer your timeline poll with periodic re-fetches of older tweet IDs and flag the ones that 404 — that's the only signal the public API surface gives.

- Alerting design. The single biggest failure mode of monitoring systems is alert fatigue. Tune your spike thresholds per account/keyword (median × multiplier, not absolute counts), de-dupe identical alerts within a window, and route VIP signals (high-follower posters, high-engagement-velocity tweets) to a separate higher-urgency channel. The runnable Python in the section above is the simplest version of this; a production system layers a few more checks on top.

python
# pip install requests
import json
import time
import statistics
import pathlib
import requests

API_KEY = "YOUR_TWITTERAPI_IO_KEY"
BASE = "https://api.twitterapi.io"
HANDLE = "elonmusk"             # change to whoever you're monitoring
POLL_INTERVAL = 60               # seconds
VELOCITY_CHECKPOINTS = [15, 60, 360, 1440]  # minutes after first-seen
SPIKE_MULTIPLIER = 3.0           # tune per account

STATE_DIR = pathlib.Path(".state")
STATE_DIR.mkdir(exist_ok=True)
IDS = STATE_DIR / f"{HANDLE}_seen.json"
VEL = STATE_DIR / f"{HANDLE}_velocity.json"
OUT = STATE_DIR / f"{HANDLE}_events.jsonl"

headers = {"X-API-Key": API_KEY}


def load_json(p, default):
    return json.loads(p.read_text()) if p.exists() else default


def save_json(p, obj):
    p.write_text(json.dumps(obj))


def emit(d):
    with OUT.open("a") as f:
        f.write(json.dumps(d) + "\n")


def resolve_uid(handle):
    r = requests.get(f"{BASE}/twitter/user/info",
                     params={"userName": handle}, headers=headers, timeout=10)
    if r.status_code == 404:
        return None  # suspended / handle not found
    r.raise_for_status()
    return str(r.json()["data"]["id"])


def poll_once(uid):
    r = requests.get(f"{BASE}/twitter/user/last_tweets",
                     params={"userId": uid}, headers=headers, timeout=10)
    r.raise_for_status()
    tweets = r.json().get("data", {}).get("tweets", [])
    seen = set(load_json(IDS, []))
    vel = load_json(VEL, [])
    now = time.time()
    engagements = []
    for t in tweets:
        if t["id"] in seen:
            continue
        e = (t.get("likeCount", 0) + t.get("retweetCount", 0) +
             t.get("replyCount", 0))
        emit({"kind": "new_tweet", "id": t["id"], "text": t.get("text"),
              "first_seen_at": now, "engagement": e})
        # schedule velocity re-checks
        for m in VELOCITY_CHECKPOINTS:
            vel.append({"tid": t["id"], "at": now + m * 60})
        seen.add(t["id"]); engagements.append(e)
    save_json(IDS, sorted(seen)[-300:])
    save_json(VEL, vel)
    # Simple spike alert (replace with Slack / PagerDuty / SES)
    if engagements and len(seen) > 30:
        # rolling median of recent engagement
        recent = engagements + [e for e in load_json(STATE_DIR / f"{HANDLE}_eng.json", [])][-100:]
        save_json(STATE_DIR / f"{HANDLE}_eng.json", recent[-100:])
        if len(recent) >= 30:
            median = statistics.median(recent)
            for e in engagements:
                if median > 0 and e > median * SPIKE_MULTIPLIER:
                    print(f"SPIKE: handle={HANDLE} engagement={e} median={median:.0f}")


def velocity_pass():
    vel = load_json(VEL, [])
    due = [c for c in vel if c["at"] <= time.time()]
    rest = [c for c in vel if c["at"] > time.time()]
    save_json(VEL, rest)
    for c in due:
        r = requests.get(f"{BASE}/twitter/tweet/info",
                         params={"tweetId": c["tid"]}, headers=headers, timeout=10)
        if r.status_code == 404:
            emit({"kind": "velocity_checkpoint", "id": c["tid"], "present": False})
        else:
            d = r.json().get("data", {})
            emit({"kind": "velocity_checkpoint", "id": c["tid"], "present": True,
                  "likes": d.get("likeCount"), "retweets": d.get("retweetCount")})


if __name__ == "__main__":
    uid = resolve_uid(HANDLE)
    while True:
        try:
            if uid is None:
                emit({"kind": "handle_inactive", "at": time.time()})
                time.sleep(1800); uid = resolve_uid(HANDLE); continue
            poll_once(uid); velocity_pass()
        except Exception as e:
            print("err:", e)
        time.sleep(POLL_INTERVAL)
08 — Questions

Questions readers ask

What's the cheapest way to monitor a Twitter / X account in 2026?

Timeline polling at 60-second intervals via a third-party X API like TwitterAPI.io. At their $0.00015 per read rate, a single account costs about $6.50/month end-to-end (1,440 reads/day × 30 days × $0.00015). The same workload on the official X API at $0.005/read costs about $216/month — the per-call gap is roughly 33×.

Polling vs streaming vs webhooks — which one should I use?

If your latency requirement is ≥ 60 seconds, use polling (simplest, cheapest, serverless-friendly). If you need sub-5-second freshness and don't want to run a persistent worker, use webhooks (stateless HTTP delivery). If you need sub-second freshness for high-stakes alerting (trading, brand-safety), use the filtered stream (persistent WebSocket). The single-line rule: pick the latency that matches your downstream urgency, then pick the cheapest path that hits it.

Can I monitor tweets without applying for X developer access?

Yes — through a third-party API like TwitterAPI.io, which uses an X-API-Key HTTP header instead of OAuth and skips the 1-2 week developer-platform application. The official X API path still requires the application + OAuth setup. If you want to ship a monitoring prototype this week, the third-party path is meaningfully faster.

What happens if my monitored account gets suspended or deactivated?

user/info returns 404. Treat this as state, not an error — flag your pipeline as handle_inactive and back off to a once-per-hour heartbeat check via user/info. Resume normal poll cadence when the handle resolves again. The Python script in this guide handles this branch automatically.

How do I detect tweet deletions in a monitoring pipeline?

Two layers. First, schedule engagement re-checks at T+15m, T+1h, T+6h, T+24h via tweet/info; any 404 at a checkpoint is a deletion event. Second, accept that sub-minute deletions are unreachable from polling — only the filtered stream captures every tweet before deletion. If you need a guaranteed-complete deletion archive, the stream is the only path.

What's the rate limit on monitoring via the X API?

Official X API has per-endpoint 15-minute caps (75-900 requests per 15 min depending on endpoint). TwitterAPI.io has no equivalent strict 15-minute window — instead, you get spending-limit control (set a maximum monthly spend in the dashboard). For 60-second monitoring of a single account, neither path's rate limit is binding; for high-fan-out monitoring (100+ accounts at 60-second cadence), the third-party path is far more predictable.

Is it legal to programmatically monitor public Twitter accounts?

Programmatic access to public tweets via the X API (official or third-party) is governed by the API's Terms of Service, not by per-account consent — public posts are available for public consumption and analysis under those terms. This is access to public data only; protected accounts are excluded. For commercial downstream uses (brand-safety products, social listening platforms, sentiment analytics), consult your jurisdiction's data-protection regulations on top of the API ToS.

09 — Further reading

Continue

Sources & further reading
More from this series
Build it

Stop reading. Start building.

Starter credits cover real testing on real data. Google sign-in, no card, no application queue.

Get an API key
    Monitor Twitter (X) Tweets via API — Dev Guide | TwitterAPI.io