Truthsocial Scraper avatar

Truthsocial Scraper

Pricing

from $10.00 / 1,000 results

Go to Apify Store
Truthsocial Scraper

Truthsocial Scraper

Scrapes the latest posts truthsocial.com. By default it saves the **3 newest posts of @realDonaldTrump**; give it any other usernames or profile URLs and a different number of posts. Each post with its text, date, media, link preview, reply/ReTruth/like counts, hashtags and mentions.

Pricing

from $10.00 / 1,000 results

Rating

0.0

(0)

Developer

Tin

Tin

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

21 days ago

Last modified

Categories

Share

Scrapes the latest posts ("Truths") of public Truth Social accounts. By default it saves the 3 newest posts of @realDonaldTrump; give it any other usernames or profile URLs and a different number of posts. Each post becomes one dataset item with its text, date, media, link preview, reply/ReTruth/like counts, hashtags and mentions. Unless you choose another proxy, all requests go through Apify Proxy, RESIDENTIAL group, country US.

Truth Social is built on Mastodon, so public profiles are served by a Mastodon-compatible JSON API (/api/v1/accounts/lookup and /api/v1/accounts/{id}/statuses). The Actor reads that API instead of rendering pages in a browser, which is fast and cheap. Requests use browser-like headers and TLS fingerprints (got-scraping), because the site is protected by Cloudflare.

Input

FieldTypeDescription
usernamesarrayRequired. Usernames or profile URLs: realDonaldTrump, @realDonaldTrump, https://truthsocial.com/@realDonaldTrump (a post URL works too). Duplicates are removed; invalid entries are skipped with a warning.
maxPostsintegerNewest posts to save per account, 1 to 1000. Default 3.
excludeRepliesbooleanSkip replies to other posts. Default true, so you get the account's own top-level posts.
excludeReTruthsbooleanSkip ReTruths (re-posts). Default false.
proxyConfigurationobjectProxy for all requests. Default when not passed: { "useApifyProxy": true, "apifyProxyGroups": ["RESIDENTIAL"], "apifyProxyCountry": "US" }. See "Proxy" below.
accessTokenstringOptional, secret. Only needed if Truth Social stops serving public posts to visitors who are not logged in (see below).

Example input (the proxy can be left out: residential US is the default):

{
"usernames": ["realDonaldTrump", "https://truthsocial.com/@TeamTrump"],
"maxPosts": 3,
"excludeReplies": true,
"excludeReTruths": false
}

Proxy

Truth Social is protected by Cloudflare, which blocks most datacenter IP addresses, so the Actor defaults to Apify Proxy, RESIDENTIAL group, country US:

proxyConfiguration in the inputProxy used
Not passed, null, {} or an object that sets neither useApifyProxy nor proxyUrlsApify Proxy, RESIDENTIAL, US (the default)
{ "useApifyProxy": true, ... } with your own groups/countryExactly those Apify Proxy settings
{ "proxyUrls": ["http://user:pass@host:port"] }Your own proxies
{ "useApifyProxy": false } ("No proxy" in Apify Console)None, direct connection

The Console input form shows the default preselected. Each request uses a new proxy session (a new IP address) when the site blocks it.

  • Cost: residential proxy traffic is billed by Apify per GB, separately from the Actor's compute. The Actor only downloads JSON (one account lookup plus pages of 20 to 40 posts), so a run with the default 3 posts transfers well under 1 MB.
  • No residential access: if your Apify account cannot use the RESIDENTIAL group, the run fails at the start with a message saying so. Choose another proxy, or "No proxy", in proxyConfiguration.
  • Local runs: outside the Apify platform, Apify Proxy is only reachable when your account allows external access. If it is not reachable, the Actor logs a warning and continues without a proxy, but only when the proxy is the default; a proxy you chose yourself must work, or the run fails.
  • The run summary (OUTPUT) records the proxy in settings.proxyDetails, e.g. "Apify Proxy, group RESIDENTIAL, country US (default)". Proxy passwords are never logged or saved.

Output

One item per post, newest first per account (position 1 is the newest). The dataset's "Latest posts" view shows the main fields as a table.

