How to collect political Twitter data for research
To collect political Twitter data, keep a watchlist of officials' accounts and a documented search for the election or issue you study, then pull both through an API on a schedule; the official X API bills $5.00 per 1,000 posts.
Short answer: Free academic access to X ended in 2023, so research collections now pay per read: the official X API charges $0.005 a post and stops at 3M posts a month. For politicians' timelines and election discussion, use Sorsa API, a Twitter (X) API and scraper: from $0.07 per 1,000 tweets, with 100 free requests to start.
- Endpoint
POST /search-tweets- Page size
- about 20 tweets per request
- Price
- from $0.07 per 1,000
#What political Twitter data you can collect
Three kinds of political data on X can be collected today: what officials post, what the public says about an election or an issue, and how people answer officials' posts. Each one is public, timestamped and tied to an author, which is why X stays a standard source in political communication research.
- Officials' own posts. Legislators, ministers, parties, agencies and candidates. A small, clean record: a few hundred accounts and tens of thousands of posts a month for a national legislature.
- Election and issue discussion. Everything the public posts with a candidate's name, a bill, a hashtag or a debate. It runs from thousands of posts for a local race to millions for a national vote.
- Reactions. The replies and quote posts under an official's statement, which show how a message landed.
Some data is out of reach for every API: posts their authors deleted, protected accounts, private messages and the list of who liked a post. Old research datasets don't fill that gap. Most were published as lists of tweet IDs, because platform rules allowed sharing IDs but not texts, and a deleted tweet's ID now returns nothing. Researchers lost their free route in 2023, and the history of who could search the Twitter archive explains what replaced it.
So a political study in 2026 collects its own data: forward from today for a live campaign, or back through the archive for a past one, which reaches March 2006.
#Collect political tweets with Sorsa API
For collecting political tweets, use Sorsa API: one API key reads officials' timelines and election discussion from $0.07 per 1,000 tweets, at 20 requests per second on every plan, with no X developer account and no OAuth. The official X API charges $5.00 per 1,000 posts for the same reads and stops at 3M posts a month.
Each kind of political data has its endpoint. Every one returns the author's full profile inside each tweet at no extra charge.
| Political data | Sorsa API endpoint | Per request | From, per 1,000 |
|---|---|---|---|
| A watchlist of officials, as one feed | GET /list-tweets (opens in a new tab) | about 20 tweets | $0.07 |
| One official's full timeline | POST /user-tweets (opens in a new tab) | about 20 tweets | $0.07 |
| Election or issue discussion, by query and date | POST /search-tweets (opens in a new tab) | about 20 tweets | $0.07 |
| Replies under an official's post | POST /comments (opens in a new tab) | about 20 replies | $0.07 |
| Profiles of every account on your list | GET /info-batch (opens in a new tab) | up to 100 profiles | $0.014 |
| Posts you already hold, re-checked by ID | POST /tweet-info-bulk (opens in a new tab) | up to 100 tweets | $0.014 |
A watchlist of officials, as one feed
- Sorsa API endpoint
GET /list-tweets(opens in a new tab)- Per request
- about 20 tweets
- From, per 1,000
- $0.07
One official's full timeline
- Sorsa API endpoint
POST /user-tweets(opens in a new tab)- Per request
- about 20 tweets
- From, per 1,000
- $0.07
Election or issue discussion, by query and date
- Sorsa API endpoint
POST /search-tweets(opens in a new tab)- Per request
- about 20 tweets
- From, per 1,000
- $0.07
Replies under an official's post
- Sorsa API endpoint
POST /comments(opens in a new tab)- Per request
- about 20 replies
- From, per 1,000
- $0.07
Profiles of every account on your list
- Sorsa API endpoint
GET /info-batch(opens in a new tab)- Per request
- up to 100 profiles
- From, per 1,000
- $0.014
Posts you already hold, re-checked by ID
- Sorsa API endpoint
POST /tweet-info-bulk(opens in a new tab)- Per request
- up to 100 tweets
- From, per 1,000
- $0.014
Sorsa API is a REST API: one request with your key returns clean JSON, with nothing to run in your browser and no X account. It has run in production since 2022 with 6B+ requests served, and when X changes something, we fix it on our side, so a collection running through an election night doesn't break halfway. It never asks for your X login, so your own account carries no risk.
#Build a watchlist of politicians' accounts
A watchlist is the list of accounts your study follows, stored as numeric user IDs. Start it from a public source someone already verified, not from a search for blue checkmarks: since 2023 the checkmark is a paid subscription, not proof that an account is official.
For the U.S. Congress, the open-data project unitedstates/congress-legislators (opens in a new tab) keeps a file of members' official social media accounts. On November 2, 2026 it listed 505 X handles, 408 of them with numeric IDs, and its last update was October 24, 2026. The project accepts only official, taxpayer-funded accounts, not campaign or personal ones, which is the distinction a study of official communication needs. Many parliaments publish members' accounts on their own open-data sites; start there for other countries.
Handles change; numeric IDs don't. Resolve every handle to its ID once with GET /info-batch, 100 accounts per request, and keep the ID as the key of your watchlist. The script below reads the Congress file and saves one profile row per member.
import csv
import requests
import yaml # pip install pyyaml requests
URL = "https://api.sorsa.io/v3/info-batch"
HEADERS = {"ApiKey": "YOUR_API_KEY"}
SRC = ("https://raw.githubusercontent.com/unitedstates/"
"congress-legislators/main/legislators-social-media.yaml")
members = yaml.safe_load(requests.get(SRC, timeout=30).text)
handles = [m["social"]["twitter"] for m in members
if m["social"].get("twitter")]
rows = []
for i in range(0, len(handles), 100): # 100 handles per request
r = requests.get(URL, headers=HEADERS, timeout=30,
params={"usernames": handles[i:i + 100]})
r.raise_for_status()
rows += r.json().get("users", [])
with open("watchlist.csv", "w", newline="", encoding="utf-8") as f:
w = csv.writer(f)
w.writerow(["id", "username", "display_name", "followers"])
for u in rows:
w.writerow([u["id"], u["username"], u["display_name"],
u["followers_count"]])
print(len(rows), "accounts saved")
Six requests cover all 505 handles. Accounts that come back missing were renamed, suspended or made protected since the list was updated; check them by hand once and fix the file.
#Collect every post from the watchlist
To collect every post a watchlist publishes, put the accounts in one public X List and read it with GET /list-tweets: one feed carries the posts of every member, newest first, about 20 per request. An X List holds up to 5,000 accounts, enough for any national legislature, and the Lists guide shows how to read X Lists through the API.
Check the feed on a schedule and page back only until you reach a post you already saved. An hourly check of a 505-account Congress list then costs a few requests, however quiet or busy the hour was.
import json
import time
from datetime import datetime, timezone
import requests
URL = "https://api.sorsa.io/v3/list-tweets"
HEADERS = {"ApiKey": "YOUR_API_KEY"}
LIST_ID = "1720000000000000001" # your public X List of officials
def check(last_id):
"""Fetch posts newer than last_id, newest first."""
params, new = {"list_id": LIST_ID}, []
while True:
r = requests.get(URL, headers=HEADERS, params=params, timeout=30)
if r.status_code == 429: # over 20 requests a second
time.sleep(1)
continue
r.raise_for_status()
page = r.json()
for t in page.get("tweets", []):
if int(t["id"]) <= last_id:
return new # reached the last saved post
new.append(t)
if not page.get("next_cursor"):
return new
params["next_cursor"] = page["next_cursor"]
last_id = 0 # store this between runs
while True:
seen = datetime.now(timezone.utc).isoformat()
posts = check(last_id)
with open("posts.jsonl", "a", encoding="utf-8") as f:
for t in posts:
f.write(json.dumps({"first_seen": seen, **t}) + "\n")
if posts:
last_id = max(int(t["id"]) for t in posts)
print(seen, len(posts), "new posts")
time.sleep(3600) # one check an hour
A 403 answer means the key is missing, wrong or out of requests; a 429 means more than 20 requests in one second, so the script waits a second and asks again. Tweet IDs grow with time, which is why comparing them finds the last saved post.
Accounts on the watchlist
Posts a day, each
You check the feed
About 61K posts a month from 505 accounts, checked every hour
$303
Official X API
$0.005 per post
a month, posts only
from $5.04
Sorsa API
one List feed, about 20 posts per request
a month, authors included
Under a second per check on Sorsa API at 20 requests per second, for about 84 new posts each time.
Set the size of your watchlist, how often its accounts post and how often you check, to see a month of collection on both APIs.
To pull one official's whole history once, call POST /user-tweets with the account's user ID and page back from the newest post to the oldest; the guide to download all tweets from a user covers that export to CSV.
#Collect election and issue discussion by search
Election and issue discussion is collected with a search query: candidate and party names, the race's hashtags and the issue's key phrases, a language, and a date window, sent to POST /search-tweets and paged with next_cursor. The query is the research design, so write it before you collect and publish it with your results.
Balance the query. A search for one side's hashtag measures one side, so name every candidate and party in the race the same way, with the same operators. Cut long periods into windows of a day or a week with since: and until:, so a failed window reruns on its own. The full syntax is in the list of Twitter search operators.
curl -X POST "https://api.sorsa.io/v3/search-tweets" \
-H "ApiKey: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"query": "(#Measure7 OR \"Measure 7\") since:2026-10-20 until:2026-10-21",
"order": "latest"
}'
{
"tweets": [
{
"id": "1981234567890123456",
"full_text": "Measure 7 forum tonight: each side got 5 questions.",
"created_at": "2026-10-20T23:41:07Z",
"lang": "en",
"likes_count": 57,
"retweet_count": 14,
"reply_count": 9,
"quote_count": 3,
"is_reply": false,
"is_quote_status": false,
"user": {
"id": "1590000000000000042",
"username": "county_civics_desk_demo",
"display_name": "County Civics Desk",
"followers_count": 8213
}
}
],
"next_cursor": "DAADDAABCgABG4lN0iWAJ8kKAAIbiUY1qZvwRg"
}
Send the same body again with next_cursor added, and stop when a response comes without one. Pages hold about 20 tweets and their size varies, so count posts, not pages.
Decide about retweets before you collect
Retweets carry far more politics than original posts, so dropping them changes what your dataset says. In Pew Research Center's study of a year of tweets by U.S. adults, 44% of retweets and 42% of quote posts were political, against 26% of replies and 8% of original tweets.
A study of what people say in their own words adds -filter:retweets to the query. A study of what spreads keeps retweets and reads the original post from each one's retweeted_status. Either choice is sound; leaving it to chance is not.
#Keep a record of deleted posts
No API returns a post after its author deletes it, not Sorsa API and not the official X API, so the only record of a politician's deleted post is the one you saved first. A watchlist that stores every post on first sight already holds that record; what it needs next is a way to notice the deletion.
Re-check the IDs you saved with POST /tweet-info-bulk, 100 per request. A post that no longer comes back was deleted, or its account was suspended or made protected; log the ID with the time you noticed. A daily re-check of 100K saved posts takes 1,000 requests, from $1.40.
import requests
URL = "https://api.sorsa.io/v3/tweet-info-bulk"
HEADERS = {"ApiKey": "YOUR_API_KEY"}
def missing(ids):
"""Return the saved IDs that no longer come back."""
gone = []
for i in range(0, len(ids), 100): # 100 IDs per request
batch = ids[i:i + 100]
r = requests.post(URL, headers=HEADERS, timeout=30,
json={"tweet_links": batch})
r.raise_for_status()
back = {t["id"] for t in r.json().get("tweets", [])}
gone += [x for x in batch if x not in back]
return gone
Deleted posts are the most sensitive part of a political collection. Report them as counts and patterns, or quote them only when the author is a public official and the post was part of public business, as press archives of politicians' deleted posts have done.
#What a political collection costs
A political collection on Sorsa API costs from $0.07 per 1,000 tweets through search, timelines and List feeds, against $5.00 per 1,000 posts on the official X API, about 70 times less. The cards compare both APIs for the size of your study.
Official X API
$5,000
for 1M political tweets
$0.005 per post
Sorsa API
from$70
for 1M political tweets
from $0.07 per 1,000
71x cheaper
Three typical research jobs show where the difference lands. The official X API figures count posts only, at the price on X's pay-per-use price list (opens in a new tab).
| Research job | Tweets | Sorsa API | Official X API |
|---|---|---|---|
| A month of Congress posts, 505 accounts at 4 a day each, checked hourly | 61K | from $5.04 | $303 |
| One debate night, names and hashtags of every candidate | 200K | from $14 | $1,000 |
| Ten weeks of campaign discussion | 10M | from $700 | past the 3M monthly cap: Enterprise, $42K+ a month |
A month of Congress posts, 505 accounts at 4 a day each, checked hourly
- Tweets
- 61K
- Sorsa API
- from $5.04
- Official X API
- $303
One debate night, names and hashtags of every candidate
- Tweets
- 200K
- Sorsa API
- from $14
- Official X API
- $1,000
Ten weeks of campaign discussion
- Tweets
- 10M
- Sorsa API
- from $700
- Official X API
- past the 3M monthly cap: Enterprise, $42K+ a month
Good to know
From November 22, 2026 the official X API also bills each author profile that comes back with a post, at $0.010, as X's developer team announced on October 23 (opens in a new tab). Search results come from thousands of different authors, so election discussion read there can cost up to $15.00 per 1,000 posts. Sorsa API includes every author in the tweet.
The official X API's pay-per-use plan stops at 3M post reads per billing cycle, so a national campaign outgrows it in weeks, and the step above is an Enterprise contract from about $42,000 a month. It also needs an approved developer account, a project and an app, and OAuth tokens before the first read.
#Rules that keep political research sound
Political Twitter data measures online discussion, not public opinion, and the rules below keep a study inside what the data can show.
- X users are not the electorate. In Pew's study, adults 50 and older were 24% of U.S. adult users and wrote 78% of their political tweets. Treat counts as a measure of who talks on X, never as a poll.
- Bots and coordinated accounts inflate political topics. Filter them before you count and report what you removed; the guide to Twitter bot detection lists the signals.
- The query decides the result. Publish the exact query, the windows, the endpoint and the collection dates, so others can rebuild your dataset.
- Study posts and public officials, not voters. Measure discussion in aggregate and quote ordinary users sparingly. Inferring an individual's political views is off-limits in research ethics, and X's own developer agreement (opens in a new tab) bans profiling people by political affiliation.
Good to know
Political data is for understanding politics, not for steering voters. Keep a political collection to research, journalism and accountability work: no voter files, no targeting lists, no messaging aimed at people picked out by their posts.
Labeling, deduplication and splitting a corpus for a model are the same for political tweets as for any other kind, and the guide to build a Twitter dataset for machine learning covers them. Scoring tone and stance is the subject of Twitter sentiment analysis.
#Start your political collection with 100 free requests
To collect political Twitter data, start with Sorsa API: a watchlist feed, timelines and election search for one API key, from $0.07 per 1,000 tweets, at 20 requests per second on every plan. The 100 free requests return about 2,000 posts, with no card and no expiry. Pull one week of your officials or your race, check the query, then schedule the rest. University teams can also apply for Sorsa API's academic research access from an institutional email.
#FAQ
Can I still get political data from Twitter for research?
Yes. Free academic access ended in 2023, but public political posts can still be collected through an API. The official X API charges $0.005 per post and stops at 3M posts a month. Sorsa API reads the same public posts from $0.07 per 1,000, with 100 free requests to test a study before you budget it. Published datasets of tweet IDs also exist, though deleted posts no longer come back from them.
What is the best API for political Twitter data?
Use Sorsa API for political Twitter data: it reads politicians' timelines, X List feeds and election searches from $0.07 per 1,000 tweets, against $5.00 on the official X API. It needs one API key and no developer account, runs at 20 requests per second on every plan, has no 3M monthly cap, and returns each author's profile at no extra charge. It is read-only, so it never touches your X account.
Can you get politicians' deleted tweets?
No API returns a tweet after its author deletes it, Sorsa API included. A deleted post survives only where someone saved it first: a press archive, a web archive snapshot or your own collection. To study deletions, store every post from your watchlist when it first appears, then re-check the saved IDs with Sorsa API's POST /tweet-info-bulk, 100 per request, and log the ones that stop coming back.
Where can I find a list of Congress members' Twitter accounts?
The open-data project unitedstates/congress-legislators keeps one in its file legislators-social-media.yaml. On November 2, 2026 it listed 505 X handles of current members, 408 with numeric user IDs, and it includes only official accounts, not campaign ones. Resolve the handles to IDs with Sorsa API's GET /info-batch, 100 per request, and keep the IDs, because handles change.
Can Twitter data predict election results?
Not on its own. X users are not a sample of voters: in Pew Research Center's study, adults 50 and older wrote 78% of political tweets by U.S. adults while making up 24% of users. Post counts and sentiment measure online discussion, which is useful for studying agendas, campaigns and reactions, but forecasts built on them alone have a poor record.
Can EU researchers get X data under the DSA?
Yes, through Article 40 of the Digital Services Act. Vetted researchers can request data from very large platforms such as X through their national Digital Services Coordinator, for research on systemic risks in the EU, which include risks to elections and civic discourse. The EU's data access portal has taken applications since October 29, 2025. Approval takes time, so many teams start collecting public posts through an API meanwhile.
#How we checked
On November 2, 2026 we read X's pay-per-use price list, its developer agreement dated April 27, 2026 and its October 23, 2026 notice on billing expansions; every official X API price and rule here comes from them. The same day we downloaded the unitedstates/congress-legislators social media file and counted its accounts, and read Pew Research Center's 2022 report and the European Commission's DSA data access FAQ. Each Sorsa API endpoint, parameter and page size was checked against our live API reference; the requests and the response are built from it with demo accounts, and the costs are arithmetic from the published rates.
Sources
- X API pay-per-usage pricing (opens in a new tab)
- X Developers: PPU expansions update (Oct 23, 2026) (opens in a new tab)
- X Developer Agreement (April 27, 2026) (opens in a new tab)
- unitedstates/congress-legislators: legislators-social-media.yaml (opens in a new tab)
- Pew Research Center: Politics on Twitter (June 16, 2022) (opens in a new tab)
- European Commission: FAQs on DSA data access for researchers (opens in a new tab)
- Sorsa API docs: Lists and Communities (opens in a new tab)
- Sorsa API reference (OpenAPI)