Back to use cases

    Use case / Analysts / Python 3 / Published

    Twitter Reply Tracker: See How an Account Uses Replies on X

    Card for Twitter Reply Tracker: See How an Account Uses Replies on X

    Reply Ledger is a small Python script that works as a Twitter reply tracker. Give it a public X handle and it pulls the account's recent posts and replies, then writes a ledger: how replies compare with original posts, who the account replies to most, reply volume by day and its best replies.

    The problem

    Replies are a big part of how brands and creators grow on X, but the built-in views mix them with everything else. Social and community teams want to see how much an account replies, to whom, and which replies actually got attention, for their own account or a peer.

    What the app does

    • Takes a public X handle and a look-back window.
    • Pulls the timeline and the account's replies in that window.
    • Compares replies, original posts, thread replies and reposts (median likes, views, bookmarks).
    • Lists who the account replies to most and reply volume by day.
    • Shows the top 10 replies by engagement with the post they answered.
    • Lists busy own posts with no reply from the account in the sample.

    How it works

    1. Timeline. GET /twitter/user/posts with paging, newest first, until the window is covered.
    2. Replies. GET /twitter/replies with user, count=100 and query=since:<date>.
    3. Parents. GET /twitter/post for the posts that the top replies answered.
    4. Write the ledger and a snapshot with every call and its cost.

    The code

    def fetch(client, handle, since, pages, parents_n):
        timeline, cursor, user = [], None, None
        for p in range(pages):
            params = {"username": handle} | ({"cursor": cursor} if cursor else {})
            st, body = client.get("/twitter/user/posts", params, f"user-posts-p{p + 1}")
            if st == 404 and p == 0:
                return None, [], {}  # handle not found: skip the replies call (it bills 10 units on empty)
            if st != 200 or not isinstance(body, dict):
                break
            user = body.get("user") or user
            tw = body.get("tweets") or []
            timeline += tw
            cursor = body.get("next_cursor")
            oldest = min((parse_time(t.get("created_at")) for t in tw), default=None)
            if not cursor or not tw or (oldest and oldest < since):
                break
        st, body = client.get("/twitter/replies", {"user": handle, "count": 100, "query": f"since:{since.date()}"}, "replies")
        replies = body if st == 200 and isinstance(body, list) else []
        tweets = in_window(own_only(merge(timeline, replies), handle), since)
        parents = {}
        top = sorted([t for t in tweets if kind(t, handle) == "reply"], key=engagement, reverse=True)[:parents_n]
        for t in top:
            pid = str(t.get("in_reply_to_status_id"))
            try:
                st, body = client.get("/twitter/post", {"id": pid}, f"parent-{pid}")
            except RuntimeError:
                break
            if st == 200 and isinstance(body, dict) and body.get("text"):
                parents[pid] = body
        return user, tweets, parents
    

    The folder has one script, replyledger.py, offline tests in test_replyledger.py and a real ledger in sample-output.md.

    Endpoints

    • GET /twitter/user/posts
    • GET /twitter/replies
    • GET /twitter/post

    Example output

    From runs on 2026-10-07: 30 days of a space agency's account took 11 calls and 121 billed units ($0.018). 14 days of a brand support account took 7 calls ($0.007). The ledger shows counts per post type, top reply targets, replies per day and the top replies by engagement.

    Run it yourself

    The public examples folder linked above includes the script and a README. Install its requirements, set DESEARCH_API_KEY from console.desearch.ai, and use the run command in that README.

    Useful flags: --days (default 30), --pages (timeline pages, default 5), --parents (parent posts to look up, default 5), --max-spend (default $0.25).

    What it costs

    On 2026-10-07, 30 days for one account cost $0.018 (11 calls, 121 billed units) and 14 days for another cost $0.007, from the X-Desearch-Cost-Usd headers. See pricing.

    Ideas to extend it

    • Compare your reply habits with two peers.
    • Run it monthly and track reply share over time.
    • Flag your busy posts that still have no reply from you.

    Use with AI agents

    Point an MCP client at the hosted Desearch server. Replace the placeholder with a key from the console. Do not commit the key.

    {
      "mcpServers": {
        "desearch": {
          "url": "https://mcp.desearch.ai/mcp",
          "headers": {
            "Authorization": "Bearer <DESEARCH_API_KEY>"
          }
        }
      }
    }

    Prompt you can paste for this example:

    Use Desearch to pull one X account's recent public posts and replies. Build a reply ledger: who they reply to, volume by day, and the busiest threads. Use only posts you retrieve. Do not include private data.

    Build your own example.

    Give your agents access to web and social search. Get an API key to start building, or talk to us about your integration.

    Read docs