# Truth Social Scraper (`axlymxp/truth-social-scraper`) Actor

Scrape Truth Social posts, profiles, replies and group timelines as clean JSON. Track any account or group, get engagement metrics, media and playable video URLs, and run incrementally for duplicate-free monitoring. No login required. Pay only for results.

- **URL**: https://apify.com/axlymxp/truth-social-scraper.md
- **Developed by:** [axly](https://apify.com/axlymxp) (community)
- **Categories:** Social media, News, Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.00 / 1,000 dataset items

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#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 public data from [Truth Social](https://truthsocial.com) — posts ("truths"), account profiles, replies, media and **group timelines** — as clean, structured JSON.

This scraper talks directly to Truth Social's own JSON API instead of driving a browser. That makes it fast, cheap and stable, and it means you get the complete record for every post: full text, engagement counts, media attachments, group context and the author's live follower numbers.

**No Truth Social account, API key or login required.**

### Who it's for

| You are | You get |
| --- | --- |
| **Journalist / newsroom** | A timestamped archive of what public figures posted, with engagement at the moment of capture |
| **Political researcher / academic** | A clean, labelled post corpus ready for NLP, sentiment and discourse analysis |
| **Market / finance analyst** | Low-latency incremental polling of the accounts that move markets |
| **Brand, OSINT & social analyst** | Community-level visibility through Groups — a surface no other Truth Social scraper covers |
| **Developer** | A dependable JSON feed with pagination, retries and rate-limit handling already solved |

### What makes it different

- **Groups.** Scrape `truthsocial.com/group/<slug>` — the group record *and* its full public timeline. No other Truth Social scraper on the Store does this.
- **Playable video URLs.** Turn on `resolveVideoUrls` and posts with Rumble-hosted video come back with direct MP4 renditions and thumbnails, not just an embed ID.
- **Pinned posts.** Optionally capture the posts an account pinned to the top of its profile.
- **Everything in one run.** Mix profile URLs, usernames, group slugs and individual post URLs in a single run — there is no per-run account limit.
- **Incremental monitoring.** Truth Social post IDs are monotonic, so incremental mode returns *exactly* the posts published since your last run. No duplicates, no wasted rows.
- **Partial-failure tolerance.** A dead handle or a deleted group never kills the run; the remaining sources still finish and the run reports what failed.

### Output fields

Every row carries `recordType`, which is `post`, `profile` or `group`.

#### Post rows

| Field | Description |
| --- | --- |
| `postId` | Numeric post ID (monotonic — useful for ordering and deltas) |
| `postUrl` | Direct link to the post |
| `content` | Post text with HTML stripped, ready for analysis |
| `contentHtml` | Original markup, always preserved |
| `createdAt` / `editedAt` | Publication and last-edit timestamps (ISO 8601, UTC) |
| `language`, `visibility`, `sensitive`, `spoilerText` | Post metadata |
| `repliesCount`, `reTruthsCount`, `favouritesCount` | Engagement at capture time |
| `upvotesCount`, `downvotesCount` | Vote counts where the platform uses them |
| `isReply`, `inReplyToId`, `inReplyToAccountId` | Conversation context |
| `isReTruth`, `reTruthOfId`, `reTruthOfUrl`, `quoteId` | Re-share and quote context |
| `isPinned`, `isSponsored` | Post flags |
| `media[]`, `mediaUrls[]`, `hasMedia` | Attachments with type, dimensions, duration and preview URLs |
| `videoRenditions[]` | Playable Rumble MP4 renditions and thumbnails (when `resolveVideoUrls` is on) |
| `tags[]`, `mentions[]` | Hashtags and mentioned handles |
| `poll`, `card`, `cardUrl`, `cardTitle` | Poll object and link-preview card |
| `groupId`, `groupSlug`, `groupName` | Group the post was published in, if any |
| `authorId`, `authorUsername`, `authorDisplayName`, `authorUrl`, `authorAvatar` | Author identity |
| `authorVerified`, `authorFollowersCount`, `authorFollowingCount`, `authorStatusesCount` | Author profile stats at capture time |
| `sourceType`, `sourceKey`, `scrapedAt` | Provenance of the row |
| `raw` | The complete untouched API object (when `includeRaw` is on) |

#### Profile rows

`userId`, `username`, `acct`, `displayName`, `bio`, `bioHtml`, `profileUrl`, `avatar`, `header`, `website`, `location`, `followersCount`, `followingCount`, `statusesCount`, `createdAt`, `lastStatusAt`, `verified`, `isBot`, `isGroup`, `isLocked`, `acceptingMessages`, `fields[]`

#### Group rows

`groupId`, `slug`, `displayName`, `note`, `noteHtml`, `groupUrl`, `avatar`, `header`, `membersCount`, `visibility`, `membershipRequired`, `discoverable`, `isLocked`, `createdAt`, `tags[]`, `ownerId`, `ownerUsername`

### Use cases

**Archive a public figure's statements.** Point the scraper at one or more handles, set `maxItems` to the depth you need, and you get a complete, timestamped record with engagement — the raw material for fact-checking, timelines and reporting.

**Detect market-moving posts fast.** Schedule an incremental run every few minutes on the handles you care about. Each run returns only what is new, so the cost of monitoring stays proportional to actual activity rather than to how often you poll.

**Build an NLP dataset.** `cleanContent` gives you plain text with entities decoded and markup removed, alongside language codes, hashtags, mentions and engagement — everything a supervised model or topic study needs, with no HTML cleanup step.

**Map a community through Groups.** Pull a group's record and timeline to see who posts there, how often and with what reach. Combine several groups to profile a movement rather than a single account.

**Collect media at scale.** Set `onlyMedia` to capture just the visual posts, and `resolveVideoUrls` to get direct MP4 links for archiving or downstream video analysis.

**Track engagement over time.** Re-scrape the same posts on a schedule and diff `favouritesCount`, `reTruthsCount` and `repliesCount` to measure how reach accumulates after publication.

### Input parameters

| Parameter | Type | Default | Description |
| --- | --- | --- | --- |
| `startUrls` | array | `[]` | Any mix of profile, post and group URLs |
| `usernames` | array | `[]` | Handles, with or without `@` |
| `groupSlugs` | array | `[]` | Group slugs, e.g. `patriots`, `crypto` |
| `postIds` | array | `[]` | Numeric post IDs or post URLs |
| `resultsType` | enum | `posts` | `posts`, `replies`, `postsAndReplies` or `profile` |
| `maxItems` | integer | `100` | Row cap for the whole run; `0` means unlimited |
| `maxPostsPerSource` | integer | `0` | Per-account/group cap so one busy profile cannot use the whole budget |
| `postsNewerThan` | string | `""` | ISO date/date-time; stops paginating past it |
| `onlyMedia` | boolean | `false` | Only posts with attachments |
| `includePinned` | boolean | `false` | Also fetch pinned posts |
| `resolveVideoUrls` | boolean | `false` | Resolve Rumble MP4 renditions (one extra request per video) |
| `incrementalMode` | boolean | `false` | Return only posts published since the previous run |
| `stateKey` | string | `""` | Name the monitoring campaign; auto-derived when empty |
| `cleanContent` | boolean | `true` | Strip HTML from `content` (`contentHtml` is always kept) |
| `includeRaw` | boolean | `false` | Attach the full untouched API object as `raw` |
| `proxyConfiguration` | object | Apify residential, US | Recommended for runs of more than a few hundred rows |

### Example input

```json
{
    "usernames": ["realDonaldTrump"],
    "groupSlugs": ["patriots"],
    "resultsType": "posts",
    "maxItems": 30,
    "maxPostsPerSource": 10,
    "cleanContent": true,
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": ["RESIDENTIAL"],
        "apifyProxyCountry": "US"
    }
}
```

### Example output

```json
{
    "recordType": "post",
    "postId": "117257273512193853",
    "postUrl": "https://truthsocial.com/@realDonaldTrump/117257273512193853",
    "content": "Such a great golfer. Too bad I have very little time to play!!!",
    "contentHtml": "<p>Such a great golfer. Too bad I have very little time to play!!!</p>",
    "createdAt": "2026-09-12T09:06:42.567Z",
    "language": "en",
    "visibility": "public",
    "isReply": false,
    "isReTruth": false,
    "repliesCount": 3557,
    "reTruthsCount": 3098,
    "favouritesCount": 16861,
    "hasMedia": true,
    "mediaUrls": ["https://static-assets-1.truthsocial.com/tmtg:prime-ts-assets/media_attachments/..."],
    "tags": [],
    "mentions": [],
    "groupSlug": null,
    "authorId": "107780257626128497",
    "authorUsername": "realDonaldTrump",
    "authorDisplayName": "Donald J. Trump",
    "authorFollowersCount": 13049236,
    "sourceType": "profile",
    "sourceKey": "realDonaldTrump",
    "scrapedAt": "2026-09-13T10:22:05Z"
}
```

A group row looks like this:

```json
{
    "recordType": "group",
    "groupId": "110231299744521512",
    "slug": "patriots",
    "displayName": "patriots",
    "note": "All things patriotism",
    "groupUrl": "https://truthsocial.com/group/patriots",
    "membersCount": 20,
    "visibility": "everyone",
    "membershipRequired": true,
    "createdAt": "2023-04-20T00:00:00.000Z"
}
```

### Scheduling and webhooks

Use the Apify **scheduler** to run the actor on a cron expression — `0 * * * *` for hourly monitoring, `0 6 * * *` for a daily digest. Pair it with `incrementalMode: true` and a fixed `stateKey` so each run returns only new posts.

Add a **webhook** on `ACTOR.RUN.SUCCEEDED` to push fresh rows straight into Slack, a Google Sheet, Airtable, a database or your own endpoint the moment a run finishes. Combine both and you have a live Truth Social feed with no polling code of your own.

### Use with AI agents (MCP)

This actor works as a tool for any AI assistant that supports the [Model Context Protocol](https://docs.apify.com/platform/integrations/mcp).

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=axlymxp/truth-social-scraper"
        }
    }
}
```

Then ask your assistant things like:

- "Get the last 50 posts from realDonaldTrump on Truth Social and summarize the main themes."
- "Scrape the Truth Social group `crypto` and list the most-engaged posts this week."
- "Which of these Truth Social accounts posted the most in the last 24 hours?"

### API usage

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_API_TOKEN>")

run = client.actor("axlymxp/truth-social-scraper").call(run_input={
    "usernames": ["realDonaldTrump"],
    "resultsType": "posts",
    "maxItems": 100,
})

for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item["createdAt"], item["content"][:80])
```

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

