By Sorsa Editorial

Published April 6, 2026. Updated September 23, 2026: added a no-code browser route, a script that saves every photo and video from a profile, resumable CSV, Excel, and JSON exports, and the official full-archive search option. Official X API rates verified September 2026.

Key Takeaway: You can download all tweets from a public X account in five ways: your own X archive (your account only), no-code export tools, open-source scrapers, the official X API, or a data API. The official timeline stops at the latest 3,200 posts, so a paginated data API is the practical route to a complete history.

The last route is also the cheapest at scale. Sorsa API, a read-only Twitter/X data API, pages through any public account's full timeline with no 3,200-post ceiling and returns each post with its author, engagement counts, and direct photo and video links as JSON. Billing is one request per page of about 20 posts, which works out to about $0.10 per 1,000 tweets on the Pro plan, so a 50,000-post account uses about $5 of plan quota. 100 free requests, no card and no expiry, cover the most recent 2,000 or so posts of any account, and you can run them from the browser without writing code.

Contents

How to download all tweets from a user: 5 ways compared

MethodWhose tweetsHow manyCostEffort
1. Your X archiveYour own account onlyAll of them, plus media and DMsFreeA few days' wait
2. No-code export toolsAny public accountDepends on the tool and planVaries by toolLow
3. Open-source scrapersAny public accountVaries, breaks oftenFree code, needs your X accountsHigh
4. Official X APIAny public accountTimeline: latest 3,200; full-archive search: more$5 per 1,000 posts, developer accountMedium
5. Data API (Sorsa)Any public accountFull history, no 3,200 ceilingAbout $0.10 per 1,000 posts; 100 free requestsLow: browser or one API key

Which one fits comes down to three questions:

  • Is it your own account? Request your X archive. It is free and complete.
  • Is it someone else's account? The archive cannot help. For a few hundred recent posts, any method works; for a full history, use a data API.
  • Do you need it once or on a schedule? For recurring pulls, multiple accounts, or anything feeding a spreadsheet, dashboard, or model, an API key is the route that scales.

Method 1: Download your own X archive

X lets you download a complete archive of your own account for free: every post, your media, DMs, followers, following, and lists. In X's settings, open Your account, choose Download an archive of your data, verify your identity, and request it. X's help page notes it may take a few days to prepare, and the download arrives as a ZIP with an HTML viewer and data files.

The limit is ownership: there is no way to request another person's archive. The data files also hold JSON wrapped in JavaScript, which needs a small conversion before a spreadsheet can read it.

Best for: backing up your own account, keeping a record before deactivating, and personal analysis.

Method 2: Use a no-code export tool

Browser tools and extensions export a handle's tweets to a CSV or Excel file, with text, dates, and engagement counts. They are the quickest route for a non-technical user who needs a snapshot of recent posts.

Limits vary by tool and plan, so check how far back an export reaches before you pay, especially for prolific accounts. For a no-code route that also reaches older posts, the Sorsa playground in Method 5 exports up to 1,000 recent posts per run and pulls older periods with date-range searches.

Best for: one-off exports of recent posts and quick competitive snapshots.

Method 3: Run an open-source scraper

Open-source libraries call X's internal web endpoints from your own code. They are free, but in 2026 most of the well-known names are gone: snscrape and Twint stopped working years ago, Nitter went offline after X's cease-and-desist letters in 2026, and twikit's latest release has been reported broken since March 2026. twscrape still works, but it needs your own logged-in X accounts, which carry the risk if X restricts them. The full status check is in the guide to Twitter APIs without a developer account.

Best for: experiments with no deadline, by developers comfortable fixing breakage.

Method 4: Use the official X API

The official API offers two ways to read a user's posts, and both need a developer account with prepaid credits:

  • The user timeline endpoint returns only an account's most recent 3,200 posts, a documented cap in X's timelines documentation.
  • Full-archive search with a from:username query reaches back to 2006 and is open to self-serve developers, as X's full-archive search guide notes, at one request per second.

