Which Facebook URL Formats Contain an ID, and Which Don't?

Published Updated
A reference table of every common Facebook URL pattern, whether it carries a numeric ID, and what to do with the ones that hide it behind a name.

Facebook URLs containing profile.php?id=, /groups/NUMBER, /pages/Name/NUMBER or story_fbid= expose a numeric ID directly. Vanity URLs such as facebook.com/name, slug-based group URLs, and anything wrapped in a pfbid token or a share link do not. Those require resolution.

If you are writing a parser that accepts Facebook URLs, this distinction is the whole job. Get the pattern table right and most of your input handling falls out of it. Get it wrong and you will discover the gaps one support ticket at a time.

Which Facebook URL formats expose the ID directly?

Four patterns put the number in plain sight. These are the easy cases and you should handle them before reaching for any lookup.

The first is facebook.com/profile.php?id=100012345678901. This is a personal profile that has not claimed a vanity username, and the ID sits in the query string ready to read. It is the most convenient Facebook URL format there is, which is slightly ironic given that it is also the ugliest.

The second is facebook.com/groups/123456789012345, a group that has not set a custom username. The path segment after /groups/ is the group ID.

The third is the older Page form, facebook.com/pages/Some-Page-Name/123456789012345, where the trailing path segment is the Page ID. You see this less than you used to, but it still turns up in older data and in links that have been sitting in documents for a while.

The fourth is the legacy permalink form, facebook.com/permalink.php?story_fbid=987654321&id=123456789. This one is generous: story_fbid identifies the post and id identifies the account that posted it. Two useful numbers from one URL. Facebook has largely moved away from serving this format, but links in the wild persist.

Which formats hide the ID?

More than expose it, unfortunately, and the hidden cases are the ones your users will paste most often because they are the ones Facebook shows them.

Vanity URLs are the big one. facebook.com/cocacola contains no number at all. Worse, it is ambiguous as to type: Facebook draws usernames for profiles and Pages from the same namespace, so the URL shape cannot tell you whether you are looking at a personal account or a brand Page. You have to resolve it or visit it.

Slug-based group URLs, such as facebook.com/groups/coffeelovers, work the same way. The custom username replaced the ID rather than sitting alongside it.

Then there is pfbid, which deserves its own paragraph. Facebook now wraps many post permalinks in an opaque token, giving URLs like facebook.com/permalink/pfbid0A1b2C3.... Community analysis has not produced a reliable public method for decoding these back into numeric post IDs, and third-party tools generally treat them as opaque strings they cannot resolve. If you are holding a pfbid, assume you cannot get a number out of it. Plan your pipeline accordingly rather than hoping for a workaround.

Share links are the final category and the most common source of confusion. A shortened fb.me link, or a wrapped share URL, hides the destination entirely. Your parser sees a URL that reveals nothing, and a lookup against it fails in a way that looks like the target is private.

What does the full pattern reference look like?

Here is the table to keep next to your parser.

URL patternID present?Object typeWhere the ID is
/profile.php?id=NUMBERYesProfileid query parameter
/groups/NUMBERYesGroupPath segment after /groups/
/pages/Name/NUMBERYesPageFinal path segment
/permalink.php?story_fbid=A&id=BYesPost + accountBoth query parameters
/groups/NUMBER/posts/NUMBERYesGroup + postFirst number is the group
/vanitynameNoProfile or Page, ambiguousRequires resolution
/groups/vanity-slugNoGroupRequires resolution
/vanityname/posts/NUMBERPartlyPostPost number only, account hidden
pfbid... in any positionNoPostOpaque, not publicly decodable
fb.me/... or wrapped share linkNoUnknownExpand the link first
/watch/?v=NUMBERYesVideov query parameter
m.facebook.com/... variantsSame as desktopVariesMobile host, same path rules

The row worth a second look is /vanityname/posts/NUMBER. It gives you a post ID but not the account ID, because the account is identified by name. Half a useful URL. If you need the account ID you still have to resolve the vanity segment.

How should a parser handle these cases?

Order your checks from cheapest to most expensive, and normalise before you parse. A few rules cover most of it.

Normalise the host first. Facebook serves the same content on several hostnames, including the m. mobile subdomain, web.facebook.com, and locale subdomains. Collapse them to a canonical host before pattern matching, or write every pattern three times.

