twitterapi.io is an independent third-party service. Not affiliated with X Corp.

Blogtwitter username lookup

Twitter (X) Username Lookup — A Developer's API Reference

By Alex Chen3 min read

Username → user object resolution is one of the most common API calls in any Twitter (X) workflow — enrichment pipelines, user-page rendering, ID-mapping for stored handles, competitor-tracking watchlists. This reference walks the single-lookup + batch patterns with runnable Python + honest cost math.

Pricing references URL-cited to each provider.

01 — Section

Why username lookup matters

X's internal ID for an account is a numeric string (like 44196397 for @elonmusk). Most API operations use the numeric ID; user-visible handles are strings. Anything that stores handles + queries data needs a resolver from handle → numeric ID + profile data.

Common use cases: user-profile page rendering, converting a handle list to IDs for subsequent API calls, enrichment (given handle, retrieve bio + follower count), watchlist validation (does this handle still exist? still verified?).

02 — Section

Single lookup — twitterapi.io

Auth via X-API-Key. Pass userName parameter. Returns 404 if the handle doesn't exist.

Pricing per twitterapi.io/pricing: $0.00018 per lookup.

python
import os, requests

HEADERS = {"X-API-Key": os.environ["TWITTERAPI_IO_KEY"]}
BASE = "https://api.twitterapi.io"

def lookup(handle: str) -> dict | None:
    r = requests.get(
        f"{BASE}/twitter/user/info",
        headers=HEADERS, params={"userName": handle}, timeout=10,
    )
    if r.status_code == 404: return None
    r.raise_for_status()
    return r.json()

user = lookup("nasa")
if user:
    print(f"@{user['userName']} → id={user['id']}, followers={user['followers_count']:,}")
else:
    print("handle not found")
03 — Section

Single lookup — X official

Auth via bearer token from X Developer Console.

Pricing per docs.x.com/x-api/getting-started/pricing: $0.010 per lookup.

python
# pip install tweepy
import tweepy

client = tweepy.Client(bearer_token="YOUR_X_BEARER")

def lookup_x(handle: str):
    try:
        user = client.get_user(username=handle, user_fields=["public_metrics", "description", "verified"])
        return user.data
    except tweepy.NotFound:
        return None

u = lookup_x("nasa")
if u: print(f"@{u.username} → id={u.id}, followers={u.public_metrics['followers_count']:,}")
04 — Section

Batch lookup — 100 handles at once

For workflows polling many usernames, single-lookup loop is inefficient. Batch endpoint patterns:

X official: /2/users/by?usernames=handle1,handle2,...,handle100 (up to 100 per call).

twitterapi.io: single-lookup loop; if you need batch performance, parallelize the calls (concurrent HTTP fine given per-key throughput headroom).

For very large watchlists (10K+ handles), parallel single-lookup at twitterapi.io still lands single-digit-dollars total. X official 100-per-batch reduces API-call count but per-user cost is unchanged.

python
# Batch lookup via concurrent single-calls (twitterapi.io)
import os, requests
from concurrent.futures import ThreadPoolExecutor

HEADERS = {"X-API-Key": os.environ["TWITTERAPI_IO_KEY"]}

def lookup(handle: str) -> dict | None:
    r = requests.get(
        "https://api.twitterapi.io/twitter/user/info",
        headers=HEADERS, params={"userName": handle}, timeout=10,
    )
    if r.status_code == 404: return None
    r.raise_for_status()
    return r.json()

HANDLES = ["nasa", "github", "vercel", "anthropic", "openai"] * 20  # 100 handles

with ThreadPoolExecutor(max_workers=10) as ex:
    results = list(ex.map(lookup, HANDLES))

resolved = [r for r in results if r]
print(f"resolved {len(resolved)}/{len(HANDLES)}")
# Cost per twitterapi.io/pricing:
#   100 lookups × $0.00018 = $0.018 for the full batch
05 — Section

Side-by-side — 2 lookup paths

Dimensiontwitterapi.ioX official
Endpoint/twitter/user/info?userName=/2/users/by/username/
Batch endpointparallel single-calls/2/users/by?usernames=... (100 max)
Per-lookup cost$0.00018 (twitterapi.io/pricing)$0.010 (docs.x.com)
AuthX-API-KeyBearer + X Dev Console
404 on missingreturns 404 statusreturns 404 status
Best forany lookup workflow, cost-consciousX-native, already on Dev Console

Per-lookup cost ratio ~55× makes twitterapi.io the default for any polling workflow across many usernames.

06 — Section

Common lookup workflows

