How to read the replies to a tweet programmatically

How to read the replies to a tweet programmatically
Unif Cookbooks team
Unif Cookbooks team

Updated

A free endpoint that returns the public replies to any X post as JSON or Markdown, sorted by engagement or time, with cursor paging.

In short: GET https://unifapi.com/tools/x/replies?id=<post id or URL> returns the post and the public replies under it as JSON. It is free to use with no login, no account and no API key, and rate-limited per visitor. sort=top (default) orders by engagement, sort=recent by time. Pages are 20 replies with a nextCursor. Each reply carries the author, text, metrics, media, and inReplyToPostId, so you can rebuild the thread. It is the one piece of X data that none of the free single-post endpoints expose, and the reason most "read this thread" agent tasks used to end in a headless browser.

The replies under a post are where the reaction lives. The post itself tells you what a brand said; the replies tell you what people think of it, what broke, what they want, and which complaint got 4,000 likes. For sentiment work, customer research, and incident monitoring they are the data.

They are also the hardest part of X to read without an account. FxTwitter and vxTwitter read one post. The syndication endpoint reads one post. X's own page loads replies with JavaScript after the fact, so curl gets an empty shell. The official API exposes replies through conversation search on paid tiers.

The request

curl -s "https://unifapi.com/tools/x/replies?id=https://x.com/NASA/status/2107237881668313108"

id accepts the numeric Post ID or the full x.com / twitter.com URL. The response:

{
  "post": {
    "id": "2107237881668313108",
    "text": "Time to bring them home 🌎 …",
    "author": { "handle": "NASA", "name": "NASA", "verified": true },
    "metrics": {
      "likes": 7210,
      "reposts": 846,
      "replies": 262,
      "quotes": 60,
      "bookmarks": 197,
      "views": 2823329
    },
    "conversationId": "2107237881668313108"
  },
  "replies": {
    "items": [
      {
        "id": "2107252849688424504",
        "text": "@NASA @Space_Station @SpaceX Those space suits don't look right…",
        "createdAt": "2026-10-05T23:33:22.000Z",
        "author": {
          "handle": "Troyztoys",
          "name": "Tee Crenshaw",
          "verified": true,
          "followers": 1823
        },
        "metrics": {
          "likes": 15,
          "reposts": 1,
          "replies": 0,
          "quotes": 0,
          "bookmarks": 0,
          "views": 894
        },
        "media": [],
        "conversationId": "2107237881668313108",
        "inReplyToPostId": "2107237881668313108"
      }
    ],
    "hasMore": true,
    "nextCursor": "20@"
  }
}

post is the original. replies.items are the public posts in its conversation other than the original, direct replies and nested ones alike. Each has inReplyToPostId, so a reply to a reply points at its parent and the thread can be rebuilt as a tree.

Sorting

sort=top (the default) orders by likes plus reposts plus replies, the way X's own "Most relevant" tab roughly does. sort=recent orders newest first. For "what is the reaction" use top; for "what happened in the last hour" use recent.

The human page, /tools/x-reply-viewer, has the same two options as pills, and /tools/x-reply-viewer?q=<id>&sort=recent&format=json returns exactly what the API does.

Paging

Replies come 20 per page. Pass nextCursor back as cursor to continue. The first cursor often looks like 20@, which means "the next 20 of the page already fetched"; later ones are X's own opaque cursors. Treat them all as opaque strings.

A post with 262 replies is about 14 pages. That is 14 of your 20 free units per 10 minutes, so read X-RateLimit-Remaining from the headers and stop when you have enough; the top-sorted first page usually holds the replies that matter.

What a reply record contains

FieldMeaning
id, urlThe reply's id and canonical x.com URL
textFull text, with leading @mentions as X stores them
createdAtISO 8601, UTC
authorhandle, name, verified, followers, avatarUrl, …
metricslikes, reposts, replies, quotes, bookmarks, views
mediaPhotos and videos with sizes and MP4 URLs on X's CDN
inReplyToPostIdThe post this reply answers
conversationIdThe root post of the conversation
possiblySensitiveX's own flag

The shape is the same post record the search, profile, and media endpoints return, so a function that scores a post works on a reply unchanged.

Three things to build

A reaction summary. Fetch the top page, feed the 20 texts to a model with the original post, ask for the three most common sentiments and one representative quote each. Twenty replies and one call; the top sort has already done the ranking.

A complaint feed. For a brand's announcement, poll sort=recent every 10 minutes, keep replies whose metrics.likes climbs past a threshold between polls, and route those to a human. The rising ones are the ones that will be screenshotted.

A thread reconstruction. Walk all pages, build a map from id to reply, then attach each reply to inReplyToPostId. Replies to the original are depth one; the rest nest. Render as Markdown and you have a readable transcript of the conversation for a report.

Limits

  • Public replies only. Replies from protected accounts and deleted replies are not included, and the replies count on the original post can be higher than what is readable for that reason.
  • The free limit is 20 lookups per 10 minutes per visitor across every /tools/x/* endpoint, and a search counts as two. A 429 carries Retry-After and the URL where the cap is lifted.
  • Volume, history, and guarantees are the metered X / Twitter API, pay as you go with a workspace key, with the same field names.

FAQ

Can I get the replies to a tweet without the Twitter API?

Yes. The endpoint above reads public replies for free, with no login, account or key, rate-limited per visitor. It returns JSON by default and Markdown with format=md.

Why does X say 262 replies but I only see 200?

Some replies are from protected accounts, some were deleted, and some are hidden by the author. The count on the original post is X's, the readable set is what is public.

Does it include quote posts?

No. Quotes are separate posts, not replies. Search for the post's URL with /tools/x/search?q=<post url> to find them.

Can I read replies as text for a model?

Yes. format=md returns the original post and each reply as a Markdown block with author, text, metrics, and URL.