Skip to main content
← Back to blog
by Data Team
guideresearch

Twitter/X Data for Academic Research — What You Can Access in 2026

The End of Free Academic Access

In early 2023, Twitter (now X) shut down the Academic Research API — a program that gave verified researchers free access to the full archive of public tweets. For years, this was the backbone of computational social science. Thousands of published papers relied on it for everything from tracking misinformation to monitoring public health crises.

The shutdown wasn't gradual. One day the keys worked, the next they didn't. Research teams with multi-year longitudinal studies suddenly lost their data pipeline. IRB-approved projects had to scramble for alternatives mid-study.

If you're a researcher in 2026, here's what you need to know about the current landscape.

Current X API Pricing for Research

X now operates a tiered commercial API. Here's what each tier gives you for research purposes:

TierMonthly CostTweet ReadsSearchHistorical Access
Free$0~100/monthNoneNone
Basic$20010,000/month7-day windowNone
Pro$5,0001,000,000/month30-day windowLimited
Enterprise$42,000+CustomFull archiveFull

For most academic budgets, Pro and Enterprise are out of reach. A typical NSF grant allocates $5K–15K for the entire data collection phase — not per month. Basic's 10K tweet cap is consumed in minutes when studying any trending topic.

The math is brutal: if your study requires 500K tweets over 6 months, you're looking at roughly $30K on the Pro tier. That's more than many graduate student stipends.

What Data Do Researchers Actually Need?

Based on published methodology sections across top venues (ICWSM, CHI, WWW, CSCW), academic Twitter research typically requires:

Tweet Collections

Volume: 50K–5M tweets for quantitative studies
Timeframe: Often 1–3 months around an event (election, pandemic wave, product launch)
Fields: Full text, timestamps, engagement counts, media attachments, reply/quote context

Network Data

Follower/following graphs for influence propagation studies
Retweet cascades for information diffusion modeling
Mention networks for community detection
Conversation threads for discourse analysis

User Metadata

Account creation date, bio, location, verification status
Historical follower counts (for growth analysis)
Activity patterns (posting frequency, active hours)

Temporal Data

Tweets ordered by time for event-based studies
Real-time collection during live events
Historical snapshots for before/after comparisons

Legal Considerations

Before collecting any Twitter data, researchers must navigate several legal frameworks:

X Terms of Service

You may collect public tweets via authorized API access
Redistribution of full tweet text is prohibited — you can only share tweet IDs (and others must "rehydrate" them)
Automated scraping without API access violates the ToS, though enforcement varies
X reserves the right to revoke access at any time

GDPR (EU Researchers)

Twitter usernames and tweet content constitute personal data under GDPR
You need a lawful basis for processing — typically "legitimate interest" or "public task" for academic research
Users have the right to erasure — if someone deletes their tweet, your dataset should reflect that
Data Protection Impact Assessments (DPIAs) are recommended for large-scale social media studies

CCPA (US/California)

Similar to GDPR but with different thresholds
Applies if your dataset includes California residents (which it almost certainly does)

Copyright

Individual tweets may be copyrightable (courts are still debating this)
Fair use typically covers academic research, but don't publish entire tweet corpora without legal review

Ethical Guidelines

Legal compliance is the floor, not the ceiling. Here's what IRBs and ethics boards expect:

Informed Consent

The standard in social media research is evolving. Most IRBs accept that public tweets don't require individual consent, but:

If you're studying vulnerable populations (mental health, addiction, political dissidents), consider consent mechanisms
If your research could identify individuals even with anonymization, consent is strongly recommended
Some journals now require a statement on consent even for public data studies

Anonymization

Standard practice includes:

Replace usernames with random identifiers (USER_001, USER_002)
Remove or hash profile URLs and display names
Strip location data unless it's central to your research question
Be aware of re-identification risk — a unique enough tweet can be Googled back to its author

IRB Requirements

Most US universities classify public Twitter data collection as exempt or expedited review
EU institutions increasingly require full review for social media research
Document your data handling, storage, and deletion plans before starting collection

Data Retention

Only keep data as long as needed for your study
Have a deletion plan and timeline
Store data on encrypted, access-controlled systems
Never store data on personal devices or cloud services without institutional approval

Alternative Data Collection Methods

With the official API priced out of reach for most academics, researchers have turned to several alternatives:

