Look up any X (Twitter) account by username or numeric id — no API key, no developer account, no browser, no login.
Convert a username to a user id, a user id back to a username, and pull the public profile: display name, bio, follower and following counts, tweet count, join date, avatar, banner and verification status.
from twitter_username import resolve
user = resolve("jack")
print(user.id, user.name, user.followers_count)
# 12 jack 11177316$ twitter-username jack -f id -f screen_name -f followers_count
{
"id": "12",
"screen_name": "jack",
"followers_count": 11177316
}The official X API costs money and rate-limits hard even on paid tiers. This library pulls the same public profile data straight from X, handles the plumbing for you, and returns clean Python objects. No token to manage, no monthly bill.
pip install twitter-usernameOnly requests and beautifulsoup4 are required. For SOCKS proxies:
pip install "twitter-username[socks]"Python 3.8 or newer. Pure Python — the wheel is py3-none-any, there is
nothing to compile, and no browser, JS engine or system package is involved.
Runs unchanged on Linux, macOS and Windows, and on anything else
CPython supports (BSD, Android/Termux, iOS via CPython 3.13+). On a legacy
Windows console (cp1252, cp437) the CLI switches to UTF-8 where the terminal
allows it and otherwise emits \uXXXX-escaped JSON, so emoji and CJK display
names never crash it and the output stays valid, lossless JSON.
from twitter_username import resolve, resolve_raw
resolve("jack") # by username
resolve("@jack") # leading @ is fine
resolve("https://x.com/jack") # so is a profile URL
resolve(user_id=12) # by numeric id
resolve_raw("jack") # the untouched JSON responseEach resolve() call sets itself up from scratch. A Client keeps that setup
warm, so every lookup after the first costs a single request.
from twitter_username import Client
with Client() as client:
for handle in ["jack", "elonmusk", "python"]:
user = client.resolve(handle)
print(f"{user.screen_name:12} {user.followers_count:>12,}")Populated fields only; anything X did not return stays None. The complete
untouched payload is always on .raw, so nothing is lost.
id screen_name name created_at |
identity |
description location url |
profile |
followers_count following_count tweet_count media_count favourites_count listed_count |
counts |
verified is_blue_verified protected possibly_sensitive |
flags |
profile_image_url profile_banner_url |
media |
raw |
the original response object |
Plus created_at_datetime, profile_url, profile_image_url_original and
to_dict(include_raw=False).
from twitter_username import resolve, UserNotFound, UserUnavailable, APIError
try:
user = resolve("some_handle")
except UserNotFound:
... # no such account (also covers suspended/deactivated)
except UserUnavailable as exc:
print(exc.reason)
except APIError as exc:
print(exc.status_code, exc.body)All of them subclass TwitterUsernameError.
Transport failures (proxy refused, DNS, TLS, timeout) are not wrapped —
they surface as the usual requests.RequestException subclasses, so existing
requests error handling and retry policies keep working. The CLI catches them
and prints one line instead of a traceback.
proxies accepts a single URL applied to both schemes, or a requests-style
mapping.
from twitter_username import Client, resolve
resolve("jack", proxies="http://user:pass@127.0.0.1:8080")
resolve("jack", proxies="socks5://127.0.0.1:1080") # needs [socks] extra
with Client(proxies={"http": "http://a:8080", "https": "http://b:8080"}) as c:
c.resolve("jack")The proxy is set on the session, so it covers every request the library makes.
Headers merge in layers, each one overriding the last: library defaults →
session → client → individual call. Passing None as a value removes a
header the library would otherwise send.
from twitter_username import Client
with Client(
headers={"Accept-Language": "de-DE,de;q=0.9"},
user_agent="Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) ...",
) as client:
client.resolve("jack")
client.resolve("python", headers={"Referer": "https://x.com/explore"})Pass a configured requests.Session to keep control of retries, connection
pooling, adapters and cookies. The client will not close a session it did not
create.
import requests
from requests.adapters import HTTPAdapter, Retry
from twitter_username import Client
session = requests.Session()
session.mount("https://", HTTPAdapter(max_retries=Retry(total=3, backoff_factor=1)))
with Client(session=session) as client:
client.resolve("jack")Other Client options: timeout, page_url, features, verify, cert,
trust_env, bearer, guest_token.
twitter-username jack # parsed JSON
twitter-username jack elonmusk python # batch, JSON array
twitter-username --user-id 12 # id to username
twitter-username jack --raw # full response
twitter-username jack -f id -f followers_count
twitter-username jack --compact # one JSON object per line
twitter-username jack -x socks5://127.0.0.1:1080
twitter-username jack -H 'Accept-Language: de-DE' -H 'Referer:'Exit codes: 0 ok, 1 error, 2 usage, 3 not found, 4 unavailable.
Pipe it into jq like any other tool:
twitter-username jack elonmusk --compact | jq -r '[.screen_name, .followers_count] | @tsv'pip install -e ".[dev]"
pytest # offline tests
pytest -m network # live tests over the networkThis library depends on public data whose shape X can change without notice.
Pin a version, handle BootstrapError as a signal that something upstream
moved, and open an issue if lookups start failing.
Use it for public profile data only, and respect X's terms and the law where you are. Rate-limit yourself; do not hammer it.
twitter api · x api · twitter without api key · free twitter api · twitter scraper · x scraper · twitter username to id · twitter id to username · twitter user lookup · get twitter user id · twitter profile scraper · twitter follower count · twitter user info · x user lookup · python twitter library · twitter osint · x osint · snscrape alternative · tweepy alternative · no api key · twitter data · social media scraper · twitter account checker · username checker
MIT — see the LICENSE file included in the distribution.