An async Python SDK for the Instagram Graph API — publishing, insights, comments, hashtags, and more.
- Fully async — built on
aiohttpwith anasyncio-native interface - Typed responses — every API response is a frozen Pydantic v2 model
- Seven API namespaces —
account,media,publishing,insights,comments,hashtags,mentions - Convenience helpers — one-call publish for images/reels/stories/carousels, automatic container polling, async pagination
- Clean exception hierarchy — catch broad or specific errors as needed
- Forward-compatible models — unknown fields from future API versions are silently ignored
- Python >= 3.11
- An Instagram Business or Creator account
- A valid access token (OAuth handled externally)
- Your Instagram account ID (
ig_user_id)
pip install instagram-python-sdkimport asyncio
from instagram import (
InstagramClient,
AccountField,
MediaInsightMetric,
AccountInsightMetric,
AccountInsightPeriod,
)
async def main() -> None:
async with InstagramClient(
access_token="YOUR_ACCESS_TOKEN",
ig_user_id="17841405822304914",
) as client:
# --- Account ---
user = await client.account.get_profile(
fields=[AccountField.USERNAME, AccountField.FOLLOWERS_COUNT, AccountField.MEDIA_COUNT]
)
print(f"{user.username} has {user.followers_count:,} followers")
# --- Media ---
async for post in client.media.iter_media():
print(post.permalink, post.like_count)
# --- Publishing ---
# Post an image
result = await client.publishing.publish_image(
"https://example.com/photo.jpg",
caption="Posted via Instagram Python SDK!",
)
print(f"Published: {result.id}")
# Post a reel (handles container polling automatically)
result = await client.publishing.publish_reel(
"https://example.com/video.mp4",
caption="Check this out! #python",
share_to_feed=True,
)
print(f"Reel published: {result.id}")
# --- Insights ---
insights = await client.insights.get_media_insights(
result.id,
metrics=[MediaInsightMetric.REACH, MediaInsightMetric.VIEWS],
)
for entry in insights.data:
print(entry.name, entry.values)
asyncio.run(main())InstagramClient(
access_token: str,
ig_user_id: str,
*,
base_url: str = "https://graph.instagram.com",
api_version: str = "v22.0",
timeout: float = 30.0,
)The main client. Use as an async context manager or call await client.aclose() manually.
Set base_url="https://graph.facebook.com" when using tokens obtained via Facebook Login for Business.
| Method | Description |
|---|---|
get_profile(fields) |
Authenticated user's profile info |
get_business_discovery(target_username, ...) |
Look up a public Business/Creator account |
ID, USERNAME, NAME, BIOGRAPHY, FOLLOWERS_COUNT, FOLLOWS_COUNT,
MEDIA_COUNT, PROFILE_PICTURE_URL, WEBSITE, IG_ID, ACCOUNT_TYPE
| Method | Description |
|---|---|
list_media(*, fields, limit, after, before) |
Paginated list of the user's media |
iter_media(*, fields, limit) |
Async iterator over all media (auto-paginates) |
get_media(media_id, *, fields) |
Fetch a single media object by ID |
get_children(media_id, *, fields) |
Fetch carousel album children |
list_stories(*, fields) |
Currently active stories (24h window) |
IMAGE, VIDEO, CAROUSEL_ALBUM
FEED, REELS, STORY
All publishing follows Instagram's two-step container model: create a container, then publish it. Video containers require polling until processing is FINISHED.
| Method | Description |
|---|---|
create_image_container(image_url, ...) |
Create a container for a single image post |
create_reel_container(video_url, ...) |
Create a container for a Reel |
create_story_image_container(image_url) |
Create a container for an image story |
create_story_video_container(video_url) |
Create a container for a video story |
create_carousel_item_container(*, image_url, video_url) |
Create a carousel child container |
create_carousel_container(children, ...) |
Create a parent carousel container |
get_container_status(container_id) |
Check container processing status |
wait_for_container(container_id, ...) |
Poll until terminal state |
publish(container_id) |
Publish a finished container |
| Method | Description |
|---|---|
publish_image(image_url, ...) |
Create + publish an image in one call |
publish_reel(video_url, ...) |
Create + poll + publish a reel in one call |
publish_story_image(image_url) |
Create + publish an image story |
publish_story_video(video_url, ...) |
Create + poll + publish a video story |
publish_carousel(items, ...) |
Create children + parent + publish a carousel |
class ContainerStatus(str, Enum):
EXPIRED = "EXPIRED" # Container expired (24h TTL)
ERROR = "ERROR" # Processing failed
FINISHED = "FINISHED" # Ready to publish
IN_PROGRESS = "IN_PROGRESS" # Still processing| Method | Description |
|---|---|
get_account_insights(metrics, period, *, since, until) |
Time-series account metrics |
get_demographic_insights(metrics) |
Lifetime audience demographics (100+ followers) |
get_media_insights(media_id, metrics) |
Insights for an image or carousel |
get_reel_insights(media_id, metrics) |
Insights for a reel |
get_story_insights(media_id, metrics) |
Insights for a story (24h window) |
REACH, FOLLOWER_COUNT, VIEWS
AUDIENCE_GENDER_AGE, AUDIENCE_LOCALE, AUDIENCE_COUNTRY, AUDIENCE_CITY, ONLINE_FOLLOWERS
REACH, SAVED, VIEWS, LIKES, COMMENTS, SHARES, TOTAL_INTERACTIONS, PROFILE_VISITS, FOLLOWS
REACH, SAVED, VIEWS, LIKES, COMMENTS, SHARES, TOTAL_INTERACTIONS
REACH, EXITS, REPLIES, TAPS_FORWARD, TAPS_BACK, VIEWS, SHARES
| Method | Description |
|---|---|
list_comments(media_id, ...) |
Paginated list of top-level comments |
get_comment(comment_id, ...) |
Fetch a single comment |
get_replies(comment_id, ...) |
Paginated list of replies |
post_comment(media_id, message) |
Post a new comment |
reply_to_comment(comment_id, message) |
Reply to a comment |
hide_comment(comment_id, *, hide) |
Hide or unhide a comment |
delete_comment(comment_id) |
Delete a comment |
toggle_comments(media_id, *, enabled) |
Enable or disable comments on a post |
Limited to 30 unique hashtag searches per 7-day rolling window.
| Method | Description |
|---|---|
search(query) |
Search for a hashtag, returns its ID |
get_top_media(hashtag_id, ...) |
Top media for a hashtag |
get_recent_media(hashtag_id, ...) |
Recent media for a hashtag |
get_hashtag_info(hashtag_id) |
Get hashtag name by ID |
search_and_get_top_media(query, ...) |
Convenience: search + get top media |
| Method | Description |
|---|---|
get_mentioned_media(...) |
Media where the user is @-mentioned in captions |
get_tagged_media(...) |
Media where the user is photo-tagged |
iter_tagged_media(...) |
Fetch all tagged media across all pages |
InstagramSDKError
├── InstagramAPIError <- error payload from the Graph API
│ ├── InstagramAuthError <- invalid / expired token (code 190)
│ ├── InstagramRateLimitError <- rate limit exceeded (codes 4, 17, 32)
│ ├── InstagramPermissionError <- insufficient permissions (codes 10, 200)
│ ├── InstagramNotFoundError <- resource not found (code 803)
│ └── InstagramServerError <- 5xx from Instagram
├── InstagramContainerError <- container processing failure
└── InstagramConfigError <- SDK misconfiguration (empty token, etc.)
from instagram import InstagramAuthError, InstagramRateLimitError, InstagramAPIError
try:
user = await client.account.get_profile()
except InstagramAuthError as e:
print(f"Auth failed: {e.code} - {e.message}")
except InstagramRateLimitError:
print("Rate limited, back off and retry.")
except InstagramAPIError as e:
print(f"API error {e.code}: {e.message} (fbtrace_id={e.fbtrace_id})")| Limit | Value |
|---|---|
| API calls | 200 requests / hour / user |
| Publishing | 25 posts / 24h / account |
| Hashtag searches | 30 unique queries / 7 days |
| Container TTL | 24 hours to publish |
# Clone and install with dev extras
git clone https://github.com/inoue-ai/instagram-python-sdk.git
cd instagram-python-sdk
pip install -e ".[dev]"
# Lint and format
ruff check .
ruff format .
# Type-check
mypy instagram/
# Run tests
pytestThis SDK does not implement any OAuth flow. Obtain an access token externally and pass it to InstagramClient along with your Instagram account ID.
There are two authentication paths:
| Flow | Base URL | Scopes prefix |
|---|---|---|
| Instagram Business Login (recommended) | https://graph.instagram.com |
instagram_business_* |
| Facebook Login for Business | https://graph.facebook.com |
instagram_* |
Required permissions per feature:
| Feature | Instagram Business Login | Facebook Login |
|---|---|---|
| Profile & media read | instagram_business_basic |
instagram_basic |
| Publishing | instagram_business_content_publish |
instagram_content_publish |
| Insights | instagram_business_basic |
instagram_manage_insights |
| Comments | instagram_business_manage_comments |
instagram_manage_comments |
| Hashtag search | instagram_business_basic |
instagram_basic |
| Mentions | instagram_business_manage_comments |
instagram_manage_comments |