Back to use cases

    Use case / AI SEARCH / Python 3 / Published

    Build an AI News Today Board with Python

    Build a once-a-day AI news today board in Python: the latest AI posts on X from the last 24 hours plus recent coverage from news sites you pick, with links.

    Card for Build an AI News Today Board with Python

    Made by Desearch (desearch.ai).

    AI News Today Board is a small Python script for analysts and founders who want one AI news today list instead of scrolling several feeds. Once a day it pulls the latest AI posts on X from the last 24 hours and recent coverage from a short list of tech news sites you choose, each with a link, and marks what is new since your last run.

    The problem

    Keeping up with AI means opening several feeds every morning and scrolling past the same stories twice. A single broad phrase like "ai news today" is too loose: the example notes that a broad query on that raw phrase brought back mostly off-topic posts. What helps is a short, fixed list of focused searches, one place to read the results, and a way to see only what is new since yesterday.

    What the app does

    • Runs a fixed query plan of five AI sub-queries: new AI model release, open source LLM, AI startup funding round, AI regulation, and AI agents launch.
    • For each sub-query, gets the latest 30 X posts with at least 20 likes and keeps the ones from the last 24 hours.
    • For each sub-query, gets 10 pages from a short list of tech news sites (NEWS_SITES near the top of the script, or --sites for one run) and keeps recent coverage: pages dated in the last 7 days, plus undated pages marked "no date".
    • Drops link-only posts and posts that mention an account, dedupes by link, and tags every item with its sub-query.
    • Remembers the links it has already shown you in seen-urls.txt, so the next board marks only fresh items as new.
    • Writes a CSV (one row per item) and a Markdown board: the top 15 posts by likes plus reposts plus replies, then recent coverage from the news sites, newest first.

    How it works

    1. X posts. For each sub-query, GET /twitter with sort=Latest, count=30 and min_likes=20, through x_search in the desearch-py SDK. min_likes is passed as a string. Yes/no filters are not passed.
    2. News pages. For each sub-query, POST /desearch/ai/search with tools: ["web"], include_domains set to your news sites, result_type: "ONLY_LINKS" and date_filter: "PAST_24_HOURS", over REST with requests. The SDK's ai_search in desearch-py 1.2.1 (checked 2026-10-18 in the example README) has no include_domains argument.
    3. Filter. Keep posts from the last 24 hours, drop link-only posts and posts that mention an account (so every quote stays exactly as written), and keep pages from the last 7 days or undated ones. The example notes that the date filter did not narrow the web results to recent pages, so the script still drops pages older than 7 days.
    4. Merge. Dedupe by link, tag each item with its sub-query, and compare with seen-urls.txt.
    5. Write. Save the CSV, the Markdown board and the raw responses as JSON, and print the total cost from the response headers.

    One run is 10 calls: 5 sub-queries times 2 sources.

    The code

    The script reads the API key only from a key file (~/.desearch_api_key by default, or --key-file PATH). It does not read environment variables. The X call, copied from ai_news_board.py on main (lines 55 to 72):

    PYTHON
    async def x_call(client, tag, query, count, min_likes):
        """GET /twitter through the desearch-py SDK (x_search). Yes/no filters are not passed."""
        at, t0 = now(), time.time()
        params = {"query": query, "sort": "Latest", "count": count, "min_likes": str(min_likes)}
        try:
            res = await client.x_search(query=query, sort="Latest", count=count, min_likes=str(min_likes), include_metadata=True)
            data, meta = res.data, res.metadata
            body = [d.model_dump(mode="json") if hasattr(d, "model_dump") else d for d in (data if isinstance(data, list) else [data])]
            if isinstance(data, dict): body = data
            status = 200
            cost = getattr(meta, "cost_usd", None) if meta else None
            meta_d = meta.model_dump(mode="json") if hasattr(meta, "model_dump") else (vars(meta) if meta else {})
        except Exception as e:
            status = getattr(e, "status", None); body = {"_error": repr(e)[:500]}; cost = None; meta_d = {}
        rec = {"source": "x", "tag": tag, "params": params, "at": at, "seconds": round(time.time() - t0, 2),
               "status": status, "cost_usd": cost, "meta": meta_d, "body": body}
        log(rec, len(body) if isinstance(body, list) else 0)
        return rec

    The script runs this once per sub-query. It also adds recent coverage from an editable list of news sites (NEWS_SITES near the top of the script) through POST /desearch/ai/search. That call is web_call in the same file (lines 75 to 91). QUERY_PLAN holds the five sub-queries, samples/ holds a saved run you can rebuild offline, and tests/ has offline tests.

    View the code

    Endpoints

    • GET /twitter
    • POST /desearch/ai/search

    Example output

    Saved sample from a run at 2026-10-18T16:00:15+04:00 (16:00 Asia/Tbilisi). This page shows that stored response. It does not run a live demo.

    The live run log in samples/live-run-2026-10-18.md records 10 calls. Every call returned 200 and the number of items asked for (30 posts, 10 pages).

    callsub-querystatussecondsitems returned
    GET /twitter sort=Latest count=30 min_likes=20model release2009.2630
    GET /twitter sort=Latest count=30 min_likes=20open source llm2004.0730
    GET /twitter sort=Latest count=30 min_likes=20ai funding2007.7130
    GET /twitter sort=Latest count=30 min_likes=20ai regulation2006.4530
    GET /twitter sort=Latest count=30 min_likes=20ai agents2004.8630
    POST /desearch/ai/search tools=web count=10model release2006.2310
    POST /desearch/ai/search tools=web count=10open source llm2006.0410
    POST /desearch/ai/search tools=web count=10ai funding2006.0310
    POST /desearch/ai/search tools=web count=10ai regulation2006.0310
    POST /desearch/ai/search tools=web count=10ai agents2007.9510

    After those filters, the log says the board had 34 X posts and 18 pages (4 dated in the last 7 days, 14 undated).

    The public sample (samples/sample-raw.json) leaves out some posts, so rebuilding it makes a smaller board. samples/sample-ai-news.md reports:

    • calls: 10
    • X posts returned: 103, below the like threshold: 0, older than 24 h: 65, link only: 8, left out because they mention an account: 0
    • web pages returned: 50, outside the site list: 0, older than 7 days: 32, no date: 14
    • duplicates removed: 1, items on the board: 47, new: 47, on topic by keyword check: 44

    Authors on the board are shown as "a user".

    Run it yourself

    BASH
    git clone https://github.com/Desearch-ai/desearch-py-examples && cd desearch-py-examples/ai-news-today-board
    pip install -r requirements.txt
    printf '%s' 'YOUR_KEY' > ~/.desearch_api_key && chmod 600 ~/.desearch_api_key   # key from console.desearch.ai
    python ai_news_board.py --key-file ~/.desearch_api_key --out output

    Flags that matter: --min-likes (default 20), --max-age-hours (default 24), --count (X posts per sub-query, default 30), --web-count (pages per sub-query, default 10), --page-days (default 7), --sites to use your own news sites for one run. To try it with no key and no cost, rebuild the saved board: python ai_news_board.py --from-raw samples/sample-raw.json --out output/sample.

    What it costs

    One daily run is 10 calls. The script prints each call's X-Desearch-Cost-Usd header and the sum. The saved live-run log and the sample do not include those header values, so this page does not state a dollar amount. See pricing.

    Ideas to extend it

    • Run it with cron every morning and keep seen-urls.txt between runs, so each board shows only what is new.
    • Swap the sub-queries in QUERY_PLAN for your own niche, for example one field or one product category.
    • Replace NEWS_SITES with the sites your team reads.
    • Post the top five items to a team chat each morning.

    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.

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

    Prompt you can paste for this example:

    Use Desearch to build an AI news board for the sub-queries I name. Default plan: new AI model release, open source LLM, AI startup funding round, AI regulation, and AI agents launch. For each, call GET /twitter with sort Latest, count 30 and min_likes 20, and keep posts from the last 24 hours that are not link-only and do not mention an account. Call POST /desearch/ai/search with tools web, include_domains set to the news sites I name, result_type ONLY_LINKS and date_filter PAST_24_HOURS, then keep pages dated in the last 7 days and undated pages. Dedupe by link, tag each item with its sub-query, and mark links that are not already in my seen list as new. Show authors as a user. Do not invent posts, pages, likes or costs.

    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