const client = new ApifyClient({ token: '<YOUR_API_TOKEN>' });

const run = await client.actor('axlymxp/truth-social-scraper').call({
    groupSlugs: ['patriots'],
    maxItems: 100,
});

const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(`${items.length} rows`);
```

### FAQ

**Do I need a Truth Social account?**
No. Everything this actor returns is visible to a logged-out visitor.

**Can it scrape comments and replies under someone else's post?**
No. Truth Social requires a logged-in account to read a post's reply thread — that is a platform restriction, not a limitation of the scraper. You *can* scrape an account's own replies with `resultsType: "replies"`, and you get `repliesCount` on every post.

**Can it search Truth Social or scrape hashtags and trends?**
No. Search, trending and hashtag timelines are gated behind a login by Truth Social itself. This actor deliberately only covers what is genuinely public.

**How many posts can I get from one account?**
There is no fixed ceiling — pagination follows the platform's own cursor until the timeline ends. Use `maxItems` and `maxPostsPerSource` to control volume and cost.

**Why did I get fewer rows than `maxItems`?**
The account or group has fewer public posts than you asked for, a filter such as `onlyMedia` or `postsNewerThan` excluded the rest, or an incremental run found nothing new. All three are logged.

**Do I need a proxy?**
For small runs, no. Truth Social throttles a single IP after roughly a hundred rapid requests, so for anything beyond a few hundred rows use the default Apify residential US proxy — the actor rotates the exit IP automatically when it is throttled.

**How fresh is the data?**
It is fetched live at run time. Engagement counts are a snapshot of the moment the post was captured, which is why every row carries `scrapedAt`.

**How do I avoid duplicates when monitoring?**
Set `incrementalMode: true` and keep `stateKey` stable. The actor remembers the newest post ID per source and returns only what came after it.

**Is scraping Truth Social legal?**
This actor only reads content that is publicly visible without a login, which is broadly treated the same as other public social media content. Public posts can still contain personal data, so use the results lawfully and in line with GDPR and any other rules that apply to you. See Apify's [guide to web scraping legality](https://blog.apify.com/is-web-scraping-legal/).

# Actor input Schema

## `startUrls` (type: `array`):

Truth Social URLs in any mix: profile pages (https://truthsocial.com/@realDonaldTrump), single posts (https://truthsocial.com/@realDonaldTrump/115...), or groups (https://truthsocial.com/group/patriots).

## `usernames` (type: `array`):

Truth Social handles, with or without the leading @. Each one is resolved and its timeline scraped.

## `groupSlugs` (type: `array`):

Truth Social group slugs — the last path segment of https://truthsocial.com/group/<slug>, e.g. patriots, crypto, news. The group profile plus its public timeline are scraped.

## `postIds` (type: `array`):

Specific posts to fetch, as numeric IDs (117257273512193853) or full post URLs. Timeline options are ignored for these.

## `resultsType` (type: `string`):

Posts = original truths only. Replies = only the account's replies to others. Posts and replies = both. Profile = just the account or group record, no posts.

## `maxItems` (type: `integer`):

Hard cap on the number of rows saved for the whole run. Set 0 for unlimited — use with care, busy accounts have tens of thousands of posts.

## `maxPostsPerSource` (type: `integer`):

Optional per-account/per-group cap so one busy profile cannot consume the whole budget. 0 means only Max items applies.

## `postsNewerThan` (type: `string`):

ISO-8601 date or date-time (2026-01-01 or 2026-01-01T00:00:00Z). Pagination stops as soon as an older post appears, so this is a cheap way to backfill a window.

## `onlyMedia` (type: `boolean`):

Return only posts that carry at least one image or video attachment.

## `includePinned` (type: `boolean`):

Also fetch the posts an account has pinned to the top of its profile. They are flagged with isPinned = true.

## `resolveVideoUrls` (type: `boolean`):

For posts with Rumble-hosted video, make one extra request per video to resolve playable MP4 renditions and thumbnails into videoRenditions. Slows the run slightly.

## `incrementalMode` (type: `boolean`):

Remember the newest post ID per source and, on later runs, return only posts published since then. Ideal for scheduled monitoring — no duplicates, no wasted rows.

## `stateKey` (type: `string`):

Optional name for the incremental campaign. Leave empty to derive one automatically from the sources and settings, so different source sets never share state.

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

Strip HTML from content and decode entities, ready for text analysis. The untouched markup is always kept in contentHtml.

## `includeRaw` (type: `boolean`):

Attach the complete untouched Truth Social API object as raw, so no nested field is ever dropped.

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

Truth Social rate-limits a single IP after roughly 100 rapid requests. US residential proxies are strongly recommended for runs of more than a few hundred rows.

## Actor input object example

```json
{
  "startUrls": [
    {
      "url": "https://truthsocial.com/@realDonaldTrump"
    }
  ],
  "usernames": [
    "realDonaldTrump"
  ],
  "groupSlugs": [
    "patriots"
  ],
  "postIds": [],
  "resultsType": "posts",
  "maxItems": 100,
  "maxPostsPerSource": 0,
  "postsNewerThan": "",
  "onlyMedia": false,
  "includePinned": false,
  "resolveVideoUrls": false,
  "incrementalMode": false,
  "stateKey": "",
  "cleanContent": true,
  "includeRaw": false,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "US"
  }
}
```

# Actor output Schema

## `results` (type: `string`):

All scraped rows in the default dataset.

# 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 = {
    "startUrls": [
        {
            "url": "https://truthsocial.com/@realDonaldTrump"
        }
    ],
    "usernames": [
        "realDonaldTrump"
    ],
    "groupSlugs": [
        "patriots"
    ],
    "maxItems": 100
};

// Run the Actor and wait for it to finish
const run = await client.actor("axlymxp/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 = {
    "startUrls": [{ "url": "https://truthsocial.com/@realDonaldTrump" }],
    "usernames": ["realDonaldTrump"],
    "groupSlugs": ["patriots"],
    "maxItems": 100,
}

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

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

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

```

## CLI example

```bash
echo '{
  "startUrls": [
    {
      "url": "https://truthsocial.com/@realDonaldTrump"
    }
  ],
  "usernames": [
    "realDonaldTrump"
  ],
  "groupSlugs": [
    "patriots"
  ],
  "maxItems": 100
}' |
apify call axlymxp/truth-social-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,axlymxp/truth-social-scraper"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/mdSNeJuQ8oqjiFbfm/builds/rH8slG5ougZKcLbWd/openapi.json
