Connects Claude to the Instagram Graph API so you can fetch posts, search hashtags, and publish images without leaving your conversation. The setup assumes you've already wired up an Instagram Business account and have the right tokens in place. Publishing works through Meta's two-step container pattern, and hashtag search needs proper business permissions. Most useful when you're building workflows that need to pull recent media or automate posting, though you'll hit the usual Meta rate limits and OAuth complexity. The troubleshooting section is honest about permission errors being the main pain point.
npx -y skills add vm0-ai/vm0-skills --skill instagram --agent claude-codeInstalls into .claude/skills of the current project.
If requests fail, run zero doctor check-connector --env-name INSTAGRAM_TOKEN or zero doctor check-connector --url https://graph.facebook.com/v21.0/me --method GET
All examples below assume you have already set:
INSTAGRAM_TOKEN
INSTAGRAM_BUSINESS_ACCOUNT_ID
Fetch the most recent media (photos / videos / Reels) for the account:
curl -s -X GET "https://graph.facebook.com/v21.0/$INSTAGRAM_BUSINESS_ACCOUNT_ID/media?fields=id,caption,media_type,media_url,permalink,timestamp" --header "Authorization: Bearer $INSTAGRAM_TOKEN"
Notes:
id: media ID (used for details / insights later)caption: caption textmedia_type: IMAGE / VIDEO / CAROUSEL_ALBUMmedia_url: direct URL to the mediapermalink: Instagram permalinktimestamp: creation timeIf you already have a media id, you can fetch more complete information. Replace <your-media-id> with the id field from the "Get User Media" response (section 1 above):
curl -s -X GET "https://graph.facebook.com/v21.0/<your-media-id>?fields=id,caption,media_type,media_url,permalink,thumbnail_url,timestamp,username" --header "Authorization: Bearer $INSTAGRAM_TOKEN"
Note: hashtag search requires proper business use cases and permissions as defined by Facebook/Instagram. Refer to the official docs.
This usually involves two steps:
Replace <hashtag-name> with any hashtag name you want to search for (without the # symbol), e.g., "travel", "food", "photography":
curl -s -X GET "https://graph.facebook.com/v21.0/ig_hashtag_search?user_id=$INSTAGRAM_BUSINESS_ACCOUNT_ID&q=<hashtag-name>" --header "Authorization: Bearer $INSTAGRAM_TOKEN"
Note the id field in the returned JSON for use in the next step.
Replace <hashtag-id> with the id field from the "Search Hashtag" response (section 3.1 above):
curl -s -X GET "https://graph.facebook.com/v21.0/<hashtag-id>/recent_media?user_id=$INSTAGRAM_BUSINESS_ACCOUNT_ID&fields=id,caption,media_type,media_url,permalink,timestamp" --header "Authorization: Bearer $INSTAGRAM_TOKEN"
Publishing an image post via the Graph API usually requires two steps:
Write the request data to /tmp/request.json:
{
"image_url": "https://example.com/image.jpg",
"caption": "Hello from Instagram API 👋"
}
Replace https://example.com/image.jpg with any publicly accessible image URL and update the caption text as needed.
curl -s -X POST "https://graph.facebook.com/v21.0/$INSTAGRAM_BUSINESS_ACCOUNT_ID/media" -H "Content-Type: application/json" -d @/tmp/request.json --header "Authorization: Bearer $INSTAGRAM_TOKEN"
The response will contain an id (media container ID), for example:
{
"id": "1790xxxxxxxxxxxx"
}
Note this ID for use in the next step.
Write the request data to /tmp/request.json:
{
"creation_id": "<your-creation-id>"
}
Replace <your-creation-id> with the id field from the "Create Media Container" response (section 4.1 above):
curl -s -X POST "https://graph.facebook.com/v21.0/$INSTAGRAM_BUSINESS_ACCOUNT_ID/media_publish" -H "Content-Type: application/json" -d @/tmp/request.json --header "Authorization: Bearer $INSTAGRAM_TOKEN"
If successful, the response will contain the final media id:
{
"id": "1791yyyyyyyyyyyy"
}
You can then use the "Get details for a single media" command to fetch its permalink.
(#10) Application does not have permission for this actionINSTAGRAM_TOKEN is a valid long-lived tokenINSTAGRAM_TOKEN is sensitive; avoid printing it in logs or chat transcriptsv21.0 version in URLs to the latest<your-media-id> instead of shell variables in URLs to avoid dependencies and make examples self-containedjuliusbrussee/caveman
mattpocock/skills
shadcn/improve
obra/superpowers
forrestchang/andrej-karpathy-skills
vercel-labs/skills