Both bill per post at $0.005, so a 50,000-post history costs $250 in reads, and pay-per-use accounts are capped at 3 million post reads per billing cycle. You authenticate with OAuth credentials from a developer app. Every official rate is in the X API pricing breakdown.

Best for: teams already on the official API that also need to post, and small pulls where $5 per 1,000 posts is acceptable.

Method 5: Use a data API with no 3,200-tweet cap

A third-party data API returns public posts as JSON through documented endpoints. With Sorsa, the /user-tweets endpoint pages back through an account's entire timeline with no 3,200-post ceiling, about 20 posts per request, and each post arrives with its author profile, engagement counts, and direct media links at no extra cost. Replies are optional: set with_replies to include them. You authenticate with one ApiKey header, and you don't need an X account or an X developer account to get a key.

There are two ways to use it:

  • No code. The API playground runs the same calls in the browser: paste your key, pick User Tweets for up to 1,000 recent posts per run, or Search Tweets with from:username and a date range for older periods, and export the result as CSV or JSON. Each page counts as one request.
  • With code. The script in the next section downloads a full timeline of any size and can resume where it stopped.

Best for: someone else's account, full histories, multiple accounts, recurring pulls, and anything that feeds a spreadsheet, dashboard, or model.

How to download all tweets with code, step by step

You need an API key (100 free requests, no card), Python 3.8 or later with requests, or Node.js 18 or later (save the script as an .mjs file), and the target username.

The /user-tweets endpoint returns about 20 posts per page. Keep sending the next_cursor from each response until it comes back empty, which means you have reached the account's first post. Writing each page to a JSON Lines file as it arrives means a crash or a lost connection costs little: pass the last printed cursor back in to resume, and deduplicate by post ID in case one page repeats.

python
import json
import os
import time

import requests

API = "https://api.sorsa.io/v3"
HEADERS = {"ApiKey": os.environ["SORSA_API_KEY"]}

def download_all_tweets(username, out_path, with_replies=False, cursor=None):
    """Page through a user's full timeline, appending every post to a JSON Lines file."""
    saved = 0
    with open(out_path, "a", encoding="utf-8") as out:
        while True:
            body = {"username": username, "with_replies": with_replies}
            if cursor:
                body["next_cursor"] = cursor
            r = requests.post(f"{API}/user-tweets", headers=HEADERS, json=body, timeout=30)
            if r.status_code == 429:  # more than 20 requests in the current second
                time.sleep(1)
                continue
            r.raise_for_status()
            page = r.json()
            for tweet in page.get("tweets", []):
                out.write(json.dumps(tweet, ensure_ascii=False) + "\n")
            out.flush()  # the page is on disk before its cursor is printed
            saved += len(page.get("tweets", []))
            cursor = page.get("next_cursor")
            print(f"{saved} posts saved, resume cursor: {cursor}")
            if not cursor:
                return saved  # reached the first post

download_all_tweets("stripe", "stripe_tweets.jsonl")

The same loop in Node.js:

javascript
// Save as download.mjs and run: node download.mjs
import { appendFileSync } from "node:fs";

const API = "https://api.sorsa.io/v3";

async function downloadAllTweets(username, outPath, cursor = null) {
  let saved = 0;
  while (true) {
    const body = { username, with_replies: false };
    if (cursor) body.next_cursor = cursor;
    const res = await fetch(`${API}/user-tweets`, {
      method: "POST",
      headers: { ApiKey: process.env.SORSA_API_KEY, "Content-Type": "application/json" },
      body: JSON.stringify(body),
    });
    if (res.status === 429) {
      await new Promise((r) => setTimeout(r, 1000));
      continue;
    }
    if (!res.ok) throw new Error(`HTTP ${res.status}`);
    const page = await res.json();
    for (const t of page.tweets ?? []) appendFileSync(outPath, JSON.stringify(t) + "\n");
    saved += page.tweets?.length ?? 0;
    cursor = page.next_cursor;
    console.log(`${saved} posts saved, resume cursor: ${cursor}`);
    if (!cursor) return saved;
  }
}

await downloadAllTweets("stripe", "stripe_tweets.jsonl");

