Content
- A short history of searching X (and why agents care)
- What x_search is (public surface vs what the model actually runs)
- Parameters that actually matter
- Which models you can use
- Billing, without the happy path diagram
- How the skill is structured (if you want to steal the pattern)
- An online demo
- Closing notes
I spend a fair amount of time writing in English, and a fair amount of that writing starts as a question I can’t answer from training data alone: did anyone on X actually say this, or is this just vibes?
That’s the whole reason I built xai-x-search-skill. Not because calling an API is hard — it’s one JSON field — but because the moment you wire X search into an agent loop, the model will happily search three times when one would have done, and your bill grows in steps of half a cent that somehow add up faster than you expect.
This post is a field note from shipping that skill: how we got from “search Twitter” to server-side x_search, what parameters actually matter, which models behave, how billing works in practice, and a small demo if you want to click around instead of reading curl.
A short history of searching X (and why agents care)
If you’ve been on the platform long enough, “search” has meant several different products.
The early years were pure inverted-index keyword search. Operators like from:, since:, filter:replies, and min_faves: became a craft. Power users lived in advanced search. Developers got the REST search endpoints, rate limits, and the usual timeline of “this GraphQL field moved again.”
Semantic search showed up later in the product UI — useful when you care about aboutness rather than exact tokens. “People complaining that AI essays all start with ‘In today’s fast-paced world’” is a terrible keyword query and a decent semantic one.
API access has always been the bottleneck for builders. Scrapers, unofficial clients, cookie-based CLIs, academic archives — the ecosystem filled the gaps when official access was expensive, restricted, or flaky. Fine for a side project. Miserable as a dependency inside an agent that needs to run unattended.
Then Grok got native X access, and xAI exposed it as a server-side tool on the Responses API: you don’t implement search yourself. You attach { "type": "x_search" } and the model decides when to fire keyword search, semantic search, user lookup, or thread fetch. That is a different contract than “here is a search endpoint, go paginate.”
That contract is also where costs get sneaky. More on that below.
What x_search is (public surface vs what the model actually runs)
From the outside, the API is almost boring:
POST https://api.x.ai/v1/responses
{
"model": "grok-4.3",
"input": [{ "role": "user", "content": "What are people saying about …" }],
"tools": [{ "type": "x_search" }]
}
You never call x_keyword_search yourself. Internally, though, successful X tool usage is categorized under server-side X search, and the implementation names you’ll see in traces are roughly:
| Internal tool | What it’s for |
|---|---|
x_keyword_search |
Classic operator-style / keyword / latest ranking |
x_semantic_search |
Meaning-based retrieval |
x_user_search |
Resolve or find accounts |
x_thread_fetch |
Pull a post + surrounding thread |
The skill’s rule is simple: agents talk to x_search; humans read the internal names only when debugging usage.
One important boundary: the Skill does not make x_search itself smarter, and it does not turn X posts into facts. It is a policy layer around the tool — search strategy, cost controls, and output shape. x_search finds current discussion; verification still needs primary sources, official documentation, or other independent evidence.
Docs also allow combining x_search with web_search in one request. The model will mix sources if the question needs both a tweet and a primary source. That’s powerful. It’s also how a “quick check” turns into a multi-tool agent turn if you don’t constrain it.
Parameters that actually matter
Official x_search tool parameters (as of the current docs):
| Parameter | Notes |
|---|---|
from_date / to_date |
YYYY-MM-DD. Inclusive range. Use them. Always. |
allowed_x_handles |
Allowlist, max 20 |
excluded_x_handles |
Blocklist, max 20 |
enable_image_understanding |
Lets the agent inspect images on posts (extra tokens) |
enable_video_understanding |
X-only; video analysis (extra tokens) |
Two things I wish I’d known on day one:
- You cannot set both
allowed_x_handlesandexcluded_x_handleson the same tool. The API returns 400. Pick a lane. - Date bounds are the cheapest precision you have. A vague query over “all time” invites extra internal searches. A week-long window with a tight keyword often finishes in one call.
Beyond the tool object, request-level knobs matter more for agents:
max_tool_calls— advisory. In the current API it is useful as a requested ceiling, but it is not a circuit breaker. My cost-first tests stayed at one call; that is evidence for the prompt strategy, not a guarantee that every future run will do the same.max_turns— the documented agent-loop control. It limits assistant/tool-call turns, not necessarily individual calls; one turn may still contain multiple tools.- Prompt text — still the real throttle. “Use exactly one keyword/latest search; no semantic follow-ups” works better than optimism.
max_output_tokens— keep summaries short if you’re doing lookup, not essay generation.reasoning.effort— useful on models that support it; not universal (see below).
In the skill I only expose two modes, because that’s the tradeoff people actually make:
Cost-first (default)
One keyword/latest search. No semantic, no user search, no thread crawl unless the user pasted a status URL. Small result count. Low output budget. This is “is this claim even on the timeline?”
Quality-first
Semantic + keyword, optional user/thread context, higher call budget. This is “map the discussion and rank confidence.”
There is room for a middle tier (two calls: semantic + keyword). I didn’t add it in v1 on purpose. Two modes force a choice; three modes invite bikeshedding.
Which models you can use
Anything on the Responses path that is allowed to use server-side tools can, in principle, run x_search. In practice, behavior differs. The model examples and prices below are time-sensitive; treat them as a snapshot, not a compatibility promise.
From my own live checks while building the skill (prices and IDs move — double-check console / docs):
| Model | Notes for X search |
|---|---|
grok-4.3 |
The skill's cost-conscious default. It supports reasoning.effort in the tested request and followed the strict one-search prompt. That does not make it the best model for every workload. |
grok-4.20-0309-reasoning / non-reasoning |
Supports x_search, but rejects reasoning: { effort: ... } with HTTP 400 in my tests. Strip that block when using these IDs. The bundled script currently fails to do so; that is a bug to fix. |
grok-4.5 |
The current official docs recommend Grok 4.5 as the most capable general model. It also worked in my test, but costs more per token. |
grok-build-0.1 |
Can call x_search, but it is a coding model. I have not tested it enough to make a reliable search-quality or cost-control claim. |
Personal take: for “verify a claim on X,” prefer a model that fits the budget with a strict prompt, and pin the model choice in production. The expensive part is often the extra tool invocations, not the difference between two token price cards.
One concrete compatibility trap: the skill's PowerShell helper always sends reasoning: { effort: "low" }. That is fine for grok-4.3 and worked for grok-4.5, but it makes the current helper return HTTP 400 for the 4.20 variants. A model override must also change the request shape.
Billing, without the happy path diagram
xAI bills tool-using requests on two axes:
- Tokens — input, output, reasoning, images, etc., at the model’s rate.
- Server-side tool invocations — successful calls only.
For X Search specifically, the public price is $5 per 1,000 invocations → $0.005 per successful x_search. Web Search is priced the same way. Image/video understanding on found media is token-based, not a separate per-call fee for the view tools.
The misconception that burns money:
“I only made one HTTP request to
/v1/responses, so I only paid for one search.”
No. One Responses call can contain multiple internal X searches. Keyword, then semantic, then a thread fetch — that’s three billable X tool uses, plus whatever tokens the agent burned planning them. Billable counts live in usage fields like server_side_tool_usage / server_side_tool_usage_details.x_search_calls (names vary slightly by SDK surface). In my current Responses API test, server_side_tool_usage_details.x_search_calls returned the expected count. The tool-call output type can also vary by surface: I observed custom_tool_call, while the documentation also describes x_search_call. Parse both if you are building a reusable client. Failed tool attempts don’t count; successful ones do.
Rough numbers from my June 2026 measurements (same query, your mileage will vary):
| Setup | x_search calls | Ballpark total |
|---|---|---|
grok-4.3 cost-first + strict prompt |
1 | ~$0.012–0.015 |
| Same model, loose prompt | 2 | ~$0.020–0.025 |
| Quality-first (often 3–5 calls) | 3 | ~$0.025–0.035 |
So at cost-first rates, five dollars is a few hundred lookups, not “infinite social listening.” If you’re building a product that fans out agents, put a budget story in the skill before you put a nicer renderer in the UI.
That was the entire design thesis of xai-x-search-skill:
- Default to cost-first.
- Encode the limit in both
max_tool_callsand the instruction text. - Prefer date filters.
- Keep
SKILL.mdself-contained (a lot of agents only load that file). - Ship a small PowerShell helper that prints
x_search_callsand warns when reality exceeds the limit.
It’s not glamorous infrastructure. It’s seatbelts.
A later verification pass
After publishing the first version of this post, I re-ran the public repository and helper against the live API on 2026-07-11:
| Test | Result |
|---|---|
grok-4.3, cost-first |
HTTP 200, one x_keyword_search, 4,298 tokens |
grok-4.5, cost-first |
HTTP 200, one x_keyword_search, 4,241 tokens |
grok-4.20-0309-non-reasoning, bundled helper |
HTTP 400 because the helper still sends reasoning |
Same 4.20 model, reasoning removed |
HTTP 200, one X Search call |
Both allowed_x_handles and excluded_x_handles |
HTTP 400, as documented |
| Quality mode with its five-call budget | Five calls: two semantic and three keyword searches; 13,957 tokens |
These are spot checks, not a benchmark suite. They confirm the skill's basic cost-first path and its usage reporting, but they also confirm that model-specific request construction needs fixing before the helper should be treated as production-ready.
How the skill is structured (if you want to steal the pattern)
SKILL.md # what the agent reads: modes, payloads, failure modes
scripts/*.ps1 # optional CLI for humans / agents that can exec
agents/openai.yaml
README.md # humans, pricing tables, caveatsThe interesting part isn’t the PowerShell. It’s treating search policy as code you version with the agent. When the platform changes a default model or softens max_tool_calls, you update one skill instead of twelve prompts scattered across repos.
If you’re building skills for other tools (web search, code exec), the same split works: cheap default mode, explicit expensive mode, usage introspection after the call.
The repository is intentionally small. At the current commit it has no automated test suite, CI workflow, or replayable response fixtures. That keeps the Skill easy to copy, but it also means the PowerShell helper is a smoke-test utility, not a complete compatibility harness.
An online demo
Docs and skills are easy to skim without ever paying a cent of tool fees — which also means people never feel the “two internal searches” problem.
So I put up a small Next.js demo that mirrors the skill’s two modes:
You paste your own xAI key (the demo stores it in browser localStorage and proxies the request to xAI). Pick cost-first or quality-first, optional date range, run a search, get bookmark-style results. Successful runs snapshot into a local history modal so you can re-open bookmarks without spending again.
That storage model is for a disposable demo key, not production secret management. I have not independently audited the deployed route's logs or hosting configuration, so do not paste a long-lived production key into the demo.
Source for the demo lives in a private repo on my GitHub and deploys from main to Vercel. The skill itself is public: Tan35/xai-x-search-skill.
I’m not going to claim the UI is the point. The point is you can feel the mode switch: one careful call versus “go dig.”



Closing notes
If you only take three things from this post:
x_searchis an agent tool, not a paginated Twitter API. The model chooses keyword vs semantic vs thread; you pay per successful internal call.- Parameters worth caring about: date range, handle allow/deny (not both), media understanding only when you need it, and prompt-level call discipline.
- Default cheap. Make expensive search an explicit user intent. Treat
max_tool_callsas a hint, inspect usage after every request, and construct model-specific payloads when parameters differ.
X is still one of the noisiest, fastest feedback loops on the public internet. Giving agents access without a cost story is how you learn what “$0.005” means the hard way. The skill is my cost story, written down so I don’t re-learn it every quarter.
References
- Skill: github.com/Tan35/xai-x-search-skill
- Demo: xai-x-search-demo
- Official X Search docs: docs.x.ai/developers/tools/x-search
- Pricing: docs.x.ai/docs/pricing
- Models: docs.x.ai/developers/models
- Tool usage / billing details: docs.x.ai/developers/tools/tool-usage-details
Prices and model IDs change. Treat tables here as orientation, not a contract — verify against xAI’s docs before you put this in production.