Back to use cases

    Use case / Marketers / Python 3 / Published

    Check New X Posts for Keywords Since Your Last Look

    Search X for your phrases since a saved last-check time, keep only newer posts, drop link-only rows, and write the time to use on the next run.

    Card for Check New X Posts for Keywords Since Your Last Look

    X Keyword Monitor is a daily check for a few phrases on X. You keep a last-check time. Each run searches public posts, keeps only posts newer than that time, drops link-only posts, and prints the time to save for the next run. Authors are shown as a user. The rows are what Desearch returned, not a full count of the conversation.

    How this differs

    The Twitter complaints monitor pairs a brand with complaint words and sorts posts into themes. Export Twitter search results to CSV writes one date window to a file and does not remember the last run. This script stores a last-check time and, on the next run, keeps only posts created after it.

    The problem

    Typing the same X searches every morning means scrolling past posts you already saw. A keyword list without a cutoff fills up with yesterday. A community manager wants the new posts, a short summary, and a timestamp to paste in next time.

    What the app does

    • Reads keywords, a likes floor, a count and last_check (UTC) from config.json.
    • Calls GET /twitter with the phrases OR'd inside parentheses, from the date of the last check through today.
    • Keeps posts created after last_check.
    • Drops posts whose text has none of the keywords, and posts that are only a link.
    • Sorts what remains newest first, writes three summary lines, and prints the next last-check time.
    • Shows each author as "a user".

    How it works

    1. Search. GET /twitter with sort=Latest, min_likes, count, start_date set to the date of last_check, and end_date set to today (YYYY-MM-DD).
    2. Filter. The date on the request is a whole day, so the script drops posts that are not newer than the exact last-check time.
    3. Write output/monitor.md and output/posts.csv. Copy Next LAST CHECK back into last_check.

    The code

    The query and the request:

    def keyword_query(keywords):
        parts = ['"%s"' % term if " " in term else term for term in keywords]
        return "(" + " OR ".join(parts) + ")"
    
    
    def x_params(cfg, now):
        last = parse_time(cfg["last_check"])
        return {
            "query": keyword_query(cfg["keywords"]),
            "sort": "Latest",
            "start_date": last.date().isoformat(),
            "end_date": now.date().isoformat(),
            "min_likes": int(cfg.get("min_likes", 5)),
            "count": int(cfg.get("count", 20)),
        }
    

    Link-only posts are dropped after the response:

    def link_only(text):
        stripped = re.sub(r"https?://\S+", " ", text or "")
        stripped = re.sub(r"www\.\S+", " ", stripped)
        return re.sub(r"[^\w]+", "", stripped) == ""
    

    The live call:

    def run_live(cfg, session=None, now=None):
        key = api_key()
        if session is None:
            import requests
            session = requests.Session()
        session.headers["Authorization"] = key
        if now is None:
            now = parse_time(cfg["now"]) if cfg.get("now") else dt.datetime.now(dt.timezone.utc)
        params = x_params(cfg, now)
        res = session.get(BASE + "/twitter", params=params, timeout=90)
        try:
            body = res.json()
        except ValueError:
            body = {"_text": getattr(res, "text", "")[:500]}
        raw = {
            "run_at": now.isoformat(timespec="seconds"),
            "now": now.isoformat(timespec="seconds"),
            "last_check": cfg["last_check"],
            "cfg": cfg,
            "x": {"status": res.status_code, "body": body, "params": params},
        }
        return raw, key
    

    The key is sent only in the Authorization header and is not written to the output.

    Endpoints

    • GET /twitter

    Example output

    The 2026-10-15 sample used three home-coffee phrases, at least 5 likes, from 2026-10-14 11:35 UTC to 2026-10-15 11:35 UTC. 20 posts came back, 12 were newer than the last check, and 11 were kept. 1 link-only post was dropped. 8 posts were older than the last check. Authors in the public sample are shown as 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

    Each run is one GET /twitter call. The sample write-up does not publish a dollar total from X-Desearch-Cost-Usd. See pricing.

    Ideas to extend it

    • Run it on a schedule and append each CSV.
    • Add a language note when you only want one language.
    • Keep the dropped link-only rows in a second file.

    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 search public X posts for the phrases I give you, starting from the last-check time I set. Keep only posts newer than that time, drop link-only posts, and tell me the time to use next. Show authors as a user. Do not invent posts.

    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