How to Collect Donald Trump X Posts with Advanced Search
If you are tracking a public figure on X, the hard part is rarely the first request. The real work is keeping the query reproducible, paging through results without losing your place, and storing enough context that someone else can audit the dataset later.
This guide uses TwexAPI's Advanced Twitter Search by Page endpoint to collect public posts from @realDonaldTrump. The same pattern works for other public accounts: start with a precise advanced search query, request the first page, keep the returned next_cursor, and repeat until has_next_page is false or your collection window is complete.
When to Use This Workflow
Use the paginated Advanced Search endpoint when you need a repeatable pull of public X posts that match an advanced search expression. For a Trump monitoring or research workflow, that usually means:
- Collecting posts from
from:realDonaldTrumpfor a defined date range. - Narrowing the dataset with topic terms such as
economy,election, ortrade. - Excluding retweets with
-filter:retweetswhen you only want original posts and quoted commentary. - Saving raw API responses before running summaries, sentiment analysis, or dashboards.
Avoid treating a single page as a complete archive. Each page returns the current slice of results and pagination metadata, so the dataset is only complete after you continue with the cursor chain you intend to cover.
Endpoint and Payload
Send a POST request to:
https://api.twexapi.io/twitter/advanced_search/pageThe request body has three fields:
| Field | Required | How to use it |
|---|---|---|
searchTerms | Yes | An array of advanced search query strings. For this workflow, start with from:realDonaldTrump -filter:retweets. |
sortBy | Yes | Use Latest for reverse chronological collection, or Top when you intentionally want ranked results. |
next_cursor | No | Leave it empty on the first request. Pass the previous response's next_cursor to fetch the next page. |
The response includes data, has_next_page, and next_cursor. Store all three with your export metadata.
First Page Request
Start with a narrow query and sortBy: "Latest". This makes the collection easier to reason about because each next page continues from the latest result set.
curl --request POST \
--url https://api.twexapi.io/twitter/advanced_search/page \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '{
"searchTerms": [
"from:realDonaldTrump -filter:retweets"
],
"sortBy": "Latest"
}'A shortened response looks like this:
1{
2 "code": 200,
3 "msg": "success",
4 "data": [
5 {
6 "tweet_id": "1234567890123456789",
7 "created_at": "Mon Jul 01 12:34:56 +0000 2025",
8 "text": "<post text returned by the API>",
9 "favorite_count": 1000,
10 "retweet_count": 200
11 }
12 ],
13 "has_next_page": true,
14 "next_cursor": "cursor_from_this_response"
15}Continue with next_cursor
When has_next_page is true, send another request with the cursor from the previous response.
curl --request POST \
--url https://api.twexapi.io/twitter/advanced_search/page \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '{
"searchTerms": [
"from:realDonaldTrump -filter:retweets"
],
"sortBy": "Latest",
"next_cursor": "cursor_from_this_response"
}'Do not invent cursors or reuse one from a different query. A cursor belongs to the query and sort mode that produced it.
Python Export Script
The script below writes one raw JSON object per tweet to a JSONL file, deduplicates by tweet_id, and records the cursor flow in a small sidecar metadata file.
1import json
2import time
3from datetime import datetime, timezone
4from pathlib import Path
5
6import requests
7
8TOKEN = "<your_bearer_token>"
9URL = "https://api.twexapi.io/twitter/advanced_search/page"
10QUERY = "from:realDonaldTrump -filter:retweets"
11SORT_BY = "Latest"
12OUT = Path("realDonaldTrump-posts.jsonl")
13META = Path("realDonaldTrump-posts-meta.json")
14
15headers = {
16 "Authorization": f"Bearer {TOKEN}",
17 "Content-Type": "application/json",
18}
19
20seen_ids = set()
21cursor = None
22page = 0
23cursor_log = []
24
25with OUT.open("w", encoding="utf-8") as f:
26 while True:
27 payload = {
28 "searchTerms": [QUERY],
29 "sortBy": SORT_BY,
30 }
31 if cursor:
32 payload["next_cursor"] = cursor
33
34 response = requests.post(URL, headers=headers, json=payload, timeout=30)
35 response.raise_for_status()
36 body = response.json()
37
38 page += 1
39 items = body.get("data") or []
40 for item in items:
41 tweet_id = item.get("tweet_id")
42 if not tweet_id or tweet_id in seen_ids:
43 continue
44 seen_ids.add(tweet_id)
45 f.write(json.dumps(item, ensure_ascii=False) + "\n")
46
47 cursor_log.append({
48 "page": page,
49 "items": len(items),
50 "next_cursor": body.get("next_cursor"),
51 "has_next_page": body.get("has_next_page"),
52 })
53
54 if not body.get("has_next_page") or not body.get("next_cursor"):
55 break
56
57 cursor = body["next_cursor"]
58 time.sleep(1)
59
60META.write_text(json.dumps({
61 "query": QUERY,
62 "sortBy": SORT_BY,
63 "exported_at": datetime.now(timezone.utc).isoformat(),
64 "unique_tweets": len(seen_ids),
65 "pages": cursor_log,
66}, ensure_ascii=False, indent=2), encoding="utf-8")
67
68print(f"Saved {len(seen_ids)} unique posts to {OUT}")For long-running jobs, add retry handling for temporary network failures and persist the last successful cursor before each next request. That lets you resume without starting from page one.
Query Recipes
Start simple, then add one filter at a time. It is easier to debug a query when you know which term changed the result set.
| Goal | searchTerms value |
|---|---|
| Latest public posts from the account | from:realDonaldTrump -filter:retweets |
| Posts that mention the economy | from:realDonaldTrump economy -filter:retweets |
| A fixed monthly window | from:realDonaldTrump since:2024-01-01 until:2024-02-01 -filter:retweets |
| Posts with media | from:realDonaldTrump filter:media -filter:retweets |
| Posts about voting language | from:realDonaldTrump (vote OR voting OR ballot) -filter:retweets |
If you plan to compare topics, run each query separately and store the query string with every result. Mixing many topics into one query can make downstream analysis harder to explain.
What to Store
At minimum, keep:
- The raw tweet object returned by the API.
tweet_id,created_at, text fields, author fields, and engagement counts if present.- The exact
searchTerms,sortBy, export time, and cursor chain. - A normalized post URL such as
https://x.com/realDonaldTrump/status/<tweet_id>.
For analysis, avoid relying only on engagement counts captured at one moment. Those numbers can change over time, so timestamp each export and decide whether later refreshes should overwrite or append a new snapshot.
Common Pitfalls
- Changing
searchTermsin the middle of pagination invalidates the meaning of the cursor chain. - Using
Topfor historical export can reorder results in ways that are harder to audit. UseLatestunless ranking is the point of the analysis. - Dropping raw responses too early makes it difficult to reproduce field mappings later.
- Treating a public figure's posts as a neutral dataset can hide context. Store dates, query terms, and any filtering decisions next to the data.
Wrap-up
For Trump post collection, the cleanest TwexAPI workflow is: write a precise advanced search query, call POST /twitter/advanced_search/page, keep paging with next_cursor, and save both raw results and metadata. That gives analysts a dataset that is easier to rerun, inspect, and explain.
Use the first export as a baseline, then decide whether your product needs scheduled refreshes, topic-specific datasets, or alerting on newly returned posts.