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