Twitter (X) Hashtag Popularity Tracker — API Guide
Hashtag popularity is one of the most common Twitter (X) data workflows — trend spotting, campaign ROI, cultural moment analysis, influencer identification. This guide walks the exact API pattern + aggregation math + a real cost model with runnable Python.
Pricing references URL-cited per provider.
Hashtag popularity — what to actually measure
'Popularity' is not one metric — it's a bundle. Different workflows care about different signals:
Volume: tweet count per unit time (hour / day / week). Tells you when a hashtag spiked.
Reach proxy: sum of author follower_counts across all tweets using the hashtag. Tells you total audience exposure.
Engagement: sum of favorite_count + retweet_count across tweets. Tells you how much people actually cared.
Unique authors: distinct handles using the hashtag. Tells you whether it's a coordinated push or organic spread.
Velocity: tweets-per-hour rate change. Tells you if the hashtag is climbing or decaying.
All 5 metrics come from the same /twitter/tweet/advanced_search call — you compute them in your downstream aggregation.
Runnable — hashtag daily snapshot
Simplest useful workflow: pull today's tweets containing a hashtag, compute the 5 popularity metrics.
import os, requests
from collections import Counter, defaultdict
from datetime import datetime, timedelta
HEADERS = {"X-API-Key": os.environ["TWITTERAPI_IO_KEY"]}
BASE = "https://api.twitterapi.io"
def snapshot(hashtag: str, since_days: int = 1) -> dict:
since = (datetime.utcnow() - timedelta(days=since_days)).strftime("%Y-%m-%d")
tweets, cursor = [], None
for _ in range(50):
params = {"query": f"#{hashtag} since:{since}"}
if cursor: params["cursor"] = cursor
r = requests.get(f"{BASE}/twitter/tweet/advanced_search", headers=HEADERS, params=params, timeout=15)
r.raise_for_status()
resp = r.json()
tweets.extend(resp.get("tweets", []))
cursor = resp.get("next_cursor")
if not cursor: break
volume = len(tweets)
reach = sum((t.get("author", {}).get("followers_count") or 0) for t in tweets)
engagement = sum((t.get("favorite_count", 0) + t.get("retweet_count", 0)) for t in tweets)
authors = len(set(t.get("author", {}).get("userName") for t in tweets if t.get("author")))
return {
"hashtag": hashtag, "since_days": since_days,
"volume": volume, "reach": reach, "engagement": engagement,
"unique_authors": authors,
"avg_engagement_per_tweet": engagement / max(volume, 1),
}
snap = snapshot("OpenAI", since_days=1)
print(snap)
# Cost per twitterapi.io/pricing: volume × $0.00015Time-series — 30-day popularity curve
Daily snapshots aggregated over 30 days give the popularity trend. Useful for measuring campaign impact, event virality, cultural moment decay.
Best practice: run the snapshot as a nightly cron, append daily rows to a CSV or database. After 30 days you have a clean time-series to plot.
# 30-day historical hashtag popularity — one-shot pull.
import os, requests, csv
from datetime import date, timedelta
from pathlib import Path
HEADERS = {"X-API-Key": os.environ["TWITTERAPI_IO_KEY"]}
BASE = "https://api.twitterapi.io"
def pull_day(hashtag: str, d: date) -> tuple[int, int, int]:
query = f"#{hashtag} since:{d} until:{d + timedelta(days=1)}"
n, reach, engagement, cursor = 0, 0, 0, None
for _ in range(50):
params = {"query": query}
if cursor: params["cursor"] = cursor
r = requests.get(f"{BASE}/twitter/tweet/advanced_search", headers=HEADERS, params=params, timeout=15)
r.raise_for_status()
resp = r.json()
for t in resp.get("tweets", []):
n += 1
reach += (t.get("author", {}).get("followers_count") or 0)
engagement += t.get("favorite_count", 0) + t.get("retweet_count", 0)
cursor = resp.get("next_cursor")
if not cursor: break
return n, reach, engagement
HASHTAG = "OpenAI"
END = date.today()
START = END - timedelta(days=30)
out = Path(f"{HASHTAG.lower()}_popularity_30d.csv")
with open(out, "w") as f:
w = csv.writer(f)
w.writerow(["date", "volume", "reach", "engagement"])
d = START
total = 0
while d < END:
n, r_, e = pull_day(HASHTAG, d)
w.writerow([d.isoformat(), n, r_, e])
total += n
print(f" {d}: {n:,} tweets, reach {r_:,}, engagement {e:,}")
d += timedelta(days=1)
print(f"\n30-day total: {total:,} tweets")
print(f"Cost per twitterapi.io/pricing: {total} × $0.00015 = ${total * 0.00015:.2f}")Top-tweet leaderboard — engagement-sorted
For influencer / viral-tweet identification, sort the returned tweets by engagement. Combine favorite_count + retweet_count + reply_count as the composite engagement score.
Filter to min_faves:100 at query time to pre-cut noise — top-tweet workflows care about high-signal tweets, not the long tail.
Cost math per workflow
Cost scales with tweet volume returned, per twitterapi.io/pricing. Rough estimates for common workflows:
Practical rule: always add min_faves:5 or min_faves:10 for research pulls — cuts 90%+ of noise and 90%+ of cost with negligible signal loss.
Comparison — 3 hashtag-tracking paths
Advanced patterns
Cross-hashtag correlation: pull 10 related hashtags over the same 30-day window → correlate daily volumes → identify hashtag clusters that spike together.
Sentiment overlay: send the returned tweet texts through a sentiment API (or LLM) → correlate volume + sentiment for campaign health metrics.
Influencer surface: aggregate the author.userName field weighted by engagement → top 20 authors driving the hashtag's engagement are your influencer list.
Coordinated-behavior detection: unique-authors / volume ratio anomalies (many tweets, few authors) signal coordinated inauthentic activity.
# Cross-hashtag comparison — 10 tags × 30 days for pattern analysis.
import os, requests, csv
from datetime import date, timedelta
HEADERS = {"X-API-Key": os.environ["TWITTERAPI_IO_KEY"]}
BASE = "https://api.twitterapi.io"
def pull_day_count(hashtag: str, d: date) -> int:
query = f"#{hashtag} since:{d} until:{d + timedelta(days=1)}"
n, cursor = 0, None
for _ in range(50):
params = {"query": query}
if cursor: params["cursor"] = cursor
r = requests.get(f"{BASE}/twitter/tweet/advanced_search", headers=HEADERS, params=params, timeout=15)
r.raise_for_status()
resp = r.json()
n += len(resp.get("tweets", []))
cursor = resp.get("next_cursor")
if not cursor: break
return n
HASHTAGS = ["OpenAI", "Anthropic", "Claude", "GPT4", "Gemini", "Mistral", "Llama", "AI", "MachineLearning", "LLM"]
END = date.today()
START = END - timedelta(days=30)
rows = []
d = START
while d < END:
row = {"date": d.isoformat()}
for h in HASHTAGS:
row[h] = pull_day_count(h, d)
rows.append(row)
print(f" {d}: {sum(row[h] for h in HASHTAGS):,} total")
d += timedelta(days=1)
with open("hashtag_matrix_30d.csv", "w") as f:
w = csv.DictWriter(f, fieldnames=["date"] + HASHTAGS)
w.writeheader()
w.writerows(rows)
# Downstream: pandas.read_csv() → correlation matrix → identify hashtag clusters
# Cost per twitterapi.io/pricing: sum of all pulls × $0.00015Questions readers ask
How real-time are the results?
twitterapi.io's advanced_search returns tweets typically within 1-2 minutes of posting. For minute-level tracking, poll every 5-15 minutes; for true real-time streaming, see /blog/twitter-streaming-api-real-time-guide.
Do I need to prefix with # or without?
Include the #. Query string #OpenAI matches tweets containing the hashtag; query OpenAI matches tweets containing the word (with or without hash). For hashtag popularity specifically, use #OpenAI.
Case sensitivity?
Hashtags are case-insensitive at X's search layer — #openai, #OpenAI, #OPENAI all match the same tweet set. Query in any case.
What about deleted tweets that had the hashtag?
Deleted before query time may not appear. For deletion tracking, snapshot at time T then re-check at T+1 day and diff. See /blog/deleted-tweet-search for the workflow.
Rate limits when pulling 10 hashtags in parallel?
Per-key throughput on twitterapi.io comfortably handles 10-20 concurrent search requests. For 100+ hashtags parallel, stagger with ThreadPoolExecutor(max_workers=10) to stay well within safe throughput.
How do I filter out bot-driven hashtag volume?
Post-filter by author properties: followers_count > 100, created_at > 30 days ago, default_profile_image = False. Combine 2-3 of these to strip most low-quality accounts from your popularity metric.
Best sample size for a 'popularity' baseline?
For most workflows, 500-2000 tweets gives a stable engagement + reach signal. For sentiment analysis specifically, aim for 1000+ for confidence interval stability.
Continue
- Twitter (X) API — cluster hub
- Twitter (X) hashtag tracker tools comparison
- Twitter (X) hashtag analytics API guide
- Twitter (X) hashtag search API tutorial
- Twitter (X) trends API guide
- twitterapi.io pricing
Stop reading. Start building.
Starter credits cover real testing on real data. Google sign-in, no card, no application queue.
Get an API key