1. Third-Party API Services

Services that aggregate Twitter data and offer it at lower price points. These typically maintain their own data collection infrastructure and pass savings to users. Pricing ranges from $5–50/month for volumes that would cost $5K+ on the official API.

2. Pre-Built Datasets

Several repositories host curated Twitter datasets:

Zenodo — Academic data repository, many Twitter datasets with DOIs
Harvard Dataverse — Hosts tweet ID datasets for rehydration
ICWSM Data Challenge — Annual curated datasets for research

The downside: you're limited to what someone else already collected.

3. Pushshift / Archive Projects

Community-driven archives that capture public social media data. Availability and legality vary by jurisdiction.

4. Collaborative Collection

Pool resources with other research groups. If five labs each contribute $1K/month to a shared Pro tier API account, everyone benefits.

5. Qualitative Approaches

For smaller studies, manual collection of publicly visible tweets is both legal and ethically straightforward. Tools like screenshots with consent can work for studies under 1,000 tweets.

Sample Research Use Cases

Misinformation Tracking

Collecting tweets containing specific claims during breaking news events, tracking how they spread through retweet networks, and measuring the reach of corrections.

Data needs: Real-time search, conversation threads, retweet cascades, user network data. Typically 100K–1M tweets over 1–4 weeks.

Public Health Surveillance

Monitoring symptom mentions, vaccine sentiment, or health behavior discussions across geographic regions.

Data needs: Keyword-based search with location filtering, longitudinal collection over months, user bio parsing for demographics. Typically 500K–5M tweets.

Political Discourse Analysis

Studying how political narratives form, spread, and evolve on the platform during elections or policy debates.

Data needs: Full conversation threads, quote tweet chains, user political alignment classification, temporal analysis. Typically 1M–10M tweets.

Community Detection

Identifying and mapping online communities around specific topics (crypto, gaming, activism) through interaction networks.

Data needs: Follower/following graphs, mention networks, reply threads, user metadata. Typically 50K–500K users.

Structuring a Research Dataset

Here's a practical Python example for collecting and organizing Twitter data for research. This covers the anonymization and metadata layer — for the full collection/export toolkit (search pagination, batch user lookup, network data, CSV/JSON export, credit budgeting) see [Export Twitter Data for Research](/blog/twitter-data-export-research).

PYTHON
import requests
import json
import hashlib
import os
from datetime import datetime

class ResearchDataCollector:
    """Collect and structure Twitter data for academic research."""

    def __init__(self, api_key, output_dir="research_data"):
        self.api_key = api_key
        self.base_url = "https://xcrop.io/api/v2"
        self.headers = {"Authorization": "Bearer " + api_key}
        self.output_dir = output_dir
        os.makedirs(output_dir, exist_ok=True)

    def anonymize_user(self, username):
        """Generate a consistent anonymous ID for a username."""
        hash_val = hashlib.sha256(username.encode()).hexdigest()[:12]
        return "USER_" + hash_val

    def collect_search_results(self, query, max_pages=5):
        """Collect tweets matching a search query."""
        all_tweets = []
        cursor = None

        for page in range(max_pages):
            payload = {
                "query": query,
                "count": 20,
                "sort": "latest"
            }
            if cursor:
                payload["cursor"] = cursor

            response = requests.post(
                self.base_url + "/search",
                headers=self.headers,
                json=payload
            )

            if response.status_code != 200:
                print("Error on page " + str(page) + ": " + str(response.status_code))
                break

            result = response.json()
            tweets = result.get("data", [])
            all_tweets.extend(tweets)

            cursor = result.get("meta", {}).get("next_cursor")
            if not cursor:
                break

            print("Page " + str(page + 1) + ": collected " + str(len(tweets)) + " tweets")

        return all_tweets

    def anonymize_dataset(self, tweets):
        """Remove identifying information from tweets."""
        anonymized = []
        for tweet in tweets:
            record = {
                "tweet_id": tweet.get("id"),
                "text": tweet.get("text", ""),
                "created_at": tweet.get("created_at", ""),
                "likes": tweet.get("likes", 0),
                "retweets": tweet.get("retweets", 0),
                "replies": tweet.get("replies", 0),
                "user_anon_id": self.anonymize_user(
                    tweet.get("user", {}).get("username", "unknown")
                ),
                "user_verified": tweet.get("user", {}).get("verified", False),
                "user_followers_bucket": self._bucket_followers(
                    tweet.get("user", {}).get("followers", 0)
                ),
                "has_media": bool(tweet.get("media")),
                "is_reply": bool(tweet.get("in_reply_to")),
                "is_quote": bool(tweet.get("quoted_tweet")),
                "language": tweet.get("lang", "unknown")
            }
            anonymized.append(record)
        return anonymized

    def _bucket_followers(self, count):
        """Bin follower counts to prevent re-identification."""
        if count < 100:
            return "<100"
        elif count < 1000:
            return "100-1K"
        elif count < 10000:
            return "1K-10K"
        elif count < 100000:
            return "10K-100K"
        else:
            return "100K+"

    def save_dataset(self, data, filename):
        """Save dataset as JSON Lines (one record per line)."""
        filepath = os.path.join(self.output_dir, filename)
        with open(filepath, "w") as f:
            for record in data:
                f.write(json.dumps(record) + "\n")
        print("Saved " + str(len(data)) + " records to " + filepath)

    def generate_metadata(self, query, tweet_count):
        """Generate a metadata file documenting the collection."""
        metadata = {
            "collection_date": datetime.now().isoformat(),
            "query": query,
            "total_tweets": tweet_count,
            "anonymized": True,
            "follower_counts_bucketed": True,
            "fields_removed": [
                "username", "display_name", "profile_url",
                "bio", "location", "profile_image"
            ],
            "retention_plan": "Delete raw data after publication",
            "irb_protocol": "YOUR_IRB_NUMBER_HERE"
        }
        filepath = os.path.join(self.output_dir, "collection_metadata.json")
        with open(filepath, "w") as f:
            json.dump(metadata, f, indent=2)
        print("Metadata saved to " + filepath)


