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

Scrape Truth Social profiles and what they post. Each post comes with its text, date, engagement, and media, and you can collect only what is new since your last run, so following an account never means paying twice.

- **URL**: https://apify.com/tri_angle/truth-scraper.md
- **Developed by:** [Tri⟁angle](https://apify.com/tri_angle) (Apify)
- **Categories:** Social media
- **Features:** Limited permissions
- **Stats:** 527 total users, 46 monthly users, 99.9% runs succeeded, 8 bookmarks
- **User rating**: 4.98 out of 5 stars

## Pricing

from $1.15 / 1,000 results

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
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.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## 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.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

### Scrape Truth Social posts, replies, and profiles

Truth Social Scraper takes Truth Social usernames or profile URLs, like `@realDonaldTrump`, and returns either the profile itself or its posts and replies: the text, the date, likes, reposts, replies, media, mentions, and hashtags. It can collect only what is new since your last run, or everything after a date, so following an account costs only the new posts.

### What you get

What a row holds depends on `resultsType`.

**Profile details**, one row per profile:

| Field | What it holds |
|---|---|
| `username`, `displayName`, `url` | The account and its page |
| `description`, `website` | The bio and linked site |
| `followersCount`, `followingCount`, `postsAndRepliesCount` | Audience and activity |
| `verified`, `createdAt` | Verification and when the account was created |
| `avatar`, `header` | Profile and header images |

**Posts and replies**, one row per post:

| Field | What it holds |
|---|---|
| `content` | The post text, as HTML, or plain text with `cleanContent` on |
| `createdAt`, `url`, `id` | When it was posted and where |
| `favouritesCount`, `reblogsCount`, `repliesCount` | Likes, reposts, and replies |
| `mediaAttachments` | Images, videos, and GIFs, with their URLs and preview images |
| `mentions`, `tags` | Accounts mentioned and hashtags used |
| `pinned`, `muted`, `sensitive` | Flags on the post |
| `quote`, `reblog`, `card`, `poll` | A quoted or reposted post, a link preview, or a poll, when there is one |
| `language`, `visibility` | Detected language and who can see it |

### How to scrape Truth Social in Apify Console

1. Open Truth Social Scraper and add usernames, with or without `@`, or profile URLs to `profiles`.
2. Pick what to collect in `resultsType`: profile details, posts, replies, or posts and replies.
3. Set `maxPostsAndReplies` per profile.
4. Start the run and export the dataset as JSON, CSV, or Excel.

### Input

| Field | Type | What it does |
|---|---|---|
| `profiles` | array | Usernames, with or without `@`, or profile URLs such as `https://truthsocial.com/@realDonaldTrump` |
| `resultsType` | string | `profile-details`, `posts`, `replies`, or `posts-and-replies` |
| `maxPostsAndReplies` | integer | The most posts or replies per profile. Default `100` |
| `postsNewerThan` | string | Only posts newer than this ISO date, for example `2026-04-01` |
| `continueFromLastPostId` | boolean | Each run returns only what is newer than the last post the previous run saw. Default `false` |
| `peek` | boolean | With `continueFromLastPostId`, filter by the saved position without moving it. Default `false` |
| `onlyPostsWithMedia` | boolean | Only posts with an image, video, or GIF. Default `false` |
| `includeMuted` | boolean | Include muted posts. Default `true` |
| `cleanContent` | boolean | Strip HTML from `content` and return plain text. Default `false` |

The smallest input that works:

```json
{
  "profiles": ["@realDonaldTrump"],
  "resultsType": "posts"
}
```

Plain-text posts since a date:

```json
{
  "profiles": ["realDonaldTrump"],
  "resultsType": "posts-and-replies",
  "postsNewerThan": "2026-09-01",
  "cleanContent": true,
  "maxPostsAndReplies": 500
}
```

### Only what is new

Two ways to avoid paying for the same posts twice.

**By date.** `postsNewerThan` returns only posts newer than a date. Truth Social lists posts newest first, so the Actor stops reading as soon as it reaches an older post that is not pinned, which keeps backfills cheap.

**By position.** `continueFromLastPostId` remembers the newest post it saw for each profile and content type, in the named key-value store `store-truth-cursor`, and the next run returns only what came after it. No date to keep track of.

For a cheap "anything new?" check from n8n, Zapier, or Make, combine it with `peek`:

1. **Detect.** `continueFromLastPostId: true`, `peek: true`, `maxPostsAndReplies: 1`. It returns one post if there is something new and nothing if there is not, and leaves the saved position alone.
2. **Fetch.** When the detect run returned a post, run again with `peek: false` and a higher `maxPostsAndReplies`. It collects everything new and moves the position forward.

### Call it from code, or from an AI agent

Start a run with the Apify API and get the posts back in the same request:

```bash
curl -X POST "https://api.apify.com/v2/acts/tri_angle~truth-scraper/run-sync-get-dataset-items" \
  -H "Authorization: Bearer $APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"profiles": ["realDonaldTrump"], "resultsType": "posts", "maxPostsAndReplies": 20, "cleanContent": true}'
```

To let an agent use it, connect Apify's MCP server at `https://mcp.apify.com` in Claude, Cursor, or any MCP client and add Truth Social Scraper as a tool. An agent can then read an account's latest posts and summarize them.

### What it costs

You pay per event, at the price of your Apify plan:

| Event | Free plan | Diamond plan |
|---|---|---|
| Actor start | $0.0001 | $0.00005 |
| Result (one post, reply, or profile) | $0.005 | $0.0005 |

On the Free plan, 1,000 posts cost about $5. A detect run that finds nothing costs only the start fee.

### Limitations

- Public profiles, posts, and replies only.
- Comments on other people's posts need a logged-in account on Truth Social, so they are not collected.
- Counts are what Truth Social shows at run time.

### Troubleshooting

These cover what usually goes wrong.

- **`content` has HTML tags.** Turn on `cleanContent`.
- **A run returned nothing with `continueFromLastPostId` on.** Nothing new was posted since the last run. That is the cursor working.
- **A profile returns nothing.** Check the username on truthsocial.com.

For anything else, open an issue on the Actor's Issues tab with your run ID.

### Frequently asked questions

These are the questions people ask before their first run.

#### Is the Truth Social data live?

Yes. Every run reads Truth Social at the time it runs.

#### What is the smallest input that works?

One username in `profiles` and a `resultsType`, for example `posts`.

#### What happens when there are no new posts?

With `continueFromLastPostId` or `postsNewerThan`, the run returns nothing and you pay only the start fee.

#### Can I use it as a Truth Social API?

Yes. Call it through the Apify API with a JSON input and read the posts back as JSON. It needs no Truth Social account or login.

#### Does it work with MCP and AI agents?

Yes. Add it to Apify's MCP server and any MCP client can run it as a tool.

#### How much does it cost to scrape 1,000 Truth Social posts?

About $5 on the Free plan, down to about $0.50 on the Diamond plan.

#### How do I get notified of every new post?

Schedule a detect run with `continueFromLastPostId` and `peek`, and trigger a fetch run from your workflow tool when it returns a post.

#### Can I scrape the comments under a post?

No. Truth Social requires a login to see them, and this Actor only reads public data.

#### Is it legal to scrape Truth Social?

Scraping publicly available data is generally legal, but posts and profiles can contain personal data, which laws such as GDPR protect. Follow Truth Social's terms and ask a lawyer if you are unsure about your use case.

# Actor input Schema

## `profiles` (type: `array`):

Enter username(s) with or without "@". Additionally you can provide profile URL(s) (e.g. https://truthsocial.com/@realDonaldTrump).

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

Type of content you want to scrape from the specified profiles:

- **Profile details**: Scrape information about the profile itself, such as the description, avatar, followersCount and other profile-related details.
- **Posts**: Scrape the posts made by the profile, excluding replies to other posts.
- **Replies**: Scrape only the replies that the profile has made to other users posts.
- **Posts and replies**: Scrape both the main posts made by the profile and the replies to other users posts.

## `maxPostsAndReplies` (type: `integer`):

The maximum number of posts/replies to scrape per profile.

## `includeMuted` (type: `boolean`):

If checked, muted posts/replies will also be included in the `postsAndReplies` output.

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

If checked, on each run only posts/replies newer than the last id seen for each profile/resultsType pair will be scraped. The newest id per `username:resultsType` is persisted to the named key-value store `store-truth-cursor` under key `LAST_POST_IDS`, so the cursor carries across runs. Useful for incremental runs.

## `peek` (type: `boolean`):

Only relevant when `continueFromLastPostId` is on. If checked, the run still uses the persisted cursor to filter results, but does NOT update the cursor at the end. Use this for cheap "is there at least one new post since last run?" probes: set `maxPostsAndReplies` to 1 and `peek` to true, then trigger a follow-up run with `peek` off (and a higher `maxPostsAndReplies`) to fetch every new post since the previous real run.

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

ISO 8601 date or date-time (e.g. `2026-04-01` or `2026-04-01T00:00:00Z`). Only posts/replies with `createdAt` strictly newer than this value are returned. Pagination stops as soon as an older non-pinned post is encountered, so the filter is efficient on Truth Social's newest-first feed. Useful for ad-hoc backfills (`continueFromLastPostId` handles the recurring case). Leave empty to disable.

## `onlyPostsWithMedia` (type: `boolean`):

If checked, only posts/replies that contain at least one media attachment (image, video, GIF) will be returned.

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

If checked, HTML tags are stripped from the `content` field and common HTML entities are decoded. Truth Social wraps post text in `<p>`, `<a>`, `<br>` etc. - turn this on to get plain text. Defaults to false to preserve the existing output shape.

## Actor input object example

```json
{
  "profiles": [
    "@realDonaldTrump"
  ],
  "resultsType": "profile-details",
  "maxPostsAndReplies": 100,
  "includeMuted": true,
  "continueFromLastPostId": false,
  "peek": false,
  "onlyPostsWithMedia": false,
  "cleanContent": false
}
```

# 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 = {
    "profiles": [
        "@realDonaldTrump"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("tri_angle/truth-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 = { "profiles": ["@realDonaldTrump"] }

# Run the Actor and wait for it to finish
run = client.actor("tri_angle/truth-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 '{
  "profiles": [
    "@realDonaldTrump"
  ]
}' |
apify call tri_angle/truth-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,tri_angle/truth-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/wFKNJUPPLyEg7pdgv/builds/oJDQpMGXLeqwaoLZD/openapi.json
