Metadata-Version: 2.5
Name: twitter-username
Version: 0.1.0
Summary: Resolve X (Twitter) accounts by handle or numeric id, logged out and without an API key.
Project-URL: Homepage, https://github.com/binarykernal/twitter-username
Project-URL: Repository, https://github.com/binarykernal/twitter-username
Project-URL: Issues, https://github.com/binarykernal/twitter-username/issues
Project-URL: Changelog, https://github.com/binarykernal/twitter-username/blob/main/CHANGELOG.md
Author: binarykernal
License: MIT License
        
        Copyright (c) 2026 binarykernal
        
        Permission is hereby granted, free of charge, to any person obtaining a copy
        of this software and associated documentation files (the "Software"), to deal
        in the Software without restriction, including without limitation the rights
        to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
        copies of the Software, and to permit persons to whom the Software is
        furnished to do so, subject to the following conditions:
        
        The above copyright notice and this permission notice shall be included in all
        copies or substantial portions of the Software.
        
        THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
        IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
        FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
        AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
        LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
        OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
        SOFTWARE.
License-File: LICENSE
Keywords: account-lookup,cli,follower-count,followers,free-twitter-api,id-to-username,no-api-key,osint,profile-scraper,snscrape-alternative,social-media,tweepy-alternative,twitter,twitter-api,twitter-profile,twitter-scraper,twitter-user-id,twitter-username,user-info,user-lookup,username,username-to-id,web-scraping,x,x-api,x-scraper
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Internet :: WWW/HTTP
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: Utilities
Classifier: Typing :: Typed
Requires-Python: >=3.8
Requires-Dist: beautifulsoup4>=4.9
Requires-Dist: requests>=2.25
Provides-Extra: dev
Requires-Dist: build>=1.0; extra == 'dev'
Requires-Dist: pytest>=7; extra == 'dev'
Requires-Dist: twine>=4.0; extra == 'dev'
Provides-Extra: socks
Requires-Dist: requests[socks]>=2.25; extra == 'socks'
Provides-Extra: validate
Requires-Dist: playwright>=1.40; extra == 'validate'
Description-Content-Type: text/markdown

# twitter-username

[![PyPI](https://img.shields.io/pypi/v/twitter-username.svg)](https://pypi.org/project/twitter-username/)
[![Python](https://img.shields.io/pypi/pyversions/twitter-username.svg)](https://pypi.org/project/twitter-username/)
[![License](https://img.shields.io/pypi/l/twitter-username.svg)](https://github.com/binarykernal/twitter-username/blob/main/LICENSE)

**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.

```python
from twitter_username import resolve

user = resolve("jack")
print(user.id, user.name, user.followers_count)
# 12 jack 11177316
```

```bash
$ twitter-username jack -f id -f screen_name -f followers_count
{
  "id": "12",
  "screen_name": "jack",
  "followers_count": 11177316
}
```

## Why

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.

## Install

```bash
pip install twitter-username
```

Only `requests` and `beautifulsoup4` are required. For SOCKS proxies:

```bash
pip install "twitter-username[socks]"
```

### Requirements

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.

## Usage

### One-off lookups

```python
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 response
```

### Many lookups — reuse a `Client`

Each `resolve()` call sets itself up from scratch. A `Client` keeps that setup
warm, so every lookup after the first costs a single request.

```python
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,}")
```

### The `User` object

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)`.

### Errors

```python
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

`proxies` accepts a single URL applied to both schemes, or a requests-style
mapping.

```python
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.

## Custom headers

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.

```python
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"})
```

### Bringing your own session

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.

```python
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`.

## Command line

```bash
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:

```bash
twitter-username jack elonmusk --compact | jq -r '[.screen_name, .followers_count] | @tsv'
```

## Development

```bash
pip install -e ".[dev]"
pytest                    # offline tests
pytest -m network         # live tests over the network
```

## Stability

This 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.

## Keywords

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

## License

MIT — see the `LICENSE` file included in the distribution.
