X

find-queryid

x.com · Cowork
Download for Coworkthe skill folder, zipped
How to use it in Coworkonce per skill
Download the skill (.zip)

One .zip per skill. Inside: SKILL.md with the intent and the frontmatter, and the code that runs in the page.

Open Skills in Cowork

Settings → Personalize → Skills. This is Cowork's own skill library, shared across every chat.

Add → pick the .zip

Click Add and choose the file you just downloaded. Cowork installs it once; no CLAUDE.md, no per-project setup.

Ask in plain language

The skill stays available in every session. Cowork runs it in your own Chrome, riding the session you are already signed into.

Side effectread
Authsession (a logged-in X session is required - every GraphQL call is signed with the ct0 cookie)
Needsnavigate · evaluate
Summary

Find the queryId of an X GraphQL operation by searching the loaded JS bundles.

Params
{"op":"string, REQUIRED (the operationName, e.g. \"UserByScreenName\", \"SearchTimeline\", \"CreateTweet\")"}
Returns
{"op":"string","queryId":"string|null (null when the operation is not in the bundles loaded by the current page)"}
SKILL.md78 lines

x-find-queryid

Resolves an operation name (e.g. SearchTimeline) to its current queryId by grepping X's own script bundles. Resolves in a single bridge call against X's internal GraphQL API, no page is opened.

The extractor lives as text in the site's localStorage (key x-find-queryid) and is rebuilt on each call with synchronous eval. It is stored once and then persists across navigation and browser restarts, so on every run except the first it is already there.

Default action: just call (step 1). The call itself reports NEEDS_STORE when the extractor is missing or out of date, only then do you store it (step 2) and call again.

Versioning. The stored extractor is gated by VER (must match the version in the frontmatter above). Both snippets carry VER = "1", keep them in sync with the frontmatter. When evaluate.js changes, bump version and VER in both snippets: the next call sees the mismatch, returns NEEDS_STORE, and re-stores automatically. Storage stays at two keys (x-find-queryid and x-find-queryid:ver), overwritten each store, versions never accumulate.

1. Call (do this every run, params only, single bridge call)

await (() => {
  const KEY = "x-find-queryid", VER = "1";
  const s = localStorage.getItem(KEY);
  if (!s || localStorage.getItem(KEY + ":ver") !== VER) return 'NEEDS_STORE';
  const fn = eval('(' + s + ')');
  return fn(document, { op: "SearchTimeline" });
})()

Returns the operation's current queryId. If it returns the string 'NEEDS_STORE', the extractor is missing or stale in this browser → do step 2 once, then run this exact call again.

Run this snippet verbatim. Never add an await before the eval, only the outer await is allowed.

Any logged-in x.com page works: the extractor reads the session cookies and the page's own script tags, then calls the API itself. It does not read the page's content, so it does not matter which x.com page is open.

2. Store (only when step 1 returned NEEDS_STORE; persists until localStorage is cleared)

From a logged-in x.com page, evaluate the following with the bridge, replacing <FN> with the contents of evaluate.js (the ( async (root, params) => { ... } ) function). Keep VER equal to the call snippet's:

(() => {
  const KEY = "x-find-queryid", VER = "1";
  const fn = (<FN>);
  localStorage.setItem(KEY, String(fn));
  localStorage.setItem(KEY + ":ver", VER);
  return 'stored';
})()

Returns "stored". The extractor passes through the model only here, once. Then go back to step 1.

What it is for

X rotates its GraphQL queryId hashes on every deploy. This skill reads the current ones straight from the bundles the page loaded, so it is the repair tool for any x-* skill that starts 404ing.

The home page loads ~3 bundles carrying ~99 operations (verified), which covers the common ones. An operation only used on a page you have not visited may be absent, open a page that uses it and retry.

A queryId alone is not always enough: some operations also need the anti-bot signature (see below), which this cannot produce.

Why some X skills are API and some are not

X requires an anti-bot signature header (x-client-transaction-id, generated per request by its obfuscated JS) on some GraphQL operations but not others. Verified live:

operationsignature needed
UserByRestId (x-whoami)no
UserByScreenName (x-get-profile)no
UserTweets (x-my-tweets)no
SearchTimeline (x-search-tweets)yes - 404 without it
CreateTweet (x-post-tweet, x-reply)yes - 200 but the post is silently dropped

That is why the search and write skills drive the rendered page instead of the API: without the signature the API is not an option, and no amount of correct variables fixes it.

Errors

  • NEEDS_STORE → extractor missing or version-mismatched in this browser; run step 2 once, then retry step 1.
  • queryId: null → the operation is not in the bundles this page loaded; open an x.com page that uses it and retry.
  • no twid cookie / empty ct0 → not logged in to X in this browser; log in once and retry.
  • HTTP 429 → rate limited; see Rate limit.

Success assertion

{ "type": "json", "jsonPath": "queryId" }
find-queryid: the X skill in Cowork · browser-memory