- **Write-op coverage (2026-04-19):** all 12 write ops verified PASS end-to-end (`likePost`, `unlikePost`, `savePost`, `unsavePost`, `followUser`, `unfollowUser`, `muteUser`, `unmuteUser`, `blockUser`, `unblockUser`, `createComment`, `deleteComment`). `createComment`/`deleteComment` chain via `${prev.createComment.id}` against a low-traffic target post — high-profile accounts (e.g. `@instagram`) trigger spam-filter shadow-deletes that 404 the immediate delete.
Resources
7Install
npx skillscat add imoonkey/openweb/src-sites-instagram Install via the SkillsCat registry.
Overview
Social media platform (Meta). Photo/video sharing, stories, reels.
Workflows
Look up a user profile
getUserProfile(username)→ user info withid, bio, follower/following counts
Browse a user's posts (by username)
getUserPosts(username, count)→ posts withpk,code, captions, like counts, user infogetUserPosts(username, count, max_id)→ next page (cursor fromnext_max_id)
Browse a user's posts (by ID)
getUserProfile(username)→idgetFeed(id, count)→ posts withpk,code, captions, like countsgetFeed(id, count, max_id)→ next page (cursor fromnext_max_id)
View post comments
getPostComments(id)→ comments with text, author info, like countsidis the numeric PK fromgetFeedorgetUserPostsitems (items[].pk)
getPostComments(id, min_id)→ next page (cursor fromnext_min_id)
View a specific post
getPost(id)→ media detail with caption, likes, comments, media URLsidis the numeric PK fromgetFeeditems (items[].pk)
View a user's stories
getUserProfile(username)→idgetStories(id)→ current stories viareelobject (null if no active stories)
Like a post
getFeed(id, count)orgetUserPosts(username, count)→items[].pklikePost(id=items[].pk)→ status
Unlike a post
getFeed(id, count)orgetUserPosts(username, count)→items[].pkunlikePost(id=items[].pk)→ status
Follow a user
getUserProfile(username)→data.user.idfollowUser(id=data.user.id)→ friendship_status (following/outgoing_request)
Unfollow a user
getUserProfile(username)→data.user.idunfollowUser(id=data.user.id)→ friendship_status
Save a post
getFeed(id, count)orgetUserPosts(username, count)→items[].pksavePost(id=items[].pk)→ status
Unsave a post
getFeed(id, count)orgetUserPosts(username, count)→items[].pkunsavePost(id=items[].pk)→ status
Comment on a post
getFeed(id, count)orgetUserPosts(username, count)→items[].pkcreateComment(id=items[].pk, comment_text)→ responseid(the new comment's pk)
Delete a comment
- Either chain off
createComment→id, orgetPostComments(id=items[].pk)→comments[].pk deleteComment(media_id=items[].pk, comment_id=createComment.id | comments[].pk)→{status: "ok"}
Verify fixtures pair these as
order:1/order:2withcomment_id=${prev.createComment.id}. Use a low-traffic target post (the verify fixture targets @wangxinyu926) —"test"placeholders) since IG comments are public.
Block a user
getUserProfile(username)→data.user.idblockUser(id=data.user.id)→ friendship_status
Unblock a user
getUserProfile(username)→data.user.idunblockUser(id=data.user.id)→ friendship_status
Mute a user
getUserProfile(username)→data.user.idmuteUser(id=data.user.id)→ status (hides posts + stories)
Unmute a user
getUserProfile(username)→data.user.idunmuteUser(id=data.user.id)→ status
Browse Explore page
getExplore()→ trending posts gridgetExplore(max_id)→ next page
View followers / following
getUserProfile(username)→idgetFollowers(id, count)→ follower list with usernames, verification statusgetFollowing(id, count)→ following list
View a user's Reels
getUserProfile(username)→idgetReels(id, count)→ reels with play counts, captions
View notifications
getNotifications()→ activity feed (likes, comments, follows, mentions)
Search for users
searchUsers(query)→ user list with usernames, full names, verification status
Operations
| Operation | Intent | Key Input | Key Output | Notes |
|---|---|---|---|---|
| getUserProfile | view user profile | username | id, biography, follower/following counts, is_verified | entry point |
| getUserPosts | browse posts by username | username | posts with pk, code, caption, like_count, user info | adapter; paginated via next_max_id |
| getPost | view post detail | id (numeric PK) ← getFeed items[].pk | caption, like_count, comment_count, media URLs | — |
| getFeed | browse user posts by ID | id (user ID) ← getUserProfile data.user.id | posts with pk, code, caption, like_count | paginated via next_max_id |
| getPostComments | view post comments | id (numeric PK) ← getFeed items[].pk | comments with text, author, like counts | paginated via next_min_id |
| getStories | view user stories | id (user ID) ← getUserProfile data.user.id | reel with story items, media URLs, expiration times | null reel if no active stories |
| likePost | like a post | id (numeric PK) ← getFeed items[].pk | status | write; CSRF |
| unlikePost | unlike a post | id (numeric PK) ← getFeed items[].pk | status | write; CSRF |
| followUser | follow a user | id (user ID) ← getUserProfile data.user.id | friendship_status | write; CSRF |
| unfollowUser | unfollow a user | id (user ID) ← getUserProfile data.user.id | friendship_status | write; CSRF |
| savePost | bookmark a post | id (numeric PK) ← getFeed items[].pk | status | write; CSRF |
| unsavePost | remove bookmark | id (numeric PK) ← getFeed items[].pk | status | write; CSRF |
| createComment | add comment | id (numeric PK), comment_text | response id (new comment pk), text, from.id, from.username |
write; CSRF; chains into deleteComment |
| deleteComment | remove comment | media_id, comment_id ← createComment.id or getPostComments comments[].pk | {status: "ok"} |
write; CSRF; URL is /api/v1/web/comments/{media}/delete/{comment}/ |
| blockUser | block a user | id (user ID) ← getUserProfile data.user.id | friendship_status | write; CSRF |
| unblockUser | unblock a user | id (user ID) ← getUserProfile data.user.id | friendship_status | write; CSRF |
| muteUser | mute a user | id (user ID) ← getUserProfile data.user.id | status | write; CSRF; adapter |
| unmuteUser | unmute a user | id (user ID) ← getUserProfile data.user.id | status | write; CSRF; adapter |
| getExplore | browse explore page | (none) | sectional_items with media grid | paginated via next_max_id |
| getFollowers | list followers | id (user ID) ← getUserProfile data.user.id | users with username, is_verified | paginated via next_max_id |
| getFollowing | list following | id (user ID) ← getUserProfile data.user.id | users with username, is_verified | paginated via next_max_id |
| getReels | view user reels | id (user ID) ← getUserProfile data.user.id | reels with play_count, captions | adapter; paginated via paging_info |
| getNotifications | activity feed | (none) | counts, new_stories, old_stories | adapter; POST |
| searchUsers | find users | query (search term) | users with username, full_name, is_verified, follower_count | entry point |
Quick Start
# Get a user profile
openweb instagram exec getUserProfile '{"username":"instagram"}'
# Get user's posts by username (adapter — resolves username automatically)
openweb instagram exec getUserPosts '{"username":"instagram","count":12}'
# Get user's feed by ID (first page)
openweb instagram exec getFeed '{"id":"25025320","count":12}'
# View a specific post (use pk from feed)
openweb instagram exec getPost '{"id":"3865890235180097425"}'
# Get comments on a post
openweb instagram exec getPostComments '{"id":"3865890235180097425"}'
# Get a user's stories
openweb instagram exec getStories '{"id":"25025320"}'
# Like / unlike a post (write operations)
openweb instagram exec likePost '{"id":"3865890235180097425"}'
openweb instagram exec unlikePost '{"id":"3865890235180097425"}'
# Follow / unfollow a user
openweb instagram exec followUser '{"id":"25025320"}'
openweb instagram exec unfollowUser '{"id":"25025320"}'
# Save / unsave a post
openweb instagram exec savePost '{"id":"3865890235180097425"}'
openweb instagram exec unsavePost '{"id":"3865890235180097425"}'
# Comment on a post
openweb instagram exec createComment '{"id":"3865890235180097425","comment_text":"Great post!"}'
openweb instagram exec deleteComment '{"media_id":"3865890235180097425","comment_id":"18042648274123456"}'
# Block / unblock a user
openweb instagram exec blockUser '{"id":"25025320"}'
openweb instagram exec unblockUser '{"id":"25025320"}'
# Mute / unmute a user (adapter — routes to correct endpoint)
openweb instagram exec muteUser '{"id":"25025320"}'
openweb instagram exec unmuteUser '{"id":"25025320"}'
# Browse Explore page
openweb instagram exec getExplore '{}'
# Get followers / following
openweb instagram exec getFollowers '{"id":"25025320","count":12}'
openweb instagram exec getFollowing '{"id":"25025320","count":12}'
# Get a user's Reels (adapter — POST to clips endpoint)
openweb instagram exec getReels '{"id":"25025320","count":12}'
# Get notifications
openweb instagram exec getNotifications '{}'
# Search users
openweb instagram exec searchUsers '{"query":"nasa"}'Known Limitations
- Write-op coverage (2026-04-19): all 12 write ops verified PASS end-to-end (
likePost,unlikePost,savePost,unsavePost,followUser,unfollowUser,muteUser,unmuteUser,blockUser,unblockUser,createComment,deleteComment).createComment/deleteCommentchain via${prev.createComment.id}against a low-traffic target post — high-profile accounts (e.g.@instagram) trigger spam-filter shadow-deletes that 404 the immediate delete.