{
"position": 1,
"username": "realDonaldTrump",
"displayName": "Donald J. Trump",
"accountId": "107780257626128497",
"profileUrl": "https://truthsocial.com/@realDonaldTrump",
"id": "115000000000001000",
"url": "https://truthsocial.com/@realDonaldTrump/115000000000001000",
"createdAt": "2026-09-27T03:00:00.000Z",
"text": "First paragraph of the post.\nSecond line https://example.com/article\n\nSecond paragraph #MAGA",
"contentHtml": "<p>First paragraph of the post.<br>Second line <a href=\"https://example.com/article\">...</a></p><p>Second paragraph #MAGA</p>",
"isReply": false,
"inReplyToId": null,
"isReTruth": false,
"reTruthOf": null,
"quoteOf": null,
"repliesCount": 100,
"reTruthsCount": 200,
"likesCount": 300,
"media": [
{ "type": "image", "url": "https://static-assets-1.truthsocial.com/...jpg", "previewUrl": "https://static-assets-1.truthsocial.com/...jpg", "description": null }
],
"link": { "url": "https://example.com/article", "title": "Article title", "description": "Article summary", "imageUrl": "https://example.com/a.jpg" },
"mentions": [],
"hashtags": ["MAGA"],
"language": "en",
"sensitive": false,
"spoilerText": null,
"visibility": "public",
"scrapedAt": "2026-09-27T04:13:40.736Z"
}

(The values above illustrate the format; they are not a real post.)

Notes on the fields:

  • text is the post as plain text: paragraphs separated by a blank line, links written out in full. contentHtml is the original HTML.
  • For a ReTruth (isReTruth: true), text, media, link and the counts describe the re-posted original, and reTruthOf names its author, URL, date and text. createdAt is when the account re-posted it.
  • For a quote post, quoteOf holds the quoted post (or just its id when the API gives no details).
  • likesCount is Mastodon's "favourites" count, shown as likes on Truth Social.

The run's status message summarises the result, e.g. "Saved 3 post(s) from 1 account(s)." and lists accounts that were not found or could not be scraped.

Dataset schema and views

.actor/dataset_schema.json describes every output field with its type (the fields JSON Schema above is the exact contract: all fields are always present, and fields that can be empty are null rather than missing). The Apify platform checks each saved item against this schema, and the Actor converts API values to the declared types before saving, so an unexpected value from Truth Social is stored as null instead of failing the run.

The dataset offers three views in Apify Console and the API (?view=<name>):

ViewShows
overview (Latest posts)Account, position, date, text, ReTruth flag, reply/ReTruth/like counts, URL.
engagement (Engagement)Likes, ReTruths and replies per post, plus reply and ReTruth flags.
media (Media and links)Attachments, link preview, hashtags and mentions.

Output schema and run summary

.actor/output_schema.json tells Apify Console and the API where a run's results are. The run's Output tab (and the output of a run started via API) shows these links:

OutputLink
latestPostsDataset items in the "Latest posts" view (?view=overview).
engagementDataset items in the "Engagement" view (?view=engagement).
mediaAndLinksDataset items in the "Media and links" view (?view=media).
allFieldsAll dataset items with every field.
summaryThe run summary, key-value store record OUTPUT.

At the end of every run, the Actor saves the summary as the OUTPUT record, also when the run fails:

{
"status": "SUCCEEDED",
"message": "Saved 2 post(s) from 1 account(s). Not found: @nobody. Failed: @blockedUser.",
"postsSaved": 2,
"accounts": [
{ "username": "realDonaldTrump", "status": "OK", "postsSaved": 2, "error": null },
{ "username": "nobody", "status": "NOT_FOUND", "postsSaved": 0, "error": null },
{ "username": "blockedUser", "status": "FAILED", "postsSaved": 0, "error": "truthsocial.com refused the request to /api/v1/accounts/lookup: Cloudflare bot protection (HTTP 403)." }
],
"skippedInputs": [{ "value": "bad user!", "reason": "\"bad user!\" is not a valid username (letters, digits and _ only)" }],
"settings": { "maxPosts": 2, "excludeReplies": true, "excludeReTruths": false, "proxy": true, "proxyDetails": "Apify Proxy, group RESIDENTIAL, country US (default)", "accessToken": false },
"startedAt": "2026-09-27T04:50:00.000Z",
"finishedAt": "2026-09-27T04:50:03.000Z"
}

status is SUCCEEDED or FAILED; accounts[].status is OK, NOT_FOUND or FAILED. settings.proxy says whether a proxy was used and settings.proxyDetails which one. settings.accessToken only says whether a token was given; the token itself is never saved. When the input is invalid or the proxy cannot be set up, settings is null and message explains the problem.

Memory

