Back to Blog
Guide

How to Find the User ID for Any Instagram, TikTok or X Account

October 14, 2026
9 min read
S
By SociaVault Team
user IDInstagramTikTokTwitterXhandles

How to Find the User ID for Any Instagram, TikTok or X Account

Somebody on your tracking list rebrands. Their old handle stops working, and your dashboard quietly marks them as gone. You look them up by hand and there they are: same person, same followers, new name.

Renamed accounts are one of the most common reasons a lookup comes back "not found" (we went through the other reasons here). And they're entirely avoidable. A handle is a label the owner can change whenever they like. Underneath it, every platform keeps a user ID that's assigned once and never moves. Store that, and a rename becomes a non-event.

Here's where the ID lives on Instagram, TikTok and X, how to get from an ID back to the current handle, and the one platform where you can't.

Where the ID lives

PlatformLook it up withID fieldExample
Instagram/instagram/profile?handle=nasauser.id528817151
TikTok/tiktok/profile?handle=mrbeastuser.id, plus user.secUid6614519312189947909
X/twitter/profile?handle=nasarest_id11348282

YouTube works the same way with a channel ID, but its URLs come in enough flavours to deserve their own guide: finding a YouTube channel ID from any URL.

On Instagram, the user object sits a level down inside the response's data, so read it defensively. The code further down handles both shapes.

X has a decoy field

An X profile response has two fields that look like IDs, and the obvious one is the wrong one. There's an id that looks like VXNlcjoyMjE4MzgzNDk=. Decode it from base64 and you get User:221838349, an internal label wrapped around the real number. The value you want is rest_id, which here would be 221838349. Store rest_id and ignore id.

TikTok has two IDs

TikTok gives you user.id, a plain number, and user.secUid, a long string that starts with MS4wLjABAAAA. Both are stable. Keep both, because different tools ask for different ones. Videos carry the same pair on their author object as uid and sec_uid, which means you can collect IDs from a video list without a separate profile call for each creator.

Keep every ID as a string

mrbeast's TikTok ID is 6614519312189947909. That's bigger than the largest whole number JavaScript can hold exactly, 9,007,199,254,740,991. Convert it to a number and the last few digits quietly change. No error. You're just storing the ID of nobody in particular.

You never need to do maths with an ID. Keep it as a string from the moment it arrives, in your code and in your database. It costs nothing and removes a whole category of bug.

Going back from an ID to the current handle

This is where storing IDs pays off. When a saved handle stops working, the ID gets you the new one.

Instagram. /instagram/basic-profile?userId=528817151 returns the account, current username included. We ran it with NASA's ID and got nasa back.

X. There's no profile-by-ID lookup, but there's a side door. /twitter/user-tweets-all?user_id=11348282 returns the account's tweets, and every tweet carries its author. NASA's ID came back with the author's legacy.screen_name set to NASA. It takes one request.

TikTok. You can't. The TikTok endpoints want a handle. When we called /tiktok/videos with only a user_id, it came back with "TikTok handle is required." The ID still earns its keep, though. When you track down a likely new handle some other way, look it up and compare user.id. If the numbers match, it's the same account. If they don't, you've found someone else.

Why a working handle isn't proof

This catches people the other way round. Once an account changes its name, the old handle doesn't stay retired. Someone else can claim it.

So picture a brand that renamed last spring. Its old handle still resolves, still returns a profile, still has followers. It's just a different account now, run by a stranger. If your tracker keys on handles, it'll happily start recording a stranger's numbers under the brand's name, and nothing will look broken.

Comparing IDs catches that instantly. Comparing handles never will.

The code

Two functions. One captures an account the first time you see it. The other recovers the current handle from a stored ID.

const API = "https://api.sociavault.com/v1/scrape";
const KEY = process.env.SOCIAVAULT_API_KEY;
const str = (v) => (v === null || v === undefined ? null : String(v));

async function call(path, params) {
  const res = await fetch(`${API}/${path}?${new URLSearchParams(params)}`, {
    headers: { "x-api-key": KEY },
  });
  const body = await res.json();
  if (body?.error) throw new Error(body.error);
  return body.data ?? {};
}

// First sighting: store the ID next to the handle, both as strings.
async function snapshot(platform, handle) {
  const h = String(handle).trim().replace(/^@/, "");
  if (platform === "instagram") {
    const d = await call("instagram/profile", { handle: h });
    const user = d?.data?.user ?? d?.user ?? {};
    return { platform, id: str(user.id), handle: user.username ?? h };
  }
  if (platform === "tiktok") {
    const d = await call("tiktok/profile", { handle: h });
    return { platform, id: str(d?.user?.id), secUid: d?.user?.secUid ?? null, handle: d?.user?.uniqueId ?? h };
  }
  if (platform === "twitter") {
    const d = await call("twitter/profile", { handle: h });
    return { platform, id: str(d?.rest_id), handle: d?.legacy?.screen_name ?? h };
  }
  throw new Error(`unsupported platform: ${platform}`);
}

