Twitter/X URL Regex
Matches a Twitter/X profile URL or an individual tweet (status) URL on either twitter.com or x.com, capturing the handle and optional tweet ID.
Regex Pattern
^https?:\/\/(?:www\.)?(?:twitter|x)\.com\/(\w{1,15})(?:\/status\/(\d+))?\/?$Pattern Breakdown
Hover over a token to see what it does.
| Token | Meaning |
|---|---|
| ^ | Anchors the match to the start of the string |
| https? | Matches http or https |
| :\/\/ | Literal :// scheme separator |
| (?:www\.)? | Optional www. subdomain prefix |
| (?:twitter|x)\.com\/ | Either the legacy twitter.com or current x.com host, followed by a slash |
| (\w{1,15}) | Capture group 1: the handle, 1 to 15 word characters matching Twitter's username length limit |
| (?:\/status\/(\d+))? | Optional /status/ segment with capture group 2 for the numeric tweet ID |
| \/?$ | Optional trailing slash, then end of string |
Detailed Explanation
What it does
This pattern matches both a bare profile URL like https://x.com/handle and a link to a specific tweet like https://twitter.com/handle/status/123456789, accepting either the legacy twitter.com domain or the current x.com domain. It captures the handle and, when present, the numeric tweet ID.
Why it works
The host alternation (?:twitter|x)\.com covers the platform's rebrand while keeping backward compatibility with existing links. The handle is bounded to \w{1,15}, matching Twitter/X's documented maximum username length, which helps reject non-profile paths that happen to start with a word-like segment but are actually longer, such as internal app routes. The optional /status/(\d+) group makes the tweet ID capture opt-in, so the same pattern serves both profile and tweet URLs.
Common use cases
- Validating a social media link field that accepts either the twitter.com or x.com domain
- Extracting a handle and tweet ID from a pasted link to fetch tweet details via the X API
- Normalizing links from either domain to a single canonical form during storage
- Filtering scraped URLs to isolate links to individual tweets versus profile pages
Edge cases
- Both twitter.com and x.com resolve successfully, reflecting the platform's 2023 rebrand
- A trailing slash after the handle or tweet ID is accepted because of the optional \/? before the end anchor
- Handles longer than 15 characters are rejected since \w{1,15} caps the length, matching the platform's real constraint
- Status links without a handle are not matched since the handle group is mandatory, unlike the tweet ID which is optional
- Reserved paths that aren't real handles, like /home or /search, would still technically match since this pattern doesn't maintain a reserved-word denylist
Limitations
- Does not exclude Twitter/X's reserved system routes (e.g. /home, /explore, /settings) from being treated as valid handles
- Does not validate that the numeric tweet ID corresponds to an actual existing tweet
- Does not match other X URL types such as media galleries, lists, or spaces
Interactive Tester
Edit the pattern or text below — matching runs live in your browser.
Test Cases
Editable — add your own inputs to see if they pass.
| Input | Expected | Result | |
|---|---|---|---|
| Pass | |||
| Pass | |||
| Pass | |||
| Pass | |||
| Pass | |||
| Pass | |||
| Pass |
Language Variants
Production-ready examples in 12 languages.
const twitterUrlRegex = /^https?:\/\/(?:www\.)?(?:twitter|x)\.com\/(\w{1,15})(?:\/status\/(\d+))?\/?$/;
const m = 'https://x.com/openai/status/123'.match(twitterUrlRegex);
console.log(m[1], m[2]); // 'openai' '123'Common Mistakes
Only matching twitter.com and rejecting valid x.com links after the platform's rebrand
Fix: Use a host alternation (?:twitter|x)\.com so both domains are accepted
Allowing handles of unbounded length, which lets non-profile paths slip through as false positives
Fix: Cap the handle with \w{1,15} to match Twitter/X's actual username length limit
Treating reserved routes like /home or /settings as valid handles
Fix: Maintain a denylist of reserved words and check captured handles against it after the regex match
Performance Notes
- The bounded handle quantifier \w{1,15} avoids unbounded backtracking compared to an open-ended + or *
- The optional status group only adds matching cost when a /status/ segment is actually present in the input
- Anchoring with ^ and $ avoids scanning arbitrary substrings for a match when validating a full URL string
Browser Compatibility
| Engine | Supported | Notes |
|---|---|---|
| Chrome | Yes | — |
| Firefox | Yes | — |
| Safari | Yes | — |
| Edge | Yes | — |
| Node.js | Yes | — |