Every post in the file carries full_text, created_at, lang, likes, reposts, replies, quotes, views, bookmarks, the full author profile under user, and an entities array with photo, video, and link URLs. For a slice instead of the whole timeline, use search with the from: operator and filters. This pulls only well-performing original posts from 2025:

python
# Continues from the script above (same API and HEADERS)
r = requests.post(
    f"{API}/search-tweets",
    headers=HEADERS,
    json={"query": "from:stripe min_faves:50 -filter:replies since:2025-01-01 until:2026-01-01", "order": "latest"},
    timeout=30,
)

Search combines from: with engagement filters (min_faves:, min_retweets:), media filters (filter:media, filter:images), language (lang:en), and dates (since:, until:). The Twitter search operators cheat sheet lists them all, and the search query builder writes the query for you. More Python patterns are in the Twitter API Python guide, and the Node.js version is in the Twitter API Node.js guide.

How to export tweets to CSV, Excel, or JSON

The JSON Lines file already is a lossless JSON export. For spreadsheets, flatten each post into one row first; nested fields such as user and entities do not fit in a cell as they are:

python
import csv
import json

import pandas as pd

def flatten(t):
    """One spreadsheet row per post."""
    media = [e["link"] for e in t.get("entities", []) if e.get("type") in ("photo", "video", "animated_gif")]
    return {
        "id": t["id"],
        "created_at": t["created_at"],
        "text": t["full_text"],
        "lang": t.get("lang"),
        "likes": t.get("likes_count"),
        "reposts": t.get("retweet_count"),
        "replies": t.get("reply_count"),
        "quotes": t.get("quote_count"),
        "views": t.get("view_count"),
        "bookmarks": t.get("bookmark_count"),
        "is_reply": t.get("is_reply"),
        "is_quote": t.get("is_quote_status"),
        "media": " ".join(media),
        "url": f"https://x.com/{t['user']['username']}/status/{t['id']}",
    }

with open("stripe_tweets.jsonl", encoding="utf-8") as f:
    rows = [flatten(json.loads(line)) for line in f if line.strip()]

# CSV: utf-8-sig keeps emoji and non-Latin text intact when opened in Excel.
# Excel shortens 19-digit IDs in CSV files; the url column keeps the exact ID.
with open("stripe_tweets.csv", "w", newline="", encoding="utf-8-sig") as f:
    writer = csv.DictWriter(f, fieldnames=list(rows[0]))
    writer.writeheader()
    writer.writerows(rows)

# Excel (needs openpyxl)
pd.DataFrame(rows).to_excel("stripe_tweets.xlsx", index=False)

CSV is the most portable choice and opens in Excel, Google Sheets, pandas, and R. Keep the JSON Lines file when you need the full structure, such as quoted posts, author details, or every media variant. To send exports to a live spreadsheet on a schedule, see how to export Twitter data to Google Sheets.

How to download all media from a Twitter (X) account

To download all media from a Twitter/X profile, the photos, videos, and GIFs the account has posted, search for its media posts only and save the files from each post's entities. Photo links point to the original upload rather than the compressed preview, and video links are direct MP4 files:

python
import os
from urllib.parse import parse_qs, urlparse

import requests

API = "https://api.sorsa.io/v3"
HEADERS = {"ApiKey": os.environ["SORSA_API_KEY"]}
MEDIA_TYPES = ("photo", "video", "animated_gif")

def file_ext(url):
    parsed = urlparse(url)
    ext = os.path.splitext(parsed.path)[1]
    return ext or "." + parse_qs(parsed.query).get("format", ["jpg"])[0]