// Later, when the stored handle stops working.
async function currentHandle(platform, id) {
  if (platform === "instagram") {
    const d = await call("instagram/basic-profile", { userId: id });
    return d?.username ?? d?.user?.username ?? null;
  }
  if (platform === "twitter") {
    const d = await call("twitter/user-tweets-all", { user_id: id });
    // Walk the timeline until we reach the author object with this ID.
    const stack = [d];
    while (stack.length) {
      const node = stack.pop();
      if (!node || typeof node !== "object") continue;
      if (node.__typename === "User" && node.rest_id === id) {
        return node.core?.screen_name ?? node.legacy?.screen_name ?? null;
      }
      for (const v of Object.values(node)) if (v && typeof v === "object") stack.push(v);
    }
    return null; // no tweets to read an author from
  }
  return null; // TikTok has no lookup by ID
}

And in Python:

import os, requests

API = "https://api.sociavault.com/v1/scrape"
HEADERS = {"x-api-key": os.environ["SOCIAVAULT_API_KEY"]}

def as_str(v):
    return None if v is None else str(v)

def call(path, **params):
    body = requests.get(f"{API}/{path}", params=params, headers=HEADERS, timeout=90).json()
    if body.get("error"):
        raise RuntimeError(body["error"])
    return body.get("data") or {}

def snapshot(platform, handle):
    h = str(handle).strip().lstrip("@")
    if platform == "instagram":
        d = call("instagram/profile", handle=h)
        user = (d.get("data") or {}).get("user") or d.get("user") or {}
        return {"platform": platform, "id": as_str(user.get("id")), "handle": user.get("username", h)}
    if platform == "tiktok":
        user = call("tiktok/profile", handle=h).get("user") or {}
        return {"platform": platform, "id": as_str(user.get("id")),
                "sec_uid": user.get("secUid"), "handle": user.get("uniqueId", h)}
    if platform == "twitter":
        d = call("twitter/profile", handle=h)
        return {"platform": platform, "id": as_str(d.get("rest_id")),
                "handle": (d.get("legacy") or {}).get("screen_name", h)}
    raise ValueError(f"unsupported platform: {platform}")

def current_handle(platform, user_id):
    if platform == "instagram":
        d = call("instagram/basic-profile", userId=user_id)
        return d.get("username") or (d.get("user") or {}).get("username")
    if platform == "twitter":
        stack = [call("twitter/user-tweets-all", user_id=user_id)]
        while stack:
            node = stack.pop()
            if isinstance(node, dict):
                if node.get("__typename") == "User" and node.get("rest_id") == user_id:
                    return (node.get("core") or {}).get("screen_name") or (node.get("legacy") or {}).get("screen_name")
                stack.extend(v for v in node.values() if isinstance(v, (dict, list)))
            elif isinstance(node, list):
                stack.extend(node)
        return None
    return None  # TikTok has no lookup by ID

How we'd lay out the table

Make the ID the key and the handle just another column:

  • platform and account_id together as the primary key, account_id stored as text
  • handle, which you update whenever it changes
  • handle_checked_at, so you know how stale the handle might be

When a lookup by handle fails, run currentHandle with the stored ID, update the row, and carry on. Your history stays attached to the right account the whole time, because it was never attached to the handle in the first place. If you're still choosing which account to track in the first place, finding the official Instagram account helps you avoid fan pages and lookalikes.

Where this stops working

  • TikTok has no reverse lookup. You need the new handle from somewhere else. The ID only confirms it.
  • The X side door needs tweets. An account with nothing visible on its timeline gives you no author object to read.
  • Deleted and suspended accounts are gone. An ID can't bring back an account that no longer exists.
  • Private accounts limit what you see. The ID still identifies them, but there's little public data behind it.
  • IDs only help if you saved them early. If all you ever stored was handles, there's nothing to recover from after a rename.

Frequently Asked Questions

How do I find an Instagram user ID from a username?

Look up the profile and read the user's id field. With our API that's /instagram/profile?handle= followed by the username. NASA's Instagram ID, for example, is 528817151.

How do I find a Twitter (X) user ID?

Look up the profile and read rest_id. Ignore the id field: it's a base64 string that decodes to something like User:221838349, not the plain ID.

Can I find a username from an Instagram user ID?

Yes. /instagram/basic-profile?userId= returns the account behind an ID, including its current username. It's the easiest way to recover an account after a rename.

What's the difference between TikTok's user ID and secUid?

Both identify the same account. user.id is a long number, and secUid is a longer string starting MS4wLjABAAAA. Different tools ask for different ones, so store both.

Do user IDs ever change?

Not in normal use. The handle can change as often as the owner likes, but the user ID stays fixed for the life of the account. That's why it makes the better key.

Why did my user ID change after I parsed the JSON?

It was probably converted to a number. IDs like TikTok's run past the largest integer JavaScript can store exactly, so the last digits get rounded. Keep IDs as strings throughout.


Building a list you'll keep for months? Sign up for 50 free credits and snapshot your accounts' IDs today, while their current handles still work.

Found this helpful?

Share it with others who might benefit

Ready to Try SociaVault?

Start extracting social media data with our powerful API. No credit card required.