Strip tracking parameters next. Real-world Facebook URLs arrive carrying ?ref=, ?mibextid=, ?__cft__ and a long tail of similar additions. Keep the parameters you need, id, story_fbid, v, and discard the rest. A naive regex that does not account for query clutter will match in testing and fail on the first URL a real user pastes.

Then match the ID-bearing patterns and extract. Do the string handling carefully: Facebook IDs run to sixteen digits or more, which exceeds the safe integer range in JavaScript and the range of a 32-bit integer column. Capture the digits as a string and keep them as a string. Parse one as a number and you can get back a value that is close but subtly wrong, with no error anywhere to tell you.

Finally, route what is left. Share links need expanding, which the share link expander handles by recovering the original destination URL. Vanity URLs need resolving, which is what the Facebook ID finder does for public profiles, Pages and groups. And pfbid strings need rejecting with a clear message, because stringing the user along with a retry loop on something unresolvable is worse than telling them.

Why does the URL format vary so much in the first place?

Accumulated history, mostly. Facebook has been running for two decades and has rarely broken old links, so every URL scheme it has ever used is still partially in circulation. The profile.php?id= form predates vanity usernames. The /pages/Name/ID form predates the current Page URL scheme. permalink.php predates the current post routing.

Layered on top of that is a deliberate shift toward opaque identifiers. The move to pfbid tokens for post links took the platform in the opposite direction from clean numeric URLs, and the reasoning behind it has never been documented publicly in detail. Community discussion has produced theories rather than answers. What matters for your code is the consequence: newer Facebook URLs are less likely to carry a readable ID than older ones, and that trend has not reversed.

So plan for resolution as the normal path rather than the exception. A parser built on the assumption that URLs contain IDs will work on your historical test data and struggle with whatever users paste next year.

Do other platforms put IDs in URLs?

Rarely, and the pattern across platforms is consistent: the public URL carries a human-readable handle while the internal ID stays internal. Facebook's ID-bearing formats are the exception among social platforms, not the norm.

Instagram URLs contain a username and never the numeric user ID, so Graph API work there always begins with a resolution step. TikTok profile URLs show an @handle, and TikTok complicates matters further by maintaining both a numeric UID and a separate opaque sec_uid string that many endpoints require instead. YouTube is the one platform that sometimes gives you the ID in the URL, because a /channel/UC... path contains the channel ID outright, though handle-based and custom URLs do not. X profile URLs show the handle only.

If your parser accepts URLs from more than one platform, each needs its own pattern table. The relevant lookups are Instagram user ID, TikTok user ID, YouTube channel ID and X user ID, and the rules differ enough that a shared code path is usually a mistake.

Frequently asked questions

Can a pfbid string be converted into a numeric post ID?

Not reliably through any public method. Community analysis has not produced a dependable decoding approach, and third-party tools generally treat pfbid values as opaque strings they cannot resolve. If your pipeline needs numeric post IDs, capture them at a point where Facebook still provides them rather than planning to decode tokens later.

Is a vanity URL for a profile or a Page?

You cannot tell from the URL. Facebook allocates usernames for profiles and Pages from the same namespace, so facebook.com/somename could be either. Resolving the URL tells you the object type along with the ID, which is one reason to store the type alongside the number rather than keeping a column of bare digits.

Why does my regex fail on real Facebook URLs?

Usually tracking parameters or an unexpected host. Live URLs arrive with ?ref=, ?mibextid= and similar appended, and Facebook serves the same content on mobile, locale and regional subdomains. Normalise the host and strip unknown query parameters before matching, rather than trying to write one pattern that tolerates everything.

Do mobile Facebook URLs follow different rules?

The path and query conventions are the same; only the host differs. An m.facebook.com URL carries its ID in the same place a desktop URL would. Normalise the hostname to a canonical form first and the rest of your pattern table applies unchanged, which saves maintaining parallel sets of patterns.

Should I store the Facebook ID as a number or a string?

A string, always. IDs exceeding sixteen digits pass the safe integer limit in JavaScript and the range of a 32-bit integer column, and the resulting precision loss is silent: the parse succeeds and the value is quietly wrong. Capture digits as text, store as text, and compare as text throughout.

What should my parser do with a share link?

Expand it before anything else, because a share link reveals neither the ID nor the object type. Recover the original destination URL, then run your normal pattern matching against that. Attempting an ID lookup on an unexpanded share link fails in a way that looks like a privacy restriction, which sends you debugging the wrong problem.