# Truth Social Scraper By Keyword Search (`api-empire/truth-social-scraper`) Actor

📰 Truth Social Scraper collects public profiles, posts, comments & hashtags from Truth Social—complete with timestamps, links & engagement metrics. 📊 Export CSV/JSON for analytics, monitoring & lead gen. ⚡ Perfect for research, newsrooms, brand tracking & sentiment.

- **URL**: https://apify.com/api-empire/truth-social-scraper.md
- **Developed by:** [API Empire](https://apify.com/api-empire) (community)
- **Categories:** Social media, Lead generation, News
- **Stats:** 1 total users, 0 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $4.99 / 1,000 results

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.

Learn more: https://docs.apify.com/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

### Truth Social Scraper — Extract Posts, Profiles & Media by Keyword

Truth Social Scraper By Keyword Search watches one or more public Truth Social profiles and keeps only the posts that mention the terms on your watchlist — returning full post objects, embedded author/profile data, and any attached media as structured JSON. Every saved post is tagged with which keywords hit, how many times, a text snippet around the match, and whether it is new since your last run. No HTML, no selectors, no manual Cloudflare handling — just typed rows you can pipe into a dashboard, a spreadsheet, or an LLM. Read on for the exact input schema, the exact output shape (including the four keyword fields the source code actually writes), and how the built-in run-over-run dedup works — and where it doesn't.

***

### What is Truth Social Scraper By Keyword Search?

It's an Apify Actor that scrapes Truth Social's public, Mastodon-compatible timeline API for one or more profiles and filters the results against a keyword watchlist you define. No Truth Social account, login, or API key is required — the Actor reads the same public endpoints the Truth Social website itself uses (`/api/v1/accounts/{id}/statuses`, `/api/v1/statuses/{id}`, `/api/v1/accounts/lookup`) through Apify Proxy. It is a strict superset of a plain profile scraper: leave the keyword list empty and it returns every post from the profile's feed, unfiltered.

- Scrape a public profile's post feed, or fetch specific posts directly by ID/URL
- Filter posts by a keyword or phrase watchlist, with `any`/`all` match logic
- Pull embedded author/profile fields, media attachments, reply and re-truth (reblog/quote) data straight out of the same row
- Flag posts that are new since your last run for that profile + watchlist combination
- Export straight to JSON, CSV, Excel, or the other formats Apify's dataset supports — no parsing step

***

### 🔎 What data does Truth Social Scraper By Keyword Search collect?

Every row returned is a full Truth Social post (a Mastodon-compatible "status" object) plus four keyword-tracking fields the Actor computes. That single row bundles several distinct kinds of data:

| Data Type | Key Fields | JSON Field Names |
| --- | --- | --- |
| Posts | ID, timestamp, body text, permalink, reply flag | `id`, `created_at`, `content`, `url`, `in_reply_to_id` |
| Author / profile data (embedded per post) | Handle, display name | `account.acct`, `account.username` |
| Media attachments | Attached photos / video, one array per post | `media_attachments` |
| Re-truths & quotes | Full nested post object when the row is a repost or quote-post | `reblog`, `quote` |
| Keyword match data (added by this Actor) | Which terms hit, how many times, a text snippet, new-since-last-run flag | `matchedKeywords`, `matchCount`, `keywordSnippet`, `isNewMatch` |

The base post fields (everything except the four keyword fields) are returned exactly as Truth Social's Mastodon-compatible API sends them — the Actor does not rename, drop, or reshape them. See [Output](#-output) below for the full field list actually read and written by the scraping code, plus what "full status object" means for fields the code passes through untouched.

***

### Why not build a Truth Social keyword monitor yourself?

Truth Social does not publish a documented, developer-facing API with API keys or an approval process — the endpoints this Actor calls are the same internal, Mastodon-compatible endpoints the Truth Social web app itself uses, undocumented for third-party use. Building your own watcher means reverse-engineering those endpoints, sitting behind Cloudflare (Truth Social's edge returns 401/403/429 and "Just a moment…" interstitials to non-browser traffic), and maintaining TLS-fingerprint impersonation and IP rotation yourself.

This Actor already does that work: it opens with impit's Chrome-131 TLS fingerprint on direct requests, escalates through Apify's auto-proxy tier, then to residential proxy with per-session IP rotation on repeated blocks — trying a curl-cffi (Chrome 131) request first on residential before falling back to httpx, since that combination produces fewer Cloudflare 403s in practice. A single HTTP GET can retry up to 47 times across those tiers (`HTTP_MAX_RETRIES=8` direct/auto-proxy retries, plus up to `RESIDENTIAL_RETRY=8` residential rotations repeated across three escalation passes, plus a fixed buffer) before the run gives up on that request, with exponential backoff and a dedicated cool-down after Cloudflare interstitials.

If you're comfortable owning that maintenance burden and only need a handful of one-off pulls, a direct scraper may be worth building. If you want a keyword watchlist, dedup tracking, and Cloudflare handling that keeps working after Truth Social's edge configuration changes, that's what this Actor is for.

***

### Why do developers and teams monitor Truth Social?

Truth Social is a public political and social-commentary platform where a small number of high-follower accounts drive most engagement, which makes keyword watchlists — rather than full-feed archiving — the practical way to track it. The audiences below are the ones that actually use a keyword-filtered post monitor, not a generic "everyone scrapes everything" list.

#### For AI engineers and agent builders

Feed `matchedKeywords`, `keywordSnippet`, and `content` straight into a RAG index or an agent's tool-call response — every field arrives typed and already plain-text (when `cleanContent` is on), so there's no HTML stripping step before the text hits an embedding model. A monitoring agent can poll a run on a schedule, read `isNewMatch` to skip posts it has already indexed, and only embed genuinely new hits, keeping the vector store from re-ingesting the same post twice.

#### For journalists and media-monitoring teams

Track when a public figure's profile posts specific terms — a policy name, a company, an opponent's name — without manually refreshing a timeline. `keywordSnippet` gives enough context to triage a hit before opening the full post, and `matchCount` + `matchedKeywords` let you sort by how strongly a post matches your watchlist across a batch of saved rows.

#### For researchers and analysts

Academic and political-communication researchers can pull a bounded, keyword-scoped sample of public posts from named accounts for discourse analysis, without needing platform credentials or hitting private data — every field returned comes from Truth Social's public API surface, the same one the website itself renders from.

#### For developers building data products

Because output is a stable, typed JSON row per post, you can schedule this Actor and pipe its dataset into a warehouse, a Slack alert, or a dashboard without writing a parser. The `isNewMatch` flag (see [How many posts can you scrape](#-how-many-posts-can-you-scrape-with-this-actor)) is designed specifically so a downstream pipeline can filter to genuinely new rows instead of re-processing a full re-fetch every run.

***

### How to scrape Truth Social by keyword (step by step)

1. Open **Truth Social Scraper By Keyword Search** on its Apify Store listing and click **Try for free** (or **Start**, if you already have it saved to your account).
2. Add one or more handles under `truthSocialUsername` (the `@` is optional — the Actor strips it), or switch to Advanced and add post IDs/URLs under `fetchSinglePostByIdOrUrl` to fetch specific posts instead of a whole feed.
3. Add your terms under `keywords`, choose `keywordMatchMode` (`any` or `all`), and set `caseSensitive`, `onlyFetchReplies`, and `onlyFetchPostsWithMedia` to narrow what gets kept. Leave `keywords` empty to keep every post.
4. Set `maxPosts` (5–5000) and click **Start**. Enabling Apify Proxy under `proxyConfiguration` (RESIDENTIAL is prefilled) is strongly recommended — Truth Social sits behind Cloudflare.
5. Open the **Dataset** tab once the run finishes and export as JSON, CSV, Excel, or one of Apify's other formats — or pull it programmatically (see [Integrate](#integrate-truth-social-scraper-by-keyword-search-into-your-workflow)).

#### What to do when Truth Social changes its structure

The Actor is actively maintained against Truth Social's Mastodon-compatible API and Cloudflare configuration, and the output schema is kept stable so downstream integrations don't need to change when the underlying site does. No specific fix turnaround is published or guaranteed.

***

### ⬇️ Input

All fields are optional — there are no required parameters in the input schema. Leaving everything at default scrapes 40 recent posts from `realDonaldTrump` with no keyword filtering.

| Parameter | Type | Default | Constraints |
| --- | --- | --- | --- |
| `truthSocialUsername` | array (stringList) | *(none — falls back to `realDonaldTrump` if empty)* | One handle per line; `@` optional |
| `keywords` | array (stringList) | *(none — empty = keep every post)* | One term/phrase per line; phrases match as substrings |
| `keywordMatchMode` | string (select) | `"any"` | Enum: `"any"` (OR), `"all"` (AND) |
| `caseSensitive` | boolean | `false` | — |
| `maxPosts` | integer | `40` | `minimum: 5`, `maximum: 5000` |
| `continueFromLastPostId` | boolean | `false` | — |
| `onlyFetchReplies` | boolean | `false` | — |
| `onlyFetchPostsWithMedia` | boolean | `false` | — |
| `cleanContent` | boolean | `true` | Matching always uses plain text regardless of this setting |
| `startFromPostId` | string (textfield) | *(none)* | Must be exactly 18 digits; do not combine with `continueFromLastPostId` |
| `fetchSinglePostByIdOrUrl` | array (stringList) | *(none)* | Post IDs or full Truth Social post URLs, one per line; when set, profile-feed mode is skipped entirely |
| `proxyConfiguration` | object (proxy editor) | `{"useApifyProxy": true, "apifyProxyGroups": ["RESIDENTIAL"]}` | Standard Apify Proxy configuration object |

**Field notes, read from the source:**

- `truthSocialUsername` — every non-empty handle in the list is scraped, one profile after another, in a single run. `maxPosts` applies **per profile**, not to the run as a whole: three usernames with `maxPosts: 100` can produce up to 300 saved rows before keyword filtering, not 100.
- `keywords` — empty list = base-scraper behaviour (every post kept, `matchedKeywords` empty, `matchCount` 0). Multi-word phrases are matched as plain substrings, not tokenized/fuzzy.
- `maxPosts` — counts posts that already passed the `onlyFetchReplies` / `onlyFetchPostsWithMedia` filters during pagination, not raw posts pulled from the feed. The Actor keeps requesting more pages from Truth Social until it has collected this many qualifying posts (or the profile's feed runs out). Keyword filtering happens **after** this cap is reached — a narrow watchlist can still return zero saved rows even after scanning the full `maxPosts` allowance. Not used when `fetchSinglePostByIdOrUrl` has entries.
- `startFromPostId` — loads posts strictly older than this ID; the Actor rejects anything that isn't exactly 18 digits, and rejects combining it with `continueFromLastPostId` (they express contradictory starting points).
- `fetchSinglePostByIdOrUrl` — when this has entries, profile-feed mode (and `maxPosts`) is skipped completely; only the listed posts are fetched and checked against your keywords.
- `proxyConfiguration` — Truth Social sits behind Cloudflare. The Actor tries a direct connection and Apify's auto-proxy first, but defaults to residential proxy on repeated blocks; leaving the RESIDENTIAL group enabled (as prefilled) gives it the best chance of completing a run without escalating through failed tiers first.

**Common pitfall:** setting `continueFromLastPostId` to `true` expecting it to behave like `isNewMatch` — they track state differently (see [How many posts can you scrape](#-how-many-posts-can-you-scrape-with-this-actor)); if you only care about "what's new since last time," filter the output on `isNewMatch: true` instead of relying on `continueFromLastPostId` alone.

**Legacy field names:** the Actor also still accepts an older set of field names for backward compatibility with earlier input configurations — `urls`, `singlePostId`, `useLastPostId`, `startFromId`, `onlyReplies`, `onlyMedia`, and `username`. These aren't part of the current input schema shown above (so they won't appear as form fields in the Apify Console) and aren't documented further here; if your saved input still uses them, they continue to map onto the same behavior as their current equivalents (`fetchSinglePostByIdOrUrl`, `continueFromLastPostId`, `startFromPostId`, `onlyFetchReplies`, `onlyFetchPostsWithMedia`, `truthSocialUsername`). New integrations should use the current names in the table above.

#### Example input

```json
{
  "truthSocialUsername": ["realDonaldTrump"],
  "keywords": ["America", "great", "win"],
  "keywordMatchMode": "any",
  "caseSensitive": false,
  "maxPosts": 100,
  "continueFromLastPostId": false,
  "onlyFetchReplies": false,
  "onlyFetchPostsWithMedia": false,
  "cleanContent": true,
  "startFromPostId": "",
  "fetchSinglePostByIdOrUrl": [],
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": ["RESIDENTIAL"]
  }
}
```

***

### ⬆️ Output

Each row lands in the run's default dataset as soon as it's matched — rows stream in during the run rather than appearing all at once at the end. Every row is Truth Social's full Mastodon-compatible status object, unmodified except for optional HTML-to-plain-text cleaning of `content` (`cleanContent`), plus four fields the Actor computes: `matchedKeywords`, `matchCount`, `keywordSnippet`, and `isNewMatch`. Export as JSON, CSV, Excel, XML, RSS, or HTML table directly from the Apify dataset tab, or pull it via the API or Python/JS clients.

#### Scraped post

```json
{
  "id": "113987654321098765",
  "created_at": "2026-07-24T18:32:00.000Z",
  "content": "America is doing GREAT again — big win for everyone who believed!",
  "url": "https://truthsocial.com/@realDonaldTrump/113987654321098765",
  "in_reply_to_id": null,
  "account": {
    "id": "107780257626128497",
    "username": "realDonaldTrump",
    "acct": "realDonaldTrump",
    "display_name": "Donald J. Trump"
  },
  "media_attachments": [
    {
      "id": "113987654300000001",
      "type": "image",
      "url": "https://static-assets-1.truthsocial.com/media/example.jpg"
    }
  ],
  "reblog": null,
  "quote": null,
  "matchedKeywords": ["America", "great", "win"],
  "matchCount": 3,
  "keywordSnippet": "America is doing GREAT again — big win for everyone who believed!",
  "isNewMatch": true
}
```

**Fields confirmed in the scraping code** (`src/main.py`): `id`, `created_at`, `content` (cleaned to plain text when `cleanContent` is on — HTML entities decoded, tags stripped), `url`, `in_reply_to_id` (drives the `onlyFetchReplies` filter), `account` with its nested `acct` / `username` (used to scope keyword-match tracking per author), `media_attachments` (checked as a non-empty array for `onlyFetchPostsWithMedia`), and `reblog` / `quote` (nested, full post objects in the same shape, present when the row is a repost or quote-post — the Actor reads their `content` too when matching keywords, and cleans them recursively when `cleanContent` is on). Because the Actor calls Truth Social's Mastodon-compatible endpoints directly and passes the response through unmodified, every other field Mastodon's public [Status entity](https://docs.joinmastodon.org/entities/Status/) defines (`favourites_count`, `reblogs_count`, `replies_count`, `visibility`, `language`, `sensitive`, `spoiler_text`, `card`, `poll`, `emojis`, `application`, and so on) also comes through on each row exactly as Truth Social's API returns it — the Actor does not filter, rename, or drop any of them.

**Fields added by this Actor:**

| Field | Type | Meaning |
| --- | --- | --- |
| `matchedKeywords` | array of strings | The distinct watchlist terms found in this post (own text plus any reblog/quote text). Empty when `keywords` is empty. |
| `matchCount` | integer | Total number of keyword occurrences across the post's text, summed across all matched terms. `0` when `keywords` is empty. |
| `keywordSnippet` | string or `null` | ~160 characters of plain text centred on the first keyword match, with `…` markers when the window is truncated. `null` when there is no match (base mode) or no matched position. |
| `isNewMatch` | boolean or `null` | `true` — this post ID wasn't in the previous saved snapshot for this profile + keyword-watchlist combination (a new hit). `false` — already seen on an earlier run with the same watchlist. `null` — first-ever run for this profile + watchlist (no baseline to compare against yet). |

The dataset's default table view only surfaces ten of these keys (`id`, `created_at`, `content`, `matchedKeywords`, `matchCount`, `keywordSnippet`, `isNewMatch`, `url`, `account`, `media_attachments`) for readability — every field above is still present in the underlying JSON row; switch to the **Overview**/raw JSON view or export the dataset to see the rest.

***

### How does Truth Social Scraper By Keyword Search compare to other social keyword scrapers?

| Feature | Truth Social Scraper By Keyword Search | Generic alternative |
| --- | --- | --- |
| Output format | Typed JSON, full status object + keyword fields | Often raw HTML or partial JSON requiring a parser |
| Keyword logic | `any`/`all` match modes, case sensitivity toggle, phrase substrings | Frequently single-keyword only, no AND/OR choice |
| Cross-run dedup | `isNewMatch` flag backed by a persistent named key-value store, tracked per profile + watchlist | Usually none — every run re-returns everything |
| Single-post fetch | `fetchSinglePostByIdOrUrl` bypasses feed scraping entirely for targeted lookups | Usually feed-only |
| Anti-bot handling | Direct → auto-proxy → residential escalation with TLS impersonation and automatic IP rotation | Varies widely; many require you to supply your own proxy pool |

For comparison, Threads Search & Monitor's Apify listing advertises a "dedup-aware monitor mode" backed by a named key-value store as its differentiator among Threads scrapers, and Reddit Search Scraper's listing advertises pay-per-result pricing with no API key required — both checked on the Apify Store 2026-07-25, not measured here. This Actor's `isNewMatch` mechanism is architecturally the same idea (a persisted, per-scope snapshot of previously matched post IDs) applied to Truth Social specifically.

If you're building an AI agent or RAG pipeline, the output-format row is the decision-maker — parsing HTML inside an agent loop is a reliability failure mode, not a feature.

***

### ⚠️ How many posts can you scrape with this Actor?

`maxPosts` caps how many qualifying posts (after the reply/media filters, before keyword filtering) the Actor collects per profile, and the input schema bounds it between `5` and `5000`. There is no additional hard cap enforced in the scraping code itself beyond that schema range — the code only re-enforces the floor of 5 internally; the ceiling of 5000 is enforced by Apify's input validation before the run starts.

Pagination works by requesting Truth Social's timeline API in pages of up to 40 posts at a time, waiting roughly 4.5 seconds (plus a small random jitter) between pages to avoid triggering Cloudflare, and continuing until either `maxPosts` qualifying posts have been collected or the profile's feed is exhausted. With multiple profiles in `truthSocialUsername`, this budget applies **separately to each one** and profiles are processed one after another, not in parallel — so total posts scanned (and dataset rows saved, before keyword filtering) can be a multiple of `maxPosts`.

`fetchSinglePostByIdOrUrl` bypasses this entirely: it fetches exactly the posts you list, one HTTP call per ID/URL, with no `maxPosts` limit applying.

**On dedup across runs:** the Actor maintains two separate cross-run mechanisms, and they are not equally durable. The `isNewMatch` field is backed by a **named** Apify key-value store (`truth-social-keyword-monitor-state`), which Apify persists across separate runs by design — it reliably tells you which matched posts are new versus already seen, scoped per profile and per exact keyword/mode/case-sensitivity combination, capped at the 5,000 most recent post IDs per scope. The `continueFromLastPostId` bookmark, by contrast, is stored in the run's **default** key-value store — and Apify creates a fresh default key-value store for every run. If you're setting up a scheduled watchlist, treat `isNewMatch: true` as the reliable "what's new" signal, and don't assume `continueFromLastPostId` alone prevents re-scraping already-seen posts on a schedule — verify the behavior in your own account before depending on it for a production monitor. No benchmark run time is published for this Actor.

***

### Integrate Truth Social Scraper By Keyword Search into your workflow

Truth Social Scraper By Keyword Search works with any language or tool that can call the Apify API — there's no bespoke SDK requirement.

#### REST API integration

```python
from apify_client import ApifyClient

client = ApifyClient("<APIFY_API_TOKEN>")

run_input = {
    "truthSocialUsername": ["realDonaldTrump"],
    "keywords": ["America", "great", "win"],
    "keywordMatchMode": "any",
    "maxPosts": 100,
}

run = client.actor("<YOUR_USERNAME>/truth-social-keyword-monitor").call(run_input=run_input)

for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item["id"], item.get("matchedKeywords"), item.get("keywordSnippet"))
```

Works in Python, Node.js, Go, Ruby, cURL — anything that can authenticate to the Apify API with your account token and read a dataset back.

#### Automation platforms (n8n, Make, LangChain)

- **n8n** — use the official Apify node (or an HTTP Request node against the Apify API) to start a run with your input JSON and read the resulting dataset items into the rest of your workflow.
- **Make** — Apify's Make app exposes "Run an Actor" and "Get dataset items" modules; wire the Actor's output straight into a Slack, Sheets, or CRM module for alerting on new keyword matches.
- **LangChain** — load a finished dataset with LangChain's `ApifyDatasetLoader`, mapping each row's `content` (or `keywordSnippet`) into document text for retrieval or summarization chains.

#### Scheduling a recurring watchlist

There is no scheduling logic inside the Actor itself — recurring "monitor" behavior is Apify's **Scheduler** feature, external to this Actor. Create a Schedule on the Actor (e.g., hourly or daily) with your saved input, and use `isNewMatch: true` on each run's output to isolate genuinely new hits, since (as noted above) that flag is the durable cross-run signal, not `continueFromLastPostId`. You can also attach an Apify **webhook** to the run's `ACTOR.RUN.SUCCEEDED` event to push a notification (or trigger a downstream automation) the moment a scheduled run finishes, instead of polling the dataset yourself.

***

### Is it legal to scrape Truth Social?

Yes, when limited to publicly accessible posts and profiles. Truth Social Scraper By Keyword Search only reads data Truth Social's own public, unauthenticated API already serves — it does not log in, bypass a paywall, or access private/suspended accounts. Because post authors, handles, and display names are personal data under data-protection law, GDPR and CCPA principles apply to how you store and use anything you collect, particularly at scale or for anything beyond ad-hoc research: you need a lawful basis for processing, and you're responsible for how long you retain it and who you share it with. Truth Social's own Terms of Service govern automated access to the platform independent of data-protection law. Consult legal counsel for commercial use cases involving bulk personal data.

***

### ❓ Frequently asked questions

#### Does Truth Social Scraper By Keyword Search work without a Truth Social account?

Yes. No Truth Social login, account, or API key is used anywhere in the Actor — it reads the same public API endpoints Truth Social's own website calls. The only credential involved is your own Apify account for running the Actor and, optionally, Apify Proxy (no separate sign-up required — it's built into the `proxyConfiguration` input).

#### How often is the scraped data updated?

Every run performs a live fetch against Truth Social's API at the moment it executes — nothing is cached or served from a previous run's snapshot. Re-run the Actor (manually or on an Apify Schedule) whenever you want fresh data; there is no automatic background refresh between runs.

#### What happens if a post has been deleted, or a profile handle doesn't exist?

These two failure modes behave differently, by design of the underlying code. Fetching a specific deleted/removed post via `fetchSinglePostByIdOrUrl` is handled gracefully — Truth Social returns HTTP 404, the Actor logs it as skipped, and the run continues with the remaining IDs. An invalid or nonexistent **profile handle**, however, fails the account lookup step and is **not** caught the same way — it raises an error that stops the whole run. If you're scraping multiple profiles in one run, double-check each handle first; one bad handle currently aborts the batch rather than skipping just that profile.

#### Can I scrape private or suspended Truth Social accounts?

No. Only publicly accessible profiles and posts are returned — the Actor has no login step and cannot see anything a logged-out visitor to truthsocial.com couldn't also see.

#### Can I fetch a single Truth Social post without scraping a whole profile?

Yes. Add one or more post IDs or full post URLs to `fetchSinglePostByIdOrUrl` under Advanced — when that list has entries, profile-feed mode (and `maxPosts`) is skipped entirely, and only those specific posts are fetched and checked against your keyword watchlist.

#### Does Truth Social Scraper By Keyword Search work for AI agent workflows and LLM pipelines?

Yes — it's callable as a standard HTTP/API operation by any agent framework that can start an Apify Actor run and read back a dataset (see [Integrate](#integrate-truth-social-scraper-by-keyword-search-into-your-workflow)). Every response is typed JSON with stable field names, so there's no HTML-parsing step between the Actor's output and an LLM context window or vector store.

#### How does this handle Truth Social's Cloudflare protection?

The Actor starts with residential-proxy requests by default (the fastest path to avoiding a block in practice for this site), using a Chrome-131 TLS fingerprint via impit for direct calls and curl-cffi/httpx for proxied calls, and rotates to a fresh residential exit IP after a 401/403/429 or a Cloudflare interstitial. If residential proxy isn't available (no `proxyConfiguration` set), it falls back through a direct connection and Apify's auto-proxy tier first. See [Why not build this yourself?](#why-not-build-a-truth-social-keyword-monitor-yourself) for the retry ceiling.

#### Can I monitor a Truth Social profile for new keyword matches over time?

Yes — this is the Actor's core use case. Attach an Apify Schedule to re-run the same profile(s) and watchlist on a cadence, and filter each run's dataset on `isNewMatch: true` to isolate posts you haven't seen before. That flag is backed by a persistent named key-value store scoped to the exact profile + keyword-set + match-mode + case-sensitivity combination, so switching your watchlist starts a fresh baseline rather than mislabeling old posts as new.

#### How does Truth Social Scraper By Keyword Search compare to other keyword-monitoring scrapers?

Reddit Search Scraper's Apify listing advertises pay-per-result pricing from roughly $1.50 per 1,000 results with no Reddit API key required, and Threads Search & Monitor's listing advertises a dedicated "Monitor" mode with a dedup-aware, named-store-backed new-post flag — both checked on the Apify Store 2026-07-25, not measured here. This Actor targets a platform neither of those covers (Truth Social) and applies the same category of idea — persistent, scoped dedup tracking — to `isNewMatch`, alongside an `any`/`all` phrase-matching watchlist and a direct single-post fetch mode.

#### Does Truth Social Scraper By Keyword Search return data in a format LLMs can use directly?

Yes. Every row is typed, normalized JSON with stable field names — no HTML, no CSS selectors, no scraping artifacts to clean up before passing it to an LLM context window, indexing it into a vector store, or routing it through an agent tool call.

#### Can I use Truth Social Scraper By Keyword Search without managing proxies myself?

Yes. Enable Apify Proxy under `proxyConfiguration` (the RESIDENTIAL group is prefilled by default) and the Actor handles connection tiering, retries, and IP rotation internally — there's no separate proxy account or pool to provision.

#### What happens when Truth Social changes its structure or blocks the scraper?

The Actor is maintained against Truth Social's current API and Cloudflare configuration, and the output schema (field names and types) is kept stable so downstream integrations don't break when the underlying site changes. No specific turnaround time is published or guaranteed for fixes.

#### Why did my run save zero rows even though the profile clearly posted about my keyword?

Two independent gates run before a post is saved, and either one can produce zero rows. First, `maxPosts` bounds how many reply/media-filtered posts are pulled from the feed in that run — if your keyword only appears further back in the profile's history than `maxPosts` reaches, increase it or use `startFromPostId` to page deeper. Second, `keywordMatchMode: "all"` requires every term in `keywords` to appear in the same post; a broad watchlist with `"all"` set is much stricter than it looks. Switch to `"any"` first to confirm matches exist, then tighten to `"all"` once you've verified the watchlist.

#### Can I combine keyword filtering with fetching a single post by ID?

Yes. `fetchSinglePostByIdOrUrl` and `keywords` are independent — when you fetch specific posts, each one is still checked against your watchlist and gets `matchedKeywords`, `matchCount`, `keywordSnippet`, and `isNewMatch` computed the same way a profile-feed post would. Leave `keywords` empty if you just want the raw post(s) back with no filtering.

***

### 💬 Your feedback

Found a bug, an inconsistency, or a field you need that isn't in the output? We want to know. Open an issue from the Actor's page on the Apify Store (Issues tab) or reach out through your Apify Console — reports like these are how the keyword-matching logic and Cloudflare handling stay current as Truth Social's site changes.

# Actor input Schema

## `truthSocialUsername` (type: `array`):

✏️ Add one or more profile handles (example: **realDonaldTrump**). One entry per line. The **@** symbol is optional — we’ll figure it out.

## `keywords` (type: `array`):

🎯 Terms or phrases to watch for. A post is kept only if it matches (see match mode). **Leave empty to keep every post** (base behaviour). Phrases (multi-word) are matched as substrings.

## `keywordMatchMode` (type: `string`):

**any** — keep a post if it mentions at least one keyword.
**all** — keep only posts that mention every keyword.

## `caseSensitive` (type: `boolean`):

⬜ **Off (recommended):** ignore letter case. ✅ **On:** match exact case only.

## `maxPosts` (type: `integer`):

🎯 Number of posts to scan from that profile’s feed (between **5** and **5000**). Keyword filtering is applied to these; unmatched posts are dropped. Not used when you only fetch single posts in Advanced.

## `continueFromLastPostId` (type: `boolean`):

✅ **On:** only *new* posts since your last successful run for this profile.
⬜ **Off:** fetch fresh from the top of the feed (within your limit).

## `onlyFetchReplies` (type: `boolean`):

⬜ **Off:** normal posts (replies hidden).
✅ **On:** only reply posts.

## `onlyFetchPostsWithMedia` (type: `boolean`):

✅ **On:** keep posts that include images or video.
⬜ **Off:** everything (text-only included).

## `cleanContent` (type: `boolean`):

✅ **On (recommended):** plain text you can read at a glance.
⬜ **Off:** keep original formatting. Keyword matching always uses the plain-text version either way.

## `startFromPostId` (type: `string`):

📌 Optional **18-digit** post ID — we’ll load posts *older* than this. Don’t use together with **Pick up where you left off**.

## `fetchSinglePostByIdOrUrl` (type: `array`):

➕ Add post IDs or full Truth post links — one per line. When this list has items, **profile mode is skipped** and only these posts are checked against your keywords.

## `proxyConfiguration` (type: `object`):

🔐 Truth Social sits behind Cloudflare — residential proxy is used first. Enable Apify Proxy (RESIDENTIAL) here for reliable runs.

## Actor input object example

```json
{
  "truthSocialUsername": [
    "realDonaldTrump"
  ],
  "keywords": [
    "America",
    "great",
    "win"
  ],
  "keywordMatchMode": "any",
  "caseSensitive": false,
  "maxPosts": 40,
  "continueFromLastPostId": false,
  "onlyFetchReplies": false,
  "onlyFetchPostsWithMedia": false,
  "cleanContent": true,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}
```

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "truthSocialUsername": [
        "realDonaldTrump"
    ],
    "keywords": [
        "America",
        "great",
        "win"
    ],
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ]
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("api-empire/truth-social-scraper").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "truthSocialUsername": ["realDonaldTrump"],
    "keywords": [
        "America",
        "great",
        "win",
    ],
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
    },
}

# Run the Actor and wait for it to finish
run = client.actor("api-empire/truth-social-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "truthSocialUsername": [
    "realDonaldTrump"
  ],
  "keywords": [
    "America",
    "great",
    "win"
  ],
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}' |
apify call api-empire/truth-social-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=api-empire/truth-social-scraper",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/45FsyXuMtxemrUmO4/builds/j3tZtnI1nMvcAoy8t/openapi.json
