Fast and effective Instagram Private API wrapper (public+private requests and challenge resolver). Use the most recent version of the API from Instagram, which was obtained using reverse-engineering with Charles Proxy.
Support Python >= 3.6
Instagram API valid for 7 November 2020 (last reverse-engineering check)
Support Chat in Telegram
and Discord
@adw0rd and @onlinehunter
- Performs public (
_gql
or _a1
suffix methods) or private/auth (_v1
suffix methods) requests depending on the situation (to avoid Instagram limits)
- Challenge Resolver have Email (as well as recipes for automating receive a code from email) and SMS handlers
- Support upload a Photo, Video, IGTV, Albums and Stories
- Support work with User, Media, Insights, Collections and Direct objects
- Insights by posts and stories
- Build stories with custom background and font animation
python -m unittest tests
python -m unittest tests.ClientPublicTestCase
Public
(anonymous) methods had suffix _gql
(Instagram GraphQL
) or _a1
(example https://www.instagram.com/adw0rd/?__a=1
)
Private
(authorized request) methods have _v1
suffix
The first request to fetch media/user is public
(anonymous), if instagram raise exception, then use private
(authorized).
Example (pseudo-code):
def media_info(media_pk):
try:
return self.media_info_gql(media_pk)
except ClientError as e:
# Restricted Video: This video is not available in your country.
# Or media from private account
return self.media_info_v1(media_pk)
from instagrapi import Client
cl = Client()
cl.login(ACCOUNT_USERNAME, ACCOUNT_PASSWORD)
user_id = cl.user_id_from_username("adw0rd")
medias = cl.user_medias(user_id, 20)
The current types are in types.py:
Method |
Description |
Media |
Media (Photo, Video, Album, IGTV or Story) |
Resource |
Part of Media (for albums) |
MediaOembed |
Short version of Media |
Account |
Full private info for your account (e.g. email, phone_number) |
User |
Full public user data |
UserShort |
Short public user data (used in Usertag, Comment, Media, Direct) |
Usertag |
Tag user in Media (coordinates + UserShort) |
Location |
GEO location (GEO coordinates, name, address) |
Hashtag |
Hashtag object (id, name, picture) |
Collection |
Collection of medias (name, picture and list of medias) |
Comment |
Comments to Media |
StoryMention |
Mention users in Story (user, coordinates and dimensions) |
StoryBuild |
StoryBuilder return path to photo/video and mention cordinates |
DirectThread |
Thread (topic) with messages in Direct |
DirectMessage |
Message in Direct |
This is your authorized account
Method |
Return |
Description |
Client(settings: dict = {}, proxy: str = "") |
bool |
Init instagrapi client (settings example below) |
login(username: str, password: str) |
bool |
Login by username and password (get new cookies if it does not exist in settings) |
relogin() |
bool |
Relogin with clean cookies (required cl.username/cl.password) |
login_by_sessionid(sessionid: str) |
bool |
Login by sessionid from Instagram site |
get_settings() |
dict |
Return settings dict (more details below) |
set_proxy(dsn: str) |
dict |
Support socks and http/https proxy |
cookie_dict |
dict |
Return cookies |
user_id |
int |
Return your user_id (after login) |
device |
dict |
Return device dict which we pass to Instagram |
set_device(device: dict) |
bool |
Change device settings |
set_user_agent(user_agent: str = "") |
bool |
Change User-Agent header |
base_headers |
dict |
Base headers for Instagram |
account_info() |
Account |
Get private info for your account (e.g. email, phone_number) |
account_edit(**data) |
Account |
Change profile data (e.g. email, phone_number, username, full_name, biography, external_url) |
account_change_picture(path: Path) |
UserShort |
Change Profile picture |
Example:
cl.login("instagrapi", "42")
# cl.login_by_sessionid("peiWooShooghahdi2Eip7phohph0eeng")
cl.set_proxy("socks5://127.0.0.1:30235")
# cl.set_proxy("http://127.0.0.1:8080")
print(cl.get_settings())
print(cl.user_info(cl.user_id))
You can pass settings to the Client (and save cookies), it has the following format:
settings = {
"uuids": {
"phone_id": "57d64c41-a916-3fa5-bd7a-3796c1dab122",
"uuid": "8aa373c6-f316-44d7-b49e-d74563f4a8f3",
"client_session_id": "6c296d0a-3534-4dce-b5aa-a6a6ab017443",
"advertising_id": "8dc88b76-dfbc-44dc-abbc-31a6f1d54b04",
"device_id": "android-e021b636049dc0e9"
},
"cookies": {}, # set here your saved cookies
"last_login": 1596069420.0000145,
"device_settings": {
"cpu": "h1",
"dpi": "640dpi",
"model": "h1",
"device": "RS988",
"resolution": "1440x2392",
"app_version": "117.0.0.28.123",
"manufacturer": "LGE/lge",
"version_code": "168361634",
"android_release": "6.0.1",
"android_version": 23
},
"user_agent": "Instagram 117.0.0.28.123 Android (23/6.0.1; ...US; 168361634)"
}
cl = Client(settings)
This values send to Instagram API.
Viewing and editing publications (medias)
media_id
- String ID "{media_id}_{user_id}"
, example "2277033926878261772_1903424587"
(Instagram terminology)
media_pk
- Integer ID (real media id), example 2277033926878261772
(Instagram terminology)
code
- Short code (slug for media), example BjNLpA1AhXM
from "https://www.instagram.com/p/BjNLpA1AhXM/"
url
- URL to media publication
Method |
Return |
Description |
media_id(media_pk: int) |
str |
Return media_id by media_pk (e.g. 2277033926878261772 -> 2277033926878261772_1903424587) |
media_pk(media_id: str) |
int |
Return media_pk by media_id (e.g. 2277033926878261772_1903424587 -> 2277033926878261772) |
media_pk_from_code(code: str) |
int |
Return media_pk |
media_pk_from_url(url: str) |
int |
Return media_pk |
media_info(media_pk: int) |
Media |
Return media info |
media_delete(media_pk: int) |
bool |
Delete media |
media_edit(media_pk: int, caption: str, title: str, usertags: List[Usertag], location: Location) |
dict |
Change caption for media |
media_user(media_pk: int) |
User |
Get user info for media |
media_oembed(url: str) |
MediaOembed |
Return short media info by media URL |
media_comment(media_id: str, message: str) |
bool |
Write message to media |
media_comments(media_id: str) |
List[Comment] |
Get all comments |
Example:
>>> cl.media_pk_from_code("B-fKL9qpeab")
2278584739065882267
>>> cl.media_pk_from_code("B8jnuB2HAbyc0q001y3F9CHRSoqEljK_dgkJjo0")
2243811726252050162
>>> cl.media_pk_from_url("https://www.instagram.com/p/BjNLpA1AhXM/")
1787135824035452364
>>> cl.media_info(1787135824035452364).dict()
{'pk': 1787135824035452364,
'id': '1787135824035452364_1903424587',
'code': 'BjNLpA1AhXM',
'taken_at': datetime.datetime(2018, 5, 25, 15, 46, 53, tzinfo=datetime.timezone.utc),
'media_type': 8,
'product_type': '',
'thumbnail_url': None,
'location': {'pk': 260916528,
'name': 'Foros, Crimea',
'address': '',
'lng': 33.7878,
'lat': 44.3914,
'external_id': 181364832764479,
'external_id_source': 'facebook_places'},
'user': {'pk': 1903424587,
'username': 'adw0rd',
'full_name': 'Mikhail Andreev',
'profile_pic_url': HttpUrl('https://scontent-hel3-1.cdninstagram.com/v/t51.2885-19/s150x150/123884060_...&oe=5FD7600E')},
'comment_count': 0,
'like_count': 48,
'caption_text': '@mind__flowers в Форосе под дождём, 24 мая 2018 #downhill #skateboarding #downhillskateboarding #crimea #foros',
'usertags': [],
'video_url': None,
'view_count': 0,
'video_duration': 0.0,
'title': '',
'resources': [{'pk': 1787135361353462176,
'video_url': HttpUrl('https://scontent-hel3-1.cdninstagram.com/v/t50.2886-16/33464086_3755...0e2362', scheme='https', ...),
'thumbnail_url': HttpUrl('https://scontent-hel3-1.cdninstagram.com/v/t51.2885-15/e35/3220311...AE7332', scheme='https', ...),
'media_type': 2},
{'pk': 1787135762219834098,
'video_url': HttpUrl('https://scontent-hel3-1.cdninstagram.com/v/t50.2886-16/32895...61320_n.mp4', scheme='https', ...),
'thumbnail_url': HttpUrl('https://scontent-hel3-1.cdninstagram.com/v/t51.2885-15/e35/3373413....8480_n.jpg', scheme='https', ...),
'media_type': 2},
{'pk': 1787133803186894424,
'video_url': None,
'thumbnail_url': HttpUrl('https://scontent-hel3-1.cdninstagram.com/v/t51.2885-15/e35/324307712_n.jpg...', scheme='https', ...),
'media_type': 1}]}
>>> cl.media_oembed("https://www.instagram.com/p/B3mr1-OlWMG/").dict()
{'version': '1.0',
'title': 'В гостях у ДК @delai_krasivo_kaifui',
'author_name': 'adw0rd',
'author_url': 'https://www.instagram.com/adw0rd',
'author_id': 1903424587,
'media_id': '2154602296692269830_1903424587',
'provider_name': 'Instagram',
'provider_url': 'https://www.instagram.com',
'type': 'rich',
'width': 658,
'height': None,
'html': '<blockquote>...',
'thumbnail_url': 'https://instagram.frix7-1.fna.fbcdn.net/v...0655800983_n.jpg',
'thumbnail_width': 640,
'thumbnail_height': 480,
'can_view': True}
View a list of a user's medias, following and followers
user_id
- Integer ID of user, example 1903424587
Method |
Return |
Description |
user_medias(user_id: int, amount: int = 20) |
List[Media] |
Get list of medias by user_id |
user_followers(user_id: int) |
Dict[int, User] |
Get dict of followers users |
user_following(user_id: int) |
Dict[int, User] |
Get dict of following users |
user_info(user_id: int) |
User |
Get user info |
user_info_by_username(username: str) |
User |
Get user info by username |
user_follow(user_id: int) |
bool |
Follow user |
user_unfollow(user_id: int) |
bool |
Unfollow user |
user_id_from_username(username: str) |
int |
Get user_id by username |
username_from_user_id(user_id: int) |
str |
Get username by user_id |
Example:
>>> cl.user_followers(cl.user_id).keys()
dict_keys([5563084402, 43848984510, 1498977320, ...])
>>> cl.user_following(cl.user_id)
{
8530598273: UserShort(
pk=8530598273,
username="dhbastards",
full_name="The Best DH Skaters Ever",
profile_pic_url=HttpUrl(
'https://instagram.frix7-1.fna.fbcdn.net/v/t5...9318717440_n.jpg',
scheme='https',
host='instagram.frix7-1.fna.fbcdn.net',
...
),
),
49114585: UserShort(
pk=49114585,
username='gx1000',
full_name='GX1000',
profile_pic_url=HttpUrl(
'https://scontent-hel3-1.cdninstagram.com/v/t51.2885-19/10388...jpg',
scheme='https',
host='scontent-hel3-1.cdninstagram.com',
...
)
),
...
}
>>> cl.user_info_by_username('adw0rd').dict()
{'pk': 1903424587,
'username': 'adw0rd',
'full_name': 'Mikhail Andreev',
'is_private': False,
'profile_pic_url': HttpUrl('https://scontent-hel3-1.cdninstagram.com/v/t51.2885-19/s150x150/123884060_803537687159702_2508263208740189974_n.jpg?...', scheme='https', host='scontent-hel3-1.cdninstagram.com', tld='com', host_type='domain', ...'),
'is_verified': False,
'media_count': 102,
'follower_count': 576,
'following_count': 538,
'biography': 'Engineer: Python, JavaScript, Erlang\n@dhbastards \n@bestskatetrick \n@best_drift_daily \n@best_rally_mag \n@asphalt_kings_lb \n@surferyone \n@bmxtravel',
'external_url': HttpUrl('https://adw0rd.com/', scheme='https', host='adw0rd.com', tld='com', host_type='domain', path='/'),
'is_business': False}
Method |
Return |
Description |
photo_download(media_pk: int, folder: Path) |
Path |
Download photo (path to photo with best resoluton) |
photo_download_by_url(url: str, filename: str, folder: Path) |
Path |
Download photo by URL (path to photo with best resoluton) |
video_download(media_pk: int, folder: Path) |
Path |
Download video (path to video with best resoluton) |
video_download_by_url(url: str, filename: str, folder: Path) |
Path |
Download Video by URL (path to video with best resoluton) |
igtv_download(media_pk: int, folder: Path) |
Path |
Download IGTV (path to video with best resoluton) |
igtv_download_by_url(url: str, filename: str, folder: Path) |
Path |
Download IGTV by URL (path to video with best resoluton) |
album_download(media_pk: int, folder: Path) |
Path |
Download Album (multiple paths to photo/video with best resolutons) |
album_download_by_urls(urls: List[str], folder: Path) |
Path |
Download Album by URLs (multiple paths to photo/video) |
Upload medias to your feed. Common arguments:
path
- Path to source file
caption
- Text for you post
usertags
- List[Usertag] of mention users (see Usertag
in types.py)
location
- Location (e.g. Location(lat=42.0, lng=42.0)
)
Method |
Return |
Description |
photo_upload(path: Path, caption: str, upload_id: str, usertags: List[Usertag], location: Location) |
Media |
Upload photo (Support JPG files) |
video_upload(path: Path, caption: str, thumbnail: Path, usertags: List[Usertag], location: Location) |
Media |
Upload video (Support MP4 files) |
igtv_upload(path: Path, title: str, caption: str, thumbnail: Path, usertags: List[Usertag], location: Location) |
Media |
Upload IGTV (Support MP4 files) |
album_upload(paths: List[Path], caption: str, usertags: List[Usertag], location: Location) |
Media |
Upload Album (Support JPG and MP4) |
Upload medias to your stories. Common arguments:
path
- Path to media file
caption
- Caption for story (now use to fetch mentions)
thumbnail
- Thumbnail instead capture from source file
usertags
- Specify usertags for mention users in story
configure_timeout
- How long to wait in seconds for a response from Instagram when publishing a story
links
- "Swipe Up" links (now use first)
Method |
Return |
Description |
photo_upload_to_story(path: Path, caption: str, upload_id: str, mentions: List[Usertag]) |
Media |
Upload photo (Support JPG files) |
video_upload_to_story(path: Path, caption: str, thumbnail: Path, mentions: List[Usertag], links: List[StoryLink]) |
Media |
Upload video (Support MP4 files) |
Examples:
media_path = cl.video_download(
cl.media_pk_from_url('https://www.instagram.com/p/CGgDsi7JQdS/')
)
adw0rd = cl.user_info_by_username('adw0rd')
cl.video_upload_to_story(
media_path,
"Credits @adw0rd",
mentions=[StoryMention(user=adw0rd, x=0.49892962, y=0.703125, width=0.8333333333333334, height=0.125)],
links=[StoryLink(webUri='https://github.com/adw0rd/instagrapi')]
)
Method |
Return |
Description |
build_clip(clip: moviepy.Clip, max_duration: int = 0) |
StoryBuild |
Build CompositeVideoClip with background and mentioned users. Return MP4 file and mentions with coordinates |
video(max_duration: int = 0) # in seconds |
StoryBuild |
Call build_clip(VideoClip, max_duration) |
photo(max_duration: int = 0) # in seconds |
StoryBuild |
Call build_clip(ImageClip, max_duration) |
Example:
from instagrapi.story import StoryBuilder
media_path = cl.video_download(
cl.media_pk_from_url('https://www.instagram.com/p/CGgDsi7JQdS/')
)
adw0rd = cl.user_info_by_username('adw0rd')
buildout = StoryBuilder(
media_path,
'Credits @adw0rd',
[StoryMention(user=adw0rd)],
Path('/path/to/background_720x1280.jpg')
).video(15) # seconds
cl.video_upload_to_story(
buildout.path,
"Credits @adw0rd",
mentions=buildout.mentions,
links=[StoryLink(webUri='https://github.com/adw0rd/instagrapi')]
)
Method |
Return |
Description |
collections() |
List[Collection] |
Get all account collections |
collection_medias_by_name(name) |
List[Media] |
Get medias in collection by name |
collection_medias(collection_id, amount=21, last_media_pk=0) |
List[Media] |
Get medias in collection by collection_id; Use amount=0 to return all medias in collection; Use last_media_pk to return medias by cursor |
Get statistics by medias. Common arguments:
post_type
- Media type: "ALL", "CAROUSEL_V2", "IMAGE", "SHOPPING", "VIDEO".
time_frame
- Time frame for media publishing date: "ONE_WEEK", "ONE_MONTH", "THREE_MONTHS", "SIX_MONTHS", "ONE_YEAR", "TWO_YEARS".
data_ordering
- Data ordering in instagram response: "REACH_COUNT", "LIKE_COUNT", "FOLLOW", "SHARE_COUNT", "BIO_LINK_CLICK", "COMMENT_COUNT", "IMPRESSION_COUNT", "PROFILE_VIEW", "VIDEO_VIEW_COUNT", "SAVE_COUNT".
Method |
Return |
Description |
insights_media_feed_all(post_type: str = "ALL", time_frame: str = "TWO_YEARS", data_ordering: str = "REACH_COUNT", count: int = 0, sleep: int = 2) |
list |
Return medias with insights |
insights_account() |
dict |
Get statistics by your account |
insights_media(media_pk: int) |
dict |
Get statistics by your media |
Method |
Return |
Description |
direct_threads(amount: int = 20) |
List[DirectThread] |
Get all Threads |
direct_thread(thread_id: int, amount: int = 20) |
DirectThread |
Get Thread with Messages |
direct_messages(thread_id: int, amount: int = 20) |
List[DirectMessage] |
Get only Messages in Thread |
direct_answer(thread_id: int, text: str) |
DirectMessage |
Add Message to exist Thread |
direct_send(text: str, users: List[int] = [], threads: List[int] = []) |
DirectMessage |
Send Message to Users or Threads |
Method |
Return |
Description |
location_search(lat: float, lng: float) |
List[Location] |
Search Location by GEO coordinates |
location_complete(location: Location) |
Location |
Complete blank fields |
location_build(location: Location) |
String |
Serialized JSON |
location_info(location_pk: int) |
Location |
Return Location info (pk, name, address, lng, lat, external_id, external_id_source) |
Method |
Return |
Description |
hashtag_info(name: str) |
Hashtag |
Return Hashtag info (id, name, picture) |
hashtag_related_hashtags(name: str) |
List[Hashtag] |
Return list of related Hashtags |
hashtag_medias_top(name: str, amount: int = 9) |
List[Media] |
Return Top posts by Hashtag |
hashtag_medias_recent(name: str, amount: int = 27) |
List[Media] |
Return Most recent posts by Hashtag |
All challenges solved in the module challenge.py
Automatic submission code from SMS/Email in examples here
Exception |
Base |
Description |
ClientError |
Exception |
Base Exception for Instagram calls |
GenericRequestError |
ClientError |
Base Exception for Request |
ClientGraphqlError |
ClientError |
Exception for GraphQL calls |
ClientJSONDecodeError |
ClientError |
JSON Exception |
ClientConnectionError |
ClientError |
Connection error |
ClientBadRequestError |
ClientError |
HTTP 400 Exception |
ClientForbiddenError |
ClientError |
HTTP 403 Exception |
ClientNotFoundError |
ClientError |
HTTP 404 Exception |
ClientThrottledError |
ClientError |
HTTP 429 Exception |
ClientRequestTimeout |
ClientError |
Request Timeout Exception |
ClientIncompleteReadError |
ClientError |
Raised when response interrupted |
ClientLoginRequired |
ClientError |
Raised when Instagram required Login |
ReloginAttemptExceeded |
ClientError |
Raised when all attempts exceeded |
Exception |
Base |
Description |
PrivateError |
ClientError |
Base Exception for Private calls (received from Instagram) |
FeedbackRequired |
PrivateError |
Raise when get message=feedback_required |
LoginRequired |
PrivateError |
Raise when get message=login_required |
SentryBlock |
PrivateError |
Raise when get message=sentry_block |
RateLimitError |
PrivateError |
Raise when get message=rate_limit_error |
BadPassword |
PrivateError |
Raise when get message=bad_password |
UnknownError |
PrivateError |
Raise when get unknown message (new message from instagram) |
Exception |
Base |
Description |
ChallengeError |
PrivateError |
Base Challenge Exception (received from Instagram) |
ChallengeRedirection |
ChallengeError |
Raise when get type=CHALLENGE_REDIRECTION |
ChallengeRequired |
ChallengeError |
Raise when get message=challenge_required |
SelectContactPointRecoveryForm |
ChallengeError |
Raise when get challengeType=SelectContactPointRecoveryForm |
RecaptchaChallengeForm |
ChallengeError |
Raise when get challengeType=RecaptchaChallengeForm |
SubmitPhoneNumberForm |
ChallengeError |
Raise when get challengeType=SubmitPhoneNumberForm |
Exception |
Base |
Description |
MediaError |
PrivateError |
Base Media Exception (received from Instagram) |
MediaNotFound |
MediaError |
Raise when user unavailable |
Exception |
Base |
Description |
UserError |
PrivateError |
Base User Exception (received from Instagram) |
UserNotFound |
UserError |
Raise when user unavailable |
Exception |
Base |
Description |
CollectionError |
PrivateError |
Base Collection Exception (received from Instagram) |
CollectionNotFound |
CollectionError |
Raise when collection unavailable |
Exception |
Base |
Description |
DirectError |
PrivateError |
Base Direct Exception |
DirectThreadNotFound |
DirectError |
Raise when thread not found |
DirectMessageNotFound |
DirectError |
Raise when message in thread not found |
Exception |
Base |
Description |
PhotoNotDownload |
PrivateError |
Raise when source photo not found |
PhotoNotUpload |
PrivateError |
Raise when photo not upload |
PhotoConfigureError |
PhotoNotUpload |
Raise when photo not configured |
PhotoConfigureStoryError |
PhotoConfigureError |
Raise when photo story not configured |
Exception |
Base |
Description |
VideoNotDownload |
PrivateError |
Raise when source video not found |
VideoNotUpload |
PrivateError |
Raise when video not upload |
VideoConfigureError |
VideoNotUpload |
Raise when video not configured |
VideoConfigureStoryError |
VideoConfigureError |
Raise when video story not configured |
Exception |
Base |
Description |
IGTVNotUpload |
PrivateError |
Raise when IGTV not upload |
IGTVConfigureError |
IGTVNotUpload |
Raise when IGTV not configured |
Exception |
Base |
Description |
AlbumNotDownload |
PrivateError |
Raise when album not found |
AlbumUnknownFormat |
PrivateError |
Raise when format of media not MP4 or JPG |
AlbumConfigureError |
PrivateError |
Raise when album not configured |