# Usage example
collector = ResearchDataCollector(api_key=os.environ["XCROP_API_KEY"])

# Collect tweets about a research topic
tweets = collector.collect_search_results("vaccine sentiment", max_pages=10)

# Anonymize the dataset
clean_data = collector.anonymize_dataset(tweets)

# Save for analysis
collector.save_dataset(clean_data, "vaccine_sentiment_anon.jsonl")
collector.generate_metadata("vaccine sentiment", len(clean_data))

Data Storage Best Practices

Once you have your dataset, proper storage is critical:

File Formats

JSON Lines (.jsonl) — One record per line, easy to stream and process
Parquet — Columnar format, excellent for large datasets and analytics
CSV — Universal compatibility, but watch out for tweet text containing commas and newlines

Storage Security

Use your institution's encrypted research data storage
Enable access logging so you know who accessed the data and when
Separate raw data (with usernames) from anonymized analysis datasets
Keep the anonymization key (username → anon_id mapping) in a separate, restricted location

Version Control

Track dataset versions with checksums
Document any filtering, cleaning, or transformation applied
Keep a changelog — "v2: removed 342 deleted tweets after rehydration check"

Reproducibility

Record your exact API parameters, date ranges, and query terms
Save your collection scripts alongside the data
Include a README with schema documentation and known limitations

Common Pitfalls

A few things that trip up first-time Twitter researchers:

1. Survivorship bias — Deleted tweets disappear from the API. Your dataset only contains tweets that still exist at collection time.
1. Rate limit confusion — API rate limits reset on fixed windows, not rolling. Plan your collection schedule accordingly.
1. Bot contamination — Depending on your topic, 10–40% of tweets may come from automated accounts. Have a bot detection strategy.
1. Sampling bias — Keyword search finds tweets containing your terms, but misses relevant tweets using different vocabulary. Consider multiple query strategies.
1. Temporal artifacts — Twitter's algorithm changes affect what content is visible. A search in January may return different results than the same search in March.
1. Quote tweet context — A tweet saying "This is insane" means very different things depending on what it's quoting. Always collect the quoted tweet context.

Getting Started

For researchers needing cost-effective access to Twitter data, XCROP's Basic plan starts at $4.9/month with 700K credits — enough for most pilot studies. The search endpoint supports complex queries, and batch endpoints let you look up 100 tweets or users in a single call, making it practical to build research datasets without burning through a grant budget.

The most important step is starting small: define your research question, estimate your data needs, run a pilot collection, and scale up once you've validated your methodology.