Guest tokens
A guest token is what x.com uses when nobody is logged in. With one, emusks can read public profiles and tweets without an account. Each token has its own rate limit, and Twitter ties it to the IP that activated it, so a pool of tokens on different IPs spreads the load.
Logging in as a guest
import Emusks from "emusks";
const client = new Emusks();
await client.login({ type: "guest" });
const user = await client.users.getByUsername("XDevelopers");
const { tweets } = await client.users.tweets(user.id);Without tokens, emusks activates one token for you. Pass proxy to activate it and send every request through a proxy:
await client.login({ type: "guest", proxy: "socks5h://user:pass@host:1080" });Creating tokens
createGuestToken(opts?) activates one token. It returns the token, the guest_id cookies Twitter set with it, and the proxy it went through:
import { createGuestToken } from "emusks";
const token = await createGuestToken({ proxy: "http://user:pass@host:8080" });
// { token: "1976...", cookies: { guest_id: "v1%3A..." }, proxy: "http://...", createdAt: 1760000000000 }createGuestTokens(count, opts?) activates several at once, four at a time by default (concurrency). Activations that fail are skipped, so check the length of the result. It only throws when every activation fails. onToken(token, index) is called as each one arrives.
import { createGuestTokens } from "emusks";
const tokens = await createGuestTokens(10, { proxy: "http://user:pass@host:8080", concurrency: 4 });One Tor circuit per token
Set tor and every token gets its own Tor circuit, which usually means its own exit IP:
const tokens = await createGuestTokens(10, { tor: true });tor: true connects to socks5h://127.0.0.1:9050. Pass a URL for another port, such as tor: "socks5h://127.0.0.1:9150" for Tor Browser. emusks gives each token a unique SOCKS username, and Tor's default IsolateSOCKSAuth setting puts each username on a separate circuit. Two circuits can still share an exit relay, so expect a few repeated IPs in a large pool.
The token remembers its proxy, so its requests keep using the same circuit.
Using a pool
Pass several tokens to login and emusks rotates through them. When a GraphQL request comes back with HTTP 429 or 401, or with error code 88 (rate limited) or 239 (bad guest token), emusks moves to the next token and its proxy and retries, trying each token at most once per request. With a single token, emusks activates a fresh one instead.
const tokens = await createGuestTokens(8, { tor: true });
const client = new Emusks();
await client.login({ type: "guest", tokens });
for (const username of usernames) {
console.log(await client.users.getByUsername(username));
}The active token is client.auth.guestTokens[client.auth.guestIndex]. Tokens are plain objects, so you can save them to a file and pass them back to login later. Strings work too, and use the proxy option.
What works as a guest
| Works as a guest | Needs an account |
|---|---|
users.get, users.getByUsername | users.getMany, users.getManyByUsername, users.about |
users.tweets, users.highlights | users.followers, users.following, users.verifiedFollowers, users.userMedia |
tweets.get, tweets.getMany, tweets.similar | tweets.detail, tweets.likers, tweets.retweeters, tweets.editHistory |
communities.get, communities.about | communities.timeline |
trends.available | search.*, lists.*, notes.*, spaces.search, trends.explore |
jetfuel.topPosts | anything that writes |
users.replies returns an empty timeline for guests. The main endpoint serves fewer queries to guests than web: users.get, tweets.getMany, tweets.similar and communities.get fail there.
Twitter changes this list without notice, treat it as a snapshot of October 2026. The syndication API is another logged-out option for single tweets and profiles.