Brand Mentions Finder builds a monthly list of third-party pages and public X posts about a brand. It searches the web and X for the last 30 days, then drops the brand's own sites and the brand's own account. Authors of X posts are shown as a user. The rows are what Desearch returned for that search, not a full count of the conversation.
How this differs
The social listening report pulls the last 7 days of X posts and web pages and keeps the brand's own pages in the sheet. The Twitter complaints monitor keeps posts that pair the brand with complaint words and sorts them into themes. This script looks back 30 days, asks for links, and removes the brand's own domains and account before it labels tone.
The problem
A founder or PR person who wants "what others said this month" still has to skip the brand's own site, skip the brand's own posts, and paste the rest into a sheet. Most of a naive search is the brand talking about itself.
What the app does
- Reads the brand, what it is, brand terms, the brand's own account, own domains and a 30-day window from
config.json. - Calls AI search for web and X links, then calls X search for more posts with a likes floor.
- Drops links on the brand's own domains and subdomains, posts from the brand's own account, duplicate links, rows with no brand term, and rows that match another meaning of the name.
- Writes a table with where, link, a short snippet, tone (positive, neutral, negative) and date, plus a "left out" list.
- Shows each X author as "a user".
How it works
- Links.
POST /desearch/ai/searchwithtools: ["web", "twitter"],result_type: "ONLY_LINKS",streaming: false, andstart_date/end_datecovering the last 30 days. - More posts.
GET /twitterwith the brand terms inside parentheses,-from:for the account you name,sort=Latest,min_likesandcount. Dates areYYYY-MM-DD. - Clean. Domain and account filters run after the response. The request does not ask the API to drop domains.
- Tone. A small word list marks positive, negative or neutral. Read each row before you act on it.
The code
The X query keeps the OR group in parentheses and leaves out the brand account:
def x_query(cfg):
group = term_query(cfg["brand_terms"])
account = (cfg.get("own_account") or "").strip().lstrip("@")
if account:
group += " -from:%s" % account
return group
The AI search body:
def ai_payload(cfg, start, end):
brand = cfg["brand"]
what = (cfg.get("what_it_is") or "").strip()
prompt = "Third-party reviews, articles and posts that mention %s" % brand
if what:
prompt += ", %s" % what
prompt += ", from the past month"
return {
"prompt": prompt,
"tools": ["web", "twitter"],
"result_type": "ONLY_LINKS",
"streaming": False,
"start_date": "%sT00:00:00Z" % start.isoformat(),
"end_date": "%sT23:59:59Z" % end.isoformat(),
}
Own-domain check:
def on_own_domain(url, domains):
host = host_of(url)
if not host:
return False
for domain in domains or []:
d = domain.lower().strip().removeprefix("www.")
if d and (host == d or host.endswith("." + d)):
return True
return False
The two live calls:
def run_live(cfg, session=None):
key = api_key()
if session is None:
import requests
session = requests.Session()
session.headers["Authorization"] = key
start, end = window(cfg)
payload = ai_payload(cfg, start, end)
params = x_params(cfg, start, end)
ai = session.post(BASE + "/desearch/ai/search", json=payload, timeout=120)
xres = session.get(BASE + "/twitter", params=params, timeout=90)
raw = {
"run_at": dt.datetime.now(dt.timezone.utc).isoformat(timespec="seconds"),
"cfg": cfg,
"start_date": start.isoformat(),
"end_date": end.isoformat(),
"ai": {"status": ai.status_code, "body": _json(ai), "payload": payload},
"x": {"status": xres.status_code, "body": _json(xres), "params": params},
}
return raw, key
The key is sent only in the Authorization header and is not written to the output.
Endpoints
POST /desearch/ai/searchGET /twitter
Example output
The 2026-10-15 sample used a Mac launcher app as the brand. AI search returned web pages and X posts for the last 30 days, and the X search returned 20 posts. 6 of 10 web pages were on the brand's own site and were left out. 1 post in 30 was about something else and was left out. X 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 makes two calls. The sample write-up does not add the X-Desearch-Cost-Usd headers into one total. See pricing.
Ideas to extend it
- Run it on the first of the month and keep each CSV.
- Add a column for the brand's own pages so you can see what was dropped.
- Split tone counts by week.