Watchlist validation: nightly cron pulls current status of N handles. Detect suspensions / deletions (404) + verification changes.

ID resolution for downstream API calls: input is a handle list, downstream calls need numeric IDs. One lookup pass → build handle→ID map → downstream calls use IDs.

Enrichment for existing user records: your database has handles + you want current follower counts / bio. Batch lookup → merge back to your records.

Handle-exists check: before signup form validates or user-tagging feature accepts a handle, quick lookup confirms account exists.

Bot / spam detection: lookup + inspect follower_count / following_count / created_at / description patterns. Very low follower + high following + new account + generic bio = likely spam.

07 — Section

Edge cases

Case sensitivity: handles are case-insensitive at lookup — @NASA, @nasa, @Nasa all resolve to the same account. The API returns the account's canonical case.

Renames: handles can change. Stored handles in your database may go stale. If lookup returns different id than expected for a known handle, the handle was reassigned to a new account (the old account changed handle or was deleted + handle re-registered).

Rate-limit on batches: parallel calls at 10-20 workers is safe for twitterapi.io. Higher can bump into per-key throughput ceilings.

Numeric-only handles: not supported — X handles are alphanumeric + underscore. If your input list has pure-numeric strings they're not valid handles.

python
# Practical example: watchlist validation + enrichment nightly cron.
import os, requests, json
from concurrent.futures import ThreadPoolExecutor
from pathlib import Path
from datetime import datetime, timezone

HEADERS = {"X-API-Key": os.environ["TWITTERAPI_IO_KEY"]}
BASE = "https://api.twitterapi.io"

WATCHLIST = Path("watchlist.txt").read_text().strip().split("\n") if Path("watchlist.txt").exists() else [
    "nasa", "github", "vercel", "anthropic", "openai", "elonmusk",
]

def lookup(handle: str) -> tuple[str, dict | None]:
    r = requests.get(f"{BASE}/twitter/user/info", headers=HEADERS, params={"userName": handle}, timeout=10)
    if r.status_code == 404: return (handle, None)
    r.raise_for_status()
    return (handle, r.json())

now = datetime.now(timezone.utc).isoformat()
results = []
with ThreadPoolExecutor(max_workers=10) as ex:
    for handle, user in ex.map(lookup, WATCHLIST):
        if user is None:
            results.append({"captured_at": now, "handle": handle, "status": "NOT_FOUND"})
        else:
            results.append({
                "captured_at": now,
                "handle": user["userName"],
                "id": user.get("id"),
                "followers_count": user.get("followers_count", 0),
                "verified": user.get("verified", False),
                "status": "OK",
            })

out = Path("watchlist_snapshot.jsonl")
with open(out, "a") as f:
    for r in results:
        f.write(json.dumps(r) + "\n")

n_ok = sum(1 for r in results if r["status"] == "OK")
n_missing = len(results) - n_ok
print(f"snapshot: {n_ok} live, {n_missing} not found")
# Cost per twitterapi.io/pricing:
#   len(WATCHLIST) × $0.00018 per snapshot
#   Daily × 30 = ~$0.02-0.20/month for typical watchlists
08 — Questions

Questions readers ask

Can I look up multiple usernames in one call?

twitterapi.io: single-lookup per call; use concurrent parallel calls for batch. X official: /2/users/by supports up to 100 usernames per call. For most workloads, twitterapi.io concurrent still ends up cheaper + faster per completed lookup.

What happens if the account was suspended or deleted?

API returns 404. Handle in your data with a None return or explicit 'not found' marker. For long-standing watchlists, periodically re-check — accounts get suspended, deleted, or renamed regularly.

How do I detect a handle rename?

Compare stored id vs returned id for the same handle over time. Same handle string with a different numeric ID = the handle was reassigned. The old account either changed handle or was deleted + the handle re-registered.

Can I do lookups without authentication?

Both providers require auth. twitterapi.io needs X-API-Key; X official needs bearer. No anonymous public API for user lookup exists in 2026.

What about looking up by numeric ID instead of username?

Both providers support ID-based lookup. twitterapi.io: /twitter/user/info?userId=. X official: /2/users/. Same pricing structure per provider.

Are usernames case-sensitive when I make the API call?

No — both APIs are case-insensitive at query. ?userName=NASA and ?userName=nasa resolve to the same account. The returned userName field uses the account's canonical case.

09 — Further reading

Continue

Sources & further reading
More from this series
Build it

Stop reading. Start building.

Starter credits cover real testing on real data. Google sign-in, no card, no application queue.

Get an API key
    Twitter (X) Username Lookup — API Reference | TwitterAPI.io