SFOLN

Catalogue / Social media data

Tweet Thread Context API – Replies & Author

sfoln/x-post-context · Social media, News, Lead generation On request

Turn any X (Twitter) post URL into one context record: the post with engagement, the author's profile, the newest replies with conversation stats and optional quote posts. $30 per 1,000 posts with 20 replies included; extra replies $0.001 each, up to 100 per post.

About

What it does

Tweet Thread Context API – Replies & Author turns any X (Twitter) post URL into a complete context package in one record: the normalized post with its engagement snapshot, the author's full profile, the newest replies (20 included, up to 100) with conversation statistics (unique repliers, top repliers, share of verified repliers, the author's own replies, reply likes, languages, hashtags, mentions and linked domains) and, optionally, up to 20 quote posts. Built for social listening, crisis monitoring, PR and campaign reporting, community management and research workflows that need "what is this post and how are people reacting" without stitching four API calls together.

Price

Price per delivered record

EventPricePer 1,000Charged for
X post context package
x-post-context
$0.03$30 / 1,000Charged once per post: the normalized post, its author's profile, up to 20 replies with conversation stats and (optionally) up to 20 quote posts.
Extra reply
x-context-extra-reply
$0.001$1 / 1,000Charged per reply delivered beyond the 20 included in x-post-context (only when maxReplies > 20).

Apify free plan: up to 10 items per run. Paid plans have no per-run cap; set maxTotalChargeUsd to cap spend.

Run

Call it from code, an agent or the Console

This API is private on Apify for now. Email us and we will publish it for you, usually within two working days. The calls below work once it is public. contact@sfoln.com

curl · synchronous run, rows in the response
curl -X POST "https://api.apify.com/v2/actors/sfoln~x-post-context/run-sync-get-dataset-items" \
  -H "Authorization: Bearer $APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"posts":["https://x.com/jack/status/20"]}'
mcp.json · hosted Apify MCP server
{
  "mcpServers": {
    "apify": {
      "type": "http",
      "url": "https://mcp.apify.com?tools=sfoln/x-post-context"
    }
  }
}
asynchronous run · for large batches
POST https://api.apify.com/v2/actors/sfoln~x-post-context/runs?maxTotalChargeUsd=1
GET  https://api.apify.com/v2/actor-runs/{runId}            # until status is SUCCEEDED
GET  https://api.apify.com/v2/datasets/{defaultDatasetId}/items?format=json

Authenticate with an Apify API token. MCP clients can instead sign in with OAuth when prompted. Example prompt for an agent: Get the context of https://x.com/jack/status/20: who posted it, how it performed and what the replies are saying.

Input

Input fields

List X (Twitter) post URLs or ids. Each post produces one dataset record with the post, its author, replies and conversation stats.

