ThreadsAnswer

How to find a Threads user ID from a username

Our Threads profile route turns a username into its user ID for 1 credit. Meta's API returns an ID only for the account that logged in to your app.

4 min read

Short answer

  • A Threads profile page doesn't display the user ID, though it sits in the page source, and Meta's profile endpoint returns one only for your own account.
  • Meta's profile_lookup endpoint returns a public profile's bio and counts but no ID, and on standard access it only finds a few official Meta accounts.
  • Our Threads profile route returns the numeric ID for a public username or profile URL, 1 credit a lookup, with 100 free credits a month.
On this page

A Threads profile page doesn't display the user ID, though the number sits in the page source. Meta's profile endpoint returns an ID only for the account that logged in to your app, and its public profile lookup leaves the ID out. Our profile route takes a username or profile URL and returns the account's numeric id, the user_id our posts route takes.

Find one ID in the page source

For a single account you don't need an API. Open threads.com/@username in a browser, view the page source (Ctrl+U, or Option-Cmd-U on a Mac), and search for "user_id":". The number after it is the ID. On zuck's and mosseri's logged-out profile pages it matched the id our API returns.

What Meta's Threads API returns

Meta's Threads profile docs describe two calls. GET /me?fields=id,... returns the ID of the account that authorized your app, and no other. GET /profile_lookup?username= reads public profiles with at least 100 followers and returns name, bio, picture, verification and counts, with no id; it needs the threads_profile_discovery permission, and on standard access it finds only four official Meta accounts. Use Meta's API when the ID you need is your own.

Threads user ID with ToolzerHub

We make ToolzerHub. Our Threads API returns public Threads data as JSON with one API key. /v1/threads/profile takes a username, an @username or a full profile URL.

bash
curl "https://api.toolzerhub.com/v1/threads/profile?username=zuck" \
  -H "x-api-key: $TOOLZERHUB_API_KEY"

The ID and a few of the 25 fields in the response:

json
{
  "data": {
    "id": "63055343223",
    "pk": "63055343223",
    "username": "zuck",
    "full_name": "Mark Zuckerberg",
    "follower_count": 5751006,
    "is_verified": true,
    "text_post_app_is_private": false
  }
}

id and pk hold the same number. Pass it as user_id to /v1/threads/profile/posts to page the account's posts.

Look up many user IDs at once

The script takes a comma-separated list of usernames or profile URLs and writes a CSV with each ID, name, follower count and verified flag.

python
import csv
import os
import sys
import time

import requests

API = "https://api.toolzerhub.com/v1/threads/profile"
HEADERS = {"x-api-key": os.environ.get("TOOLZERHUB_API_KEY", "")}
FIELDS = ["input", "username", "user_id", "name", "followers", "verified", "private"]


def cell(value):
    # A leading = + - or @ would run as a formula when the CSV opens in a spreadsheet.
    return "'" + value if isinstance(value, str) and value[:1] in ("=", "+", "-", "@") else value


def lookup(username, tries=4):
    # 429 and 503 are worth a retry; the body says how long to wait.
    for attempt in range(tries):
        r = requests.get(API, params={"username": username}, headers=HEADERS, timeout=90)
        if r.status_code in (429, 503) and attempt < tries - 1:
            wait = int(((r.json().get("error") or {}).get("details") or {}).get("retryAfter") or r.headers.get("Retry-After") or 5 * (attempt + 1))
            time.sleep(min(wait, 60))
            continue
        if r.status_code == 400:  # not a valid username or profile URL
            return None
        r.raise_for_status()
        return r.json()["data"]  # None when no public profile has that name


def main(names, out="threads_user_ids.csv"):
    found = 0
    with open(out, "w", newline="", encoding="utf-8") as f:
        writer = csv.DictWriter(f, fieldnames=FIELDS)
        writer.writeheader()
        for name in [n.strip() for n in names.split(",") if n.strip()]:
            p = lookup(name) or {}
            found += bool(p)
            writer.writerow({
                "input": cell(name), "username": p.get("username"), "user_id": p.get("id"),
                "name": cell(p.get("full_name")), "followers": p.get("follower_count"),
                "verified": p.get("is_verified"), "private": p.get("text_post_app_is_private"),
            })
            print(name, "->", p.get("id") or "not found")
    print(f"found {found} user IDs, saved to {out}")


if __name__ == "__main__":
    if not HEADERS["x-api-key"] or len(sys.argv) < 2:
        sys.exit("usage: TOOLZERHUB_API_KEY=... python threads_user_ids.py zuck,@mosseri,https://www.threads.com/@nasa")
    main(*sys.argv[1:])
bash
export TOOLZERHUB_API_KEY=your_key
python threads_user_ids.py "zuck,@mosseri,https://www.threads.com/@nasa,threads,natgeo,instagram,meta"

What the lookups returned

Seven inputs gave seven IDs in 15 seconds.

Username User ID Followers
zuck 63055343223 5,751,006
mosseri 63482099442 1,054,331
nasa 28829152388 12,788,017
threads 63082166531 6,961,009
natgeo 63269174602 18,411,736
instagram 63404918397 38,268,622
meta 63053551787 1,870,996

All seven IDs came back the same on an earlier run, while follower counts moved by 3 to 33. Mosseri's ID returned 16 posts on the first page of /v1/threads/profile/posts.

What it costs

Each lookup is 1 credit, so the 100 free credits a month cover 100 usernames. $19 buys 10,000 credits that never expire, and plans for higher volume cover larger lists. Set your key and your first ID is one request away.

To read the account's posts next, see how to view Threads without an account; for Meta's other limits, see the Threads API guide; for the same job on Instagram, see Instagram API get user ID.

We are not affiliated with Meta or Threads.

Get this data from your own code

The Threads API returns it as JSON with one x-api-key header. 100 free credits monthly.