Resolving ids
Usernames to ids, shortcodes to pks, share links to reels.
Four identifier types show up in Instagram URLs, and each needs a different move to become something you can fetch. This page is the whole set.
Username → user id
Everything except the lookup itself is addressed by numeric id.
GET /users/username/instagram
# -> { "pk": "25025320", "username": "instagram", ... }Take pk and use it everywhere: /users/25025320/followers,
/users/25025320/stories, and so on.
Cache the id. The lookup is billed at double because it costs two Instagram requests — a typeahead resolve, then the profile fetch. Every subsequent call by id is single-price. At any volume this is the single biggest saving available to you.
Usernames are not stable — people rename accounts, and the id survives that while the handle does not. Storing the id is also the more correct choice, not just the cheaper one.
If you want candidates rather than one exact account, use
GET /search/users instead. The username endpoint
verifies the match and returns 404 on a near-miss.
Profile URL → user id
There is no URL-based profile lookup. Take the handle out of the path yourself:
import re
def username_from_url(url: str) -> str | None:
m = re.match(r"https?://(?:www\.)?instagram\.com/([A-Za-z0-9._]+)", url)
return m.group(1) if m else NoneThen resolve it as above.
Post URL → post
/posts/{id} accepts the shortcode directly, so a post URL needs nothing more
than a substring:
def shortcode_from_url(url: str) -> str | None:
m = re.search(r"instagram\.com/(?:p|reel|tv)/([A-Za-z0-9_-]+)", url)
return m.group(1) if m else NoneGET /posts/B4XpqViUFUI/p/, /reel/ and /tv/ all carry the same kind of code.
Shortcode ⇄ pk
The two are interconvertible — the shortcode is base64 of the pk over
Instagram's alphabet. GET /resolve/media does it for free,
with no Instagram request:
GET /resolve/media?code=B4XpqViUFUI
# -> { "pk": "2168384974851429640", "code": "B4XpqViUFUI" }You rarely need it, since /posts/{id} takes either form. It earns its keep
when normalising ids before storing them, so the same post does not end up in
your database twice under two spellings.
Some media endpoints need the composite <pk>_<owner_id> form. Where
that applies we resolve the owner for you — pass the bare id.
Share link → reel
A /s/ link is Instagram's opaque share format, used for stories and
highlights. Resolve it through
GET /oembed:
GET /oembed?url=https://instagram.com/s/aGlnaGxpZ2h0OjE4MDI...
# -> { "reel_id": "highlight:1802...", "author_id": "25025320", "can_view": true }Then fetch by the reel_id you got back — highlight: prefixed ids go to
/highlights/{id}, a bare user id goes to
/stories/{id}.
/oembed is free.
Quick reference
| You have | You want | Do this |
|---|---|---|
| Username | User id | GET /users/username/{username} → pk. Cache it. |
| Profile URL | User id | Regex the handle, then as above. |
| Post URL | Post | Regex the shortcode → GET /posts/{code} |
| Shortcode | pk | GET /resolve/media?code= — free |
| pk | Shortcode | GET /resolve/media?pk= — free |
/s/ share link | Reel | GET /oembed?url= → reel_id — free |
| Audio id | Reels using it | GET /audio/{id}/medias |
| Location id | Its media | GET /locations/{id}/recent |