The Actor runs with 256 MB by default and is capped at a maximum of 2 GB (2048 MB), set in .actor/actor.json (defaultMemoryMbytes, maxMemoryMbytes). Runs cannot be started with more than 2 GB. The Actor only makes JSON requests, so 256 MB is enough even for 1000 posts per account; raise it (up to 2 GB) only when scraping many accounts in one run, which also gives the run more CPU.

Blocking, proxies and login

  • Cloudflare: Truth Social often blocks datacenter IP addresses, including Apify's default servers, which is why the default proxy is residential (see "Proxy" above). The Actor recognises a block (Cloudflare challenge, HTTP 403/429, an HTML page instead of data), retries up to 3 times with back-off and, with a proxy, a new proxy session each time. If it stays blocked, the run fails with a message saying what to change.
  • Rate limits: HTTP 429 answers are retried after the time the site asks for (at most 60 s).
  • Login: public profiles are readable without an account. If Truth Social ever requires login for them, the run fails with "login required" and asks for accessToken. To get one: log in at truthsocial.com in your browser, open the developer tools (F12) > Network, reload, click any request to truthsocial.com/api/... and copy the value after Bearer in its Authorization request header. The token belongs to your account; the input field is stored encrypted and never logged.
  • If some accounts fail and others succeed, the run still succeeds with the posts it got; the status message lists the failed accounts. It fails only when no posts could be saved.

Run locally

npm install
apify run --purge # uses the prefill input: the 3 latest posts of @realDonaldTrump, residential US proxy

Without the Apify CLI:

mkdir -p storage/key_value_stores/default
echo '{ "usernames": ["realDonaldTrump"], "maxPosts": 3 }' > storage/key_value_stores/default/INPUT.json
APIFY_LOCAL_STORAGE_DIR=./storage node src/main.js

Results are written to storage/datasets/default/. For offline development you can point the Actor at a mock of the API with the environment variable TRUTHSOCIAL_BASE_URL (for example http://127.0.0.1:18765).

Known limitations

  • Not tested against the live site yet. This version was verified against a local mock of Truth Social's Mastodon-compatible API (pagination, filters, ReTruths, quotes, media, blocks, rate limits, login errors) and a local stand-in for Apify Proxy (which proxy group, country and session each request asked for), not against truthsocial.com itself. If Truth Social's API differs, the first real run will show it in the log.
  • Whether requests get through Cloudflare depends on the IP address. The residential US default is the most reliable choice, but not a guarantee; residential proxy traffic is billed by Apify separately.
  • Only public accounts and public posts are available. Private or suspended accounts are reported as not found.
  • Engagement counts are what the API returns at scrape time; Truth Social may round or cache them.
  • Truth Social may list a pinned post first; the Actor sorts by date, so pinned posts only appear if they are among the newest.

Changelog

0.4

  • Default proxy: when proxyConfiguration is not passed, all requests go through Apify Proxy, RESIDENTIAL group, country US. The input schema has the same value as default and prefill, so Apify Console shows it preselected. An explicit "No proxy" (useApifyProxy: false) and your own proxy settings are still respected.
  • The run summary (OUTPUT) records the proxy used in settings.proxyDetails; error hints now depend on the proxy used.
  • Unchanged from earlier versions: the 3 latest posts by default, maximum memory 2 GB (default 256 MB), the dataset schema with its three views and the output schema.

0.3

  • Output schema (.actor/output_schema.json, linked from actor.json): the run's Output tab links the three dataset views, all dataset fields and the run summary.
  • New OUTPUT record with a run summary (status, posts saved per account, accounts not found or failed, skipped inputs, settings used), saved on success and on failure.
  • Memory limits (2 GB max, 256 MB default) and the dataset schema from 0.2 are unchanged.

0.2

  • Maximum run memory capped at 2 GB (maxMemoryMbytes: 2048); default run memory set to 256 MB (defaultMemoryMbytes: 256) so the default always stays below the cap.
  • Complete dataset schema: every output field is declared with its type and description, and all fields are required (nullable where a value can be missing). Two new views, "Engagement" and "Media and links", next to "Latest posts".
  • Item values are converted to the schema types before saving (IDs as strings, counts as non-negative integers, empty strings as null), so the platform's schema check cannot reject an item because of an unexpected API value.
  • No change to the input or to which posts are scraped.

0.1

  • First version: latest posts of public Truth Social accounts via the Mastodon-compatible API, with reply and ReTruth filters, optional proxy and access token, and block/rate-limit handling.