How to Parse Trump Truth Social Posts (Python & Node.js Guide 2025)
Understanding Truth Social's API Architecture
Truth Social was built on the open-source Mastodon codebase, and while the platform does not advertise a public API, it retained significant portions of the Mastodon API structure. This creates an accessible — if unofficial — interface that developers have been using since the platform launched in 2022. The primary endpoint for public posts is structured similarly to Mastodon's /api/v1/accounts/{id}/statuses route, where Trump's account ID resolves to a fixed numeric identifier.
As of 2025, the base URL for Truth Social's API is https://truthsocial.com. Account lookup uses the /api/v1/accounts/lookup endpoint, which accepts an acct parameter (e.g., realDonaldTrump) and returns an account object including the numeric ID required for subsequent status requests. Once you have the account ID, you can paginate through posts using /api/v1/accounts/{id}/statuses?limit=40.
Authentication is optional for reading public posts, but unauthenticated requests carry stricter rate limits. Creating an application registration via /api/v1/apps and obtaining an OAuth bearer token raises your rate limit ceiling considerably and adds access to user-specific features. For monitoring purposes, a read-only application registration is sufficient and requires no user login.
One important architectural detail: Truth Social serves its API through a CDN layer that caches responses for 2–10 seconds depending on the endpoint. This means polling faster than once every 2–3 seconds yields no additional freshness and wastes rate limit budget. The optimal polling interval for a monitoring script is 2–3 seconds, which balances freshness against API courtesy and avoids triggering abuse detection.
The JSON response format closely follows Mastodon's schema. Each status object contains an id field (a large integer string), a content field (HTML-formatted text), a created_at ISO 8601 timestamp, a reblog field (null for original posts), and a media_attachments array. Stripping HTML from the content field with a parser like BeautifulSoup (Python) or Cheerio (Node.js) yields clean plain text suitable for NLP processing.
Python Implementation with requests and BeautifulSoup
The Python implementation below demonstrates a complete polling loop that fetches new Trump posts, strips HTML, and inserts them into a SQLite database. It uses the requests library for HTTP and bs4 (BeautifulSoup) for HTML parsing. Install dependencies with pip install requests beautifulsoup4 before running.
import requests
import sqlite3
import time
from bs4 import BeautifulSoup
from datetime import datetime
BASE_URL = "https://truthsocial.com"
HEADERS = {"User-Agent": "TrumpMonitor/1.0 (research; contact@example.com)"}
def get_account_id(username: str) -> str:
resp = requests.get(
f"{BASE_URL}/api/v1/accounts/lookup",
params={"acct": username},
headers=HEADERS,
timeout=10
)
resp.raise_for_status()
return resp.json()["id"]
def fetch_posts(account_id: str, since_id: str = None, limit: int = 40):
params = {"limit": limit}
if since_id:
params["since_id"] = since_id
resp = requests.get(
f"{BASE_URL}/api/v1/accounts/{account_id}/statuses",
params=params,
headers=HEADERS,
timeout=10
)
if resp.status_code == 429:
print("Rate limited — sleeping 30 seconds")
time.sleep(30)
return []
resp.raise_for_status()
return resp.json()
def strip_html(html_text: str) -> str:
return BeautifulSoup(html_text, "html.parser").get_text()
def init_db(conn):
conn.execute("""
CREATE TABLE IF NOT EXISTS posts (
post_id TEXT PRIMARY KEY,
content TEXT,
created_at TEXT,
fetched_at TEXT
)
""")
conn.commit()
def save_posts(conn, posts):
for post in posts:
if post.get("reblog"):
continue # skip reposts
conn.execute(
"INSERT OR IGNORE INTO posts VALUES (?,?,?,?)",
(
post["id"],
strip_html(post["content"]),
post["created_at"],
datetime.utcnow().isoformat()
)
)
conn.commit()
def monitor(username="realDonaldTrump", db_path="trump_posts.db", interval=3):
conn = sqlite3.connect(db_path)
init_db(conn)
account_id = get_account_id(username)
print(f"Monitoring {username} (ID: {account_id})")
latest_id = None
while True:
try:
posts = fetch_posts(account_id, since_id=latest_id)
if posts:
latest_id = posts[0]["id"]
save_posts(conn, posts)
print(f"[{datetime.utcnow()}] {len(posts)} new post(s)")
except Exception as e:
print(f"Error: {e}")
time.sleep(interval)
if __name__ == "__main__":
monitor()
Node.js Implementation with Axios
For teams already running Node.js infrastructure — common in fintech and web development contexts — the equivalent implementation uses axios for HTTP requests and better-sqlite3 for synchronous SQLite operations. Install with npm install axios better-sqlite3.
const axios = require("axios");
const Database = require("better-sqlite3");
const { JSDOM } = require("jsdom"); // npm install jsdom
const BASE_URL = "https://truthsocial.com";
const HEADERS = { "User-Agent": "TrumpMonitor/1.0 (research)" };
function stripHtml(html) {
return new JSDOM(html).window.document.body.textContent || "";
}
async function getAccountId(username) {
const res = await axios.get(`${BASE_URL}/api/v1/accounts/lookup`, {
params: { acct: username }, headers: HEADERS
});
return res.data.id;
}
async function fetchPosts(accountId, sinceId = null) {
const params = { limit: 40 };
if (sinceId) params.since_id = sinceId;
try {
const res = await axios.get(
`${BASE_URL}/api/v1/accounts/${accountId}/statuses`,
{ params, headers: HEADERS }
);
return res.data;
} catch (err) {
if (err.response?.status === 429) {
console.log("Rate limited — waiting 30s");
await new Promise(r => setTimeout(r, 30000));
}
return [];
}
}
function initDb(db) {
db.exec(`CREATE TABLE IF NOT EXISTS posts (
post_id TEXT PRIMARY KEY,
content TEXT,
created_at TEXT,
fetched_at TEXT
)`);
}
async function monitor(username = "realDonaldTrump", interval = 3000) {
const db = new Database("trump_posts.db");
initDb(db);
const insert = db.prepare(
"INSERT OR IGNORE INTO posts VALUES (?,?,?,?)"
);
const accountId = await getAccountId(username);
console.log(`Monitoring ${username} (${accountId})`);
let latestId = null;
setInterval(async () => {
const posts = await fetchPosts(accountId, latestId);
if (posts.length) {
latestId = posts[0].id;
posts.filter(p => !p.reblog).forEach(p => {
insert.run(p.id, stripHtml(p.content), p.created_at,
new Date().toISOString());
});
console.log(`${new Date().toISOString()} — ${posts.length} post(s)`);
}
}, interval);
}
monitor();
Rate Limits, Storage, and Scaling
Rate limit management is the most critical operational concern when scraping Truth Social. The platform enforces limits at the IP level, so running multiple instances from the same IP multiplies your request rate and triggers blocks faster. For serious monitoring operations, route requests through a pool of residential proxy IPs, cycling between them on each request. Commercial proxy providers offer rotating IP pools specifically optimized for social media scraping.
SQLite is adequate for single-process monitoring scripts, but once you need to query post history at scale or serve the data to multiple consumers, consider migrating to PostgreSQL. The schema above maps directly to a PostgreSQL table; just change the INSERT OR IGNORE syntax to INSERT ... ON CONFLICT DO NOTHING. Add a GIN index on the content column for full-text search capabilities.
For teams that need a managed solution without building and maintaining scraping infrastructure, TrumpBot's API at trumpbot.online/api provides authenticated REST access to a continuously updated post database. Endpoints include /posts/latest for the most recent 100 posts, /posts/search?q=tariff for keyword search, and /posts/since/{timestamp} for incremental fetching. The API handles rate limits, deduplication, HTML stripping, and NLP enrichment server-side, reducing client-side complexity to a single HTTP call.
Setting Up Webhooks for Real-Time Delivery
Rather than polling on a schedule, webhooks allow Truth Social monitoring systems to push data to your application the moment a new post is detected. TrumpBot's webhook system is the simplest path: register your endpoint URL via the API dashboard and specify filter criteria. When a matching post appears, TrumpBot sends an HTTP POST to your URL within 3–8 seconds, containing a JSON payload with the post content, metadata, and market-relevance score.
Building your own webhook push layer on top of the scraping code above requires a small addition: after saving new posts to the database, iterate through them and call your downstream endpoints using requests.post() (Python) or axios.post() (Node.js). Include retry logic with exponential backoff for endpoints that return 5xx errors. A simple in-memory queue using Python's queue.Queue or Node.js's bull library prevents post loss if your endpoint is temporarily unreachable.
For trading system integrations, the webhook payload should be enriched before forwarding. Basic enrichment includes: keyword extraction (does the post mention specific tickers or sectors?), sentiment scoring (positive/negative/neutral toward a particular asset?), and urgency classification (is this a casual comment or a policy announcement?). The TrumpBot Pro API delivers all of these fields pre-computed, saving significant NLP infrastructure costs for teams that do not want to run their own models.
| Method | Avg Latency | Setup Time | Reliability | Rate Limit Risk | Cost | Best For |
|---|---|---|---|---|---|---|
| Mastodon-compat API (DIY) | 3–10 sec | 2–4 hours | Medium | High | Free + proxy costs | Developers, researchers |
| TrumpBot REST API | 3–8 sec | 15 min | Very High | None | Free / $9 Pro | Teams, trading desks |
| TrumpBot Webhook | 3–8 sec (push) | 30 min | Very High | None | $9 Pro | Automated trading |
| Truth Social RSS feed | 60–300 sec | 5 min | Low (often breaks) | Low | Free | Casual monitoring |
| HTML scraping (Selenium) | 10–30 sec | 4–8 hours | Low (fragile) | Very High | Free + infrastructure | Last resort |
Frequently Asked Questions
Does Truth Social have an official public API?
Truth Social does not publish an official public API for third-party developers. However, the platform was built on the Mastodon open-source codebase and retained Mastodon-compatible API endpoints for public account data. These undocumented endpoints are widely used by developers for monitoring purposes.
What rate limits apply to the Truth Social API?
The Mastodon-compatible endpoints allow approximately 300 requests per 5-minute window per IP address. Exceeding this triggers HTTP 429 responses and temporary IP blocks lasting 30–60 minutes. Using residential proxy rotation mitigates this for high-frequency monitoring.
Is scraping Truth Social posts legal?
Scraping publicly available posts for research, journalism, or personal use is generally considered lawful under US case law (see hiQ Labs v. LinkedIn, 9th Circuit 2022). Commercial redistribution of scraped content or access to private accounts would raise additional legal questions. Always review the platform's Terms of Service and consult legal counsel for commercial applications.
What Python libraries are needed to scrape Truth Social?
The minimal set is requests for HTTP calls and beautifulsoup4 for stripping HTML from post content. For persistent storage, Python's built-in sqlite3 module requires no additional installation. Add schedule or APScheduler for cron-style polling loops.
How do I get Trump's account ID on Truth Social?
Make a GET request to https://truthsocial.com/api/v1/accounts/lookup?acct=realDonaldTrump. The response JSON contains an "id" field with the numeric account identifier. As of 2025 this resolves to the same stable ID and does not change.
How do I avoid duplicate posts in my database?
Use the post's "id" field as the primary key in your SQLite or PostgreSQL table and use INSERT OR IGNORE (SQLite) or INSERT ... ON CONFLICT DO NOTHING (PostgreSQL). The API also supports a since_id parameter that returns only posts newer than the specified ID, allowing you to fetch only new content on each poll cycle.
What is the difference between the Mastodon API and TrumpBot's API?
The Mastodon-compatible API is a raw data source requiring you to handle rate limits, HTML stripping, deduplication, and enrichment yourself. TrumpBot's API is a managed service that delivers pre-processed, enriched post data with NLP metadata (market relevance, keyword tags, category classification) through a stable, documented interface with no rate limit concerns for subscribers.
Can I run the scraping script on a cloud server?
Yes. The Python and Node.js scripts above run on any cloud instance. For 24/7 monitoring, use a process manager such as supervisor (Linux) or pm2 (Node.js) to restart the process automatically if it crashes. A $5/month VPS is sufficient for a single-instance monitoring setup.
How do I send scraped posts to a Telegram bot?
After parsing and saving each new post, call the Telegram Bot API sendMessage endpoint: POST https://api.telegram.org/bot{TOKEN}/sendMessage with a JSON body containing your chat_id and the post text. Create a bot via @BotFather to obtain a token. This effectively replicates what TrumpBot does internally.
Does the scraper capture images and videos from posts?
Each post's JSON includes a media_attachments array containing URLs for images and videos. You can download these files separately using the URLs provided. Note that media files are served from Truth Social's CDN and may require the original request headers to download successfully.