def download_profile_media(username, folder, max_pages=None):
    """Save every photo, video, and GIF from an account's media posts."""
    os.makedirs(folder, exist_ok=True)
    cursor, saved, pages = None, 0, 0
    while True:
        body = {"query": f"from:{username} filter:media", "order": "latest"}
        if cursor:
            body["next_cursor"] = cursor
        r = requests.post(f"{API}/search-tweets", headers=HEADERS, json=body, timeout=30)
        r.raise_for_status()
        page = r.json()
        pages += 1
        for t in page.get("tweets", []):
            for i, e in enumerate(t.get("entities", [])):
                if e.get("type") not in MEDIA_TYPES:
                    continue
                path = os.path.join(folder, f"{t['id']}_{i}{file_ext(e['link'])}")
                with requests.get(e["link"], stream=True, timeout=60) as media:
                    media.raise_for_status()
                    with open(path, "wb") as f:
                        for chunk in media.iter_content(1 << 16):
                            f.write(chunk)
                saved += 1
        cursor = page.get("next_cursor")
        if not cursor or (max_pages and pages >= max_pages):
            return saved

print(download_profile_media("nasa", "nasa_media"), "files saved")

Each search page is one API request; the file downloads themselves are ordinary HTTP requests and do not count against your quota. Pass max_pages to cap a very large account. For a single post, the media downloader returns the MP4 or full-resolution image from a post link in the browser, and the guide to downloading Twitter media via API covers video variants and image quality in depth.

How to get more than 3,200 tweets from a user

The 3,200 ceiling belongs to the official user timeline endpoint. Several routes go past it:

MethodPosts per accountNotes
Your X archiveAllOwn account only, free, a few days' wait
No-code export toolsDepends on tool and planCheck how far back an export reaches
Open-source scrapersVariesBreak when X changes; need logged-in accounts
Official X API, user timelineLatest 3,200Documented cap
Official X API, full-archive searchBack to 2006$5 per 1,000 posts, one request per second
Sorsa /user-tweetsFull timelinePage with next_cursor, about $0.10 per 1,000 posts on Pro
Sorsa /search-tweets with from:Full historyDate windows and filters

A cursor walks a timeline one page at a time, so a very large account takes a while in a single loop. To speed it up, split the history into date windows (from:username since:2024-01-01 until:2025-01-01, and so on) and run the windows in parallel, staying under 20 requests per second in total. Date-window search also recovers older periods precisely, as the guide to historical Twitter data shows.

How to see all tweets from a user on X

If you only want to read an account's history rather than download it, X's own search does the job. Type from:username in the X search box, open the Latest tab, and add dates to jump to a period, for example from:nasa since:2019-01-01 until:2019-02-01. Scrolling a profile page shows recent posts but stops well short of a long history, while a date-bounded search goes straight to the month you need. The guide to searching Twitter by date covers every date operator. When you need the results in a file, run the same query through the playground or the API.

How much does it cost to download a full timeline?

Through a flat per-request API, a full timeline costs about $0.10 per 1,000 posts on the Pro plan (about $0.25 on Starter), because one request returns a page of about 20 posts. The official X API bills $0.005 per post, $5 per 1,000, which makes the data API up to 50x cheaper for this job:

Account sizeRequestsSorsa (Pro plan quota)Official X API, full-archive search
1,000 posts50About $0.10$5
10,000 posts500About $1$50
50,000 posts2,500About $5$250
100,000 posts5,000About $10$500

Pages can come back partly filled, so treat these as best-case figures. The 100 free requests cover about 2,000 posts, enough to test any account before paying. The smallest plan, Starter at $49 a month, includes 10,000 requests, room for roughly 200,000 posts. To price a mix of timelines, profiles, and follower lists, use the X API cost calculator.

Worked example: archiving a 60,000-post account

A discourse study needs the complete history of a public figure with about 60,000 posts. An export capped at recent posts leaves a multi-year gap, and the official user timeline endpoint stops at 3,200. Official full-archive search could cover it, at 60,000 posts times $0.005, or $300.

Through /user-tweets, the same history is about 3,000 requests: roughly $6 of Pro plan quota, or about 30% of a Starter month. The first 100 requests are free, so the most recent 2,000 posts arrive before any payment, and the JSON Lines file flattens into the CSV the study's model reads.

FAQ

Can you download all tweets from someone else's account?