FieldTypeDefaultMeaning
posts *arrayrequiredPost URLs or ids
X / Twitter post URLs (https://x.com/user/status/123…) or numeric post ids, one per line. Duplicates are removed. Use the first post of a thread for the full conversation. Accounts on the Apify free plan can process up to 10 posts per run.
maxRepliesinteger20Max replies per post
Newest replies to include (0–100). The first 20 are included in the x-post-context price; each further reply is charged as x-context-extra-reply. Range 0–100.
includeAuthorbooleantrueInclude author profile
Add the author's full profile (followers, bio, verification, creation date…).
includeQuotesbooleanfalseInclude quote posts
Add up to 20 of the newest posts quoting this post (included in the package price).
maxItemsinteger1000Max posts
Safety cap on how many posts are processed in this run. Range 1–10000.
concurrencyinteger3Concurrency
Posts processed in parallel (1–5). Range 1–5.
itemTimeoutSecsinteger300Per-post timeout (seconds)
Time limit per post; reply paging stops early when it is near. Range 60–1800.
includeRawbooleanfalseInclude raw upstream response
Attach the unmodified post, author, reply and quote payloads under `raw` (larger output).
Example input
{
  "posts": [
    "https://x.com/jack/status/20"
  ]
}

Output

One record per input item

Records land in the run's dataset; a synchronous call returns them directly. Each has a status (ok is charged; everything else is free) and a charged flag. The run's OUTPUT record totals items and charges.

FieldTypeMeaning
inputstring | objectInput
The input item this record corresponds to.
statusstringStatus
ok (post found, charged x-post-context) | not_found (deleted / protected / unknown post, not charged) | error | skipped_invalid | skipped_budget | skipped_free_plan e.g. "ok"
chargedbooleanCharged
Whether this record incurred a pay-per-event charge.
chargedEventstringCharged event
Pay-per-event event charged for this record.
sourcestringSource
Upstream data source (twitterapi = TwitterAPI.io).
fetchedAtstringFetched at
ISO timestamp.
errorobjectError
code / message when status is not ok (or a partial failure).
warningsarrayWarnings
Non-fatal notes (partial data, stopped early, free-plan caps).
foundboolean | nullFound
Post exists and was returned.
postIdstring | nullPost id
Numeric X post id.
postUrlstring | nullPost URL
https://x.com/<handle>/status/<id>.
postTextstring | nullPost text
Full text of the post.
postCreatedAtstring | nullPosted at
ISO 8601.
authorHandlestring | nullAuthor handle
Handle of the post's author.
postobject | nullPost
Normalized post: counts, entities, media, reply / quote / repost flags.
authorobject | nullAuthor profile
Normalized author profile (followers, bio, verification, createdAt…); null when includeAuthor is false or the lookup failed.
authorSourcestring | nullAuthor source
embedded (from the post payload, no extra call) or lookup (/twitter/user/info).
likesinteger | nullLikes
Likes at fetch time.
retweetsinteger | nullReposts
Reposts at fetch time.
replyCountinteger | nullReply count
Total replies reported by X (not just the sampled ones).
quoteCountinteger | nullQuote count
Quote posts reported by X.
viewsinteger | nullViews
Views at fetch time.
bookmarksinteger | nullBookmarks
Bookmarks at fetch time.
engagementTotalinteger | nullEngagement total
likes + reposts + replies + quotes.
engagementRateByViewsPctnumber | nullEngagement rate (views) %
engagementTotal / views × 100.
engagementRateByFollowersPctnumber | nullEngagement rate (followers) %
engagementTotal / author followers × 100.
postAgeHoursnumber | nullPost age (h)
Hours between posting and fetch.
likesPerHournumber | nullLikes per hour
likes / postAgeHours.
hashtagsarrayHashtags
Hashtags in the post.
mentionsarrayMentions
Handles mentioned in the post.
linksarrayLinks
Expanded links in the post.
linkDomainsarrayLink domains
Domains of the post's links.
repliesReturnedinteger | nullReplies returned
Replies included in replies[] (newest first).
uniqueRepliersinteger | nullUnique repliers
Distinct reply authors in the sample.
topRepliersarrayTop repliers
Up to 5 { handle, replies } by replies in the sample.
verifiedRepliersSharePctnumber | nullVerified repliers %
Share of unique repliers with a blue check (over repliers whose status is known).
authorRepliesCountinteger | nullAuthor replies
Sampled replies written by the post's author.
avgReplyLikesnumber | nullAvg reply likes
Mean likes per sampled reply.
medianReplyLikesnumber | nullMedian reply likes
Median likes per sampled reply.
mostLikedReplyobject | nullMost liked reply
{ id, url, authorHandle, text, likes }.
repliesWithMediaPctnumber | nullReplies with media %
Share of sampled replies with images / video.
repliesWithLinksPctnumber | nullReplies with links %
Share of sampled replies with links.
replyLanguagesarrayReply languages
Up to 5 { lang, count }.
replyTopHashtagsarrayReply hashtags
Up to 10 { tag, count } across sampled replies.
replyTopMentionsarrayReply mentions
Up to 10 { handle, count }, the post's author excluded.
replyLinkDomainsarrayReply link domains
Up to 10 { domain, count } linked in replies (x.com excluded).
newestReplyAtstring | nullNewest reply
ISO 8601.
oldestReplyAtstring | nullOldest reply
ISO 8601 (oldest in the sample).
repliesarrayReplies
Sampled replies, newest first: { id, url, text, createdAt, lang, authorHandle, authorName, authorFollowers, authorIsBlueVerified, likes, retweets, replies, quotes, views, inReplyToId, hashtags, mentions, urls, mediaCount }.
repliesRequestedinteger | nullReplies requested
Effective maxReplies (20 on the free plan).
repliesPagesFetchedinteger | nullReply pages
Upstream reply pages fetched.
repliesStopReasonstring | nullReplies stop reason
limit | end | budget | deadline | aborted | empty_pages | max_pages | error | skipped.
extraRepliesChargedinteger | nullExtra replies charged
Replies charged as x-context-extra-reply (beyond the included 20).
emptyReplyPagesChargedinteger | nullEmpty reply pages charged
Extra-reply pages the upstream billed that added no new reply, charged one x-context-extra-reply each.
quotesIncludedboolean | nullQuotes requested
Whether includeQuotes was on.
quotesReturnedinteger | nullQuotes returned
Quote posts in quotePosts[].
quotePostsarrayQuote posts
Up to 20 newest quote posts (same shape as replies[]).
Example record
Example record
{
  "input": "https://x.com/jack/status/20",
  "found": true,
  "postId": "20",
  "postUrl": "https://x.com/jack/status/20",
  "postText": "just setting up my twttr",
  "postCreatedAt": "2006-03-21T20:50:14.000Z",
  "authorHandle": "jack",
  "post": {
    "id": "20",
    "likes": 300000,
    "retweets": 120000,
    "replies": 18000,
    "quotes": 9000,
    "views": null,
    "hashtags": [],
    "mentions": [],
    "urls": [],
    "isReply": false,
    "...": "…"
  },
  "author": {
    "handle": "jack",
    "name": "jack",
    "followers": 6500000,
    "isBlueVerified": true,
    "createdAt": "2006-03-21T20:50:14.000Z",
    "...": "…"
  },
  "authorSource": "embedded",
  "likes": 300000,
  "retweets": 120000,
  "replyCount": 18000,
  "quoteCount": 9000,
  "views": null,
  "bookmarks": 2000,
  "engagementTotal": 447000,
  "engagementRateByViewsPct": null,
  "engagementRateByFollowersPct": 6.8769,
  "postAgeHours": 179000.5,
  "likesPerHour": 1.68,
  "hashtags": [],
  "mentions": [],
  "links": [],
  "linkDomains": [],
  "repliesReturned": 40,
  "uniqueRepliers": 38,
  "topRepliers": [
    {
      "handle": "someone",
      "replies": 2
    }
  ],
  "verifiedRepliersSharePct": 21.05,
  "authorRepliesCount": 0,
  "avgReplyLikes": 3.4,
  "medianReplyLikes": 1,
  "mostLikedReply": {
    "id": "18…",
    "url": "https://x.com/someone/status/18…",
    "authorHandle": "someone",
    "text": "history",
    "likes": 51
  },
  "repliesWithMediaPct": 12.5,
  "repliesWithLinksPct": 5,
  "replyLanguages": [
    {
      "lang": "en",
      "count": 31
    }
  ],
  "replyTopHashtags": [
    {
      "tag": "history",
      "count": 3
    }
  ],
  "replyTopMentions": [
    {
      "handle": "elonmusk",
      "count": 2
    }
  ],
  "replyLinkDomains": [
    {
      "domain": "youtube.com",
      "count": 1
    }
  ],
  "newestReplyAt": "2026-10-14T09:12:00.000Z",
  "oldestReplyAt": "2026-10-10T17:40:00.000Z",
  "replies": [
    {
      "id": "18…",
      "url": "…",
      "text": "…",
      "authorHandle": "someone",
      "authorIsBlueVerified": false,
      "likes": 51,
      "...": "…"
    }
  ],
  "repliesRequested": 40,
  "repliesPagesFetched": 2,
  "repliesStopReason": "limit",
  "extraRepliesCharged": 20,
  "quotesIncluded": true,
  "quotesReturned": 20,
  "quotePosts": [
    {
      "id": "18…",
      "text": "…",
      "...": "…"
    }
  ],
  "status": "ok",
  "charged": true,
  "chargedEvent": "x-post-context",
  "source": "twitterapi",
  "fetchedAt": "2026-10-14T10:00:00.000Z"
}

Machine-readable

This page for agents