Back to use cases

    Use case / X DATA / Python 3 / Published

    Shortlist Podcast Guests Who Already Post About a Topic

    Find people posting on X about your show topic, confirm they post about it more than once, and note past podcast pages before you write to them.

    Card for Shortlist Podcast Guests Who Already Post About a Topic

    Podcast Guest Shortlist is for a host who needs fresh guests on a niche show. It searches public X posts on the topic from the last 30 days, checks that each person posts about it more than once, and looks for past podcast pages. Each person is shown as a user. The host reviews the table and reaches out personally. The script does not draft a message or look for contact details.

    How this differs

    The Instagram influencer finder ranks public Instagram creators in a niche by followers and engagement. This script does not read Instagram. It starts from public X posts about a topic, confirms the person keeps posting about that topic, and notes whether a web search found past podcast pages.

    The problem

    Scrolling X for people who post well about a topic, then searching each name to see if they have been on a show, takes a full morning. A one-off post is a weak guest lead. A shop or a recipe page is not a guest.

    What the app does

    • Reads topic terms, the topic name, a 30-day window, min_likes, how many people to check, and brand words from config.json.
    • Searches X, drops posts outside the window, and drops posts that do not contain a topic term.
    • Sends accounts whose display name or bio matches brand words to a skipped list.
    • For each remaining person, reads their own posts on the same topic and marks "one post only" when there is just one.
    • Searches the web for "name podcast", and once more with the topic word if the first pages do not match.
    • Writes a pitch angle from that person's newest on-topic post. The written table says "a user" and does not include account names or personal post links.

    How it works

    1. Topic search. GET /twitter with the terms inside parentheses, sort=Latest, min_likes, count, and start_date / end_date as YYYY-MM-DD.
    2. Their posts. GET /twitter/post/user with user, the same topic query, and count. The script sorts those posts by date.
    3. Past shows. GET /web?query=<display name> podcast. A second call adds the topic name when the first pages do not match. Otherwise the cell says "none found".
    4. Write output/shortlist.md and output/guests.csv.

    The code

    The topic query and the two X requests:

    def topic_query(terms):
        parts = ['"%s"' % term if " " in term else term for term in terms]
        return "(" + " OR ".join(parts) + ")"
    
    
    def search_params(cfg, start, end):
        return {
            "query": topic_query(cfg["topic_terms"]),
            "sort": "Latest",
            "start_date": start.isoformat(),
            "end_date": end.isoformat(),
            "min_likes": int(cfg.get("min_likes", 20)),
            "count": int(cfg.get("count", 50)),
        }
    
    
    def user_params(cfg, account):
        return {"user": account, "query": topic_query(cfg["topic_terms"]), "count": int(cfg.get("per_user", 10))}
    

    How a podcast page is counted:

    def podcast_status(calls, tokens):
        if not calls:
            return "none found"
        pages = as_list(calls[0].get("body"))
        if any(page_matches(item, tokens) for item in pages):
            return "found"
        if len(calls) > 1 and any(page_matches(item, tokens) for item in as_list(calls[1].get("body"))):
            return "found after adding the topic"
        return "none found"
    

    The live calls, after the topic search:

        for person in people:
            if person["brand"]:
                continue
            uparams = user_params(cfg, person["account"])
            ures = session.get(BASE + "/twitter/post/user", params=uparams, timeout=90)
            user_calls.append({"account": person["account"], "params": uparams, "status": ures.status_code, "body": _json(ures)})
            first_query = "%s podcast" % (person["name"] or "a user")
            first = session.get(BASE + "/web", params={"query": first_query}, timeout=90)
            first_body = _json(first)
            web_calls.append({"account": person["account"], "query": first_query, "status": first.status_code, "body": first_body})
            if not any(page_matches(item, person["tokens"]) for item in as_list(first_body)):
                second_query = "%s %s podcast" % (person["name"] or "a user", cfg["topic_name"])
                second = session.get(BASE + "/web", params={"query": second_query}, timeout=90)
                web_calls.append({
                    "account": person["account"], "query": second_query, "status": second.status_code, "body": _json(second),
                })
    

    The key is sent only in the Authorization header. The public table does not print account names.

    Endpoints

    • GET /twitter
    • GET /twitter/post/user
    • GET /web

    Example output

    The 2026-10-14 sample used home baking terms, at least 20 likes, over 30 days. 50 posts came back. 15 people were checked. 13 were kept as individuals and 2 were skipped as brand-style accounts. Past podcast pages were found for 5 of the 15. One of those showed up only after the topic was added to the web search. The public table calls every person "a user".

    Run it yourself

    The public examples folder linked above includes the script, config.json, a saved prompt and a README. Install its requirements, set DESEARCH_API_KEY from console.desearch.ai, and use the run command in that README. You can also paste the saved prompt into an MCP client pointed at https://mcp.desearch.ai/mcp.

    What it costs

    A run is one topic search, then one posts call and one or two web calls for each person who is not skipped as a brand. The sample write-up does not add X-Desearch-Cost-Usd into a single total. See pricing.

    Ideas to extend it

    • Keep last month's accounts so the next shortlist is new people.
    • Add a column for how many of the checked posts fall inside the 30-day window.
    • Stop at fewer people while you try a new topic.

    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 find public X posts from the last 30 days about the topic I name. Keep people who posted about it more than once, skip brand-style accounts, and search the web for past podcast pages. Call each person a user. Do not draft outreach or look for contact details. Do not invent posts or pages.

    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