Yes, if the account is public. X's archive only covers your own account, so for anyone else you need a tool or an API. A data API such as Sorsa pages through the full public timeline with no 3,200-post cap using a short script, its browser playground exports up to 1,000 recent posts per run, and the first 100 requests, about 2,000 posts, are free. Use the data in line with privacy rules and any terms that apply to you.

How do you download all of your own tweets?

Request your X archive. In X's settings, open Your account, choose Download an archive of your data, verify your identity, and request it. X says the archive may take a few days to prepare. It includes every post, your media, DMs, followers, and following as a ZIP file with an HTML viewer and data files.

Is there a free way to download all tweets from a user?

For your own account, the X archive is free and complete. For someone else's, Sorsa's 100 free requests, with no card and no expiry, download about 2,000 posts of any public account, which covers many smaller accounts in full. Open-source libraries are free but need your own logged-in X accounts. The official X API no longer includes free reads for new developers.

How do you get more than 3,200 tweets from a user?

Avoid the official user timeline endpoint, which stops at the latest 3,200 posts. The official full-archive search can reach older posts at $0.005 each. A data API such as Sorsa pages through the complete timeline with no cap, at about $0.10 per 1,000 posts on the Pro plan, and date-window search with since: and until: recovers any specific period.

Can you download tweets from a private (protected) account?

No. Protected accounts share posts only with approved followers, and public data tools, including Sorsa, return public posts only. If you own the protected account, request your X archive, which includes all of your posts.

How do you download all photos and videos from an X profile?

Search the account's media posts with the query from:username filter:media and save the files from each post's entities, where photo links point to the original upload and video and GIF links are direct MP4 files. Search pages count as API requests, and the file downloads do not. For a single post, a media downloader tool returns the files from the post link.

What format is best: CSV, Excel, or JSON?

CSV is the most portable and opens in Excel, Google Sheets, pandas, and R. JSON, or JSON Lines with one post per line, keeps the full structure, including author profiles, quoted posts, and media, which suits pipelines and databases. Excel is convenient for sharing with non-technical colleagues. A common setup is to save JSON Lines and flatten it to CSV or Excel when needed.

How do you download tweets with specific keywords or hashtags?

Use search instead of the timeline. Combine from:username with the keyword or hashtag, for example from:stripe #payments since:2025-01-01, and add filters such as min_faves: or filter:media to narrow it further. Each search page returns about 20 matching posts and counts as one request.

How long does it take to download a full timeline?

It depends on the account's size and response times, because a cursor pages through a timeline one request at a time. A few thousand posts take minutes. For accounts with tens of thousands of posts, split the history into yearly date windows and run the searches in parallel, staying under the 20 requests per second limit.

Can an AI agent download a user's tweets?

Yes. An agent can call the same user-tweets and search endpoints over plain HTTP, or connect through Sorsa's MCP server so an assistant can fetch a user's posts or search their history on request. Each call costs one request from the same quota, and the 100 free requests are enough to test an agent workflow end to end.

Getting started

Start in the browser: get an API key, open the playground, pick User Tweets, and export an account's recent posts to CSV in a couple of minutes. The 100 free requests are one-time, need no card, and never expire, which covers the most recent 2,000 or so posts of any public account. When you need a full history, run the script above with the same key.

When you are ready to scale, the flat per-request pricing plans cost about $0.10 per 1,000 posts through timelines on the Pro plan and from $0.02 per 1,000 tweets through batch endpoints, with 20 requests per second on every plan. If an AI assistant should do the downloading, connect it through the Sorsa MCP server.

Reviewed by Keksich, founder of Sorsa, marketer and X API researcher.

This guide draws on our team's hands-on work running the live Sorsa API since 2022 and testing all five methods. The 3,200-post timeline cap and full-archive search access were checked on September 23, 2026 against X's developer documentation, the official pay-per-use rates and 3 million post-read cap against X's pricing page, and the archive steps against X's Help Center. Endpoint behavior, pagination, and media fields come from the Sorsa API v3 documentation, and the code samples were tested against mocked API responses. Sorsa is an independent service and is not affiliated with or endorsed by X Corp. Verified September 2026.