Interactions
instagrapi provides various types of Interactions that can be used to control how the program will interact with the Instagram:
Media- Media (Photo, Video, Album, IGTV, Reels or Story)- Types - Field reference for public
instagrapi.typesmodels Resource- Part of Media (for albums)MediaOembed- Short version of MediaAccount- Full private info for your account (e.g. email, phone_number)TOTP- 2FA TOTP helpers (generate seed, enable/disable TOTP, generate code as Google Authenticator)User- Full public user dataUserShort- 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 MediaHighlight- HighlightsStory- StoryStoryArchiveDay- Story archive day shellStoryLink- Story link stickerStoryLocation- Tag Location in Story (as sticker)StoryMention- Mention users in Story (user, coordinates and dimensions)StoryHashtag- Hashtag for story (as sticker)StorySticker- Tag sticker to story (for example from giphy)StoryBuild- StoryBuilder return path to photo/video and mention co-ordinatesDirectThread- Thread (topic) with messages in DirectDirectMessage- Message in DirectInsight- Insights for a postTrack- Music track (for Reels/Clips)Note- Direct Notes
Interacting with Instagram Account
instagrapi provides the following Interactions that can be used to control and get the information about your Instagram account:
Client(settings: dict = {}, proxy: str = "", tls_verify: Union[bool, str] = True)- Initinstagrapiclient
cl.login("instagrapi", "42")
# cl.login("instagrapi", "42", verification_code="123456") # with 2FA verification_code
# cl.login_by_sessionid("peiWooShooghahdi2Eip7phohph0eeng")
cl.set_proxy("socks5://127.0.0.1:30235")
# cl.set_proxy("http://127.0.0.1:8080")
# cl.set_proxy("socks5://127.0.0.1:30235")
# when addressing the proxy via hostname:
# cl.set_proxy("socks5h://exampleproxy.tld:30235")
print(cl.get_settings())
print(cl.user_info(cl.user_id))
Request
| Property | Description |
|---|---|
| request_logger | Logger in which various actions from Instagram are registered |
| request_timeout | Timeout in seconds between requests (1 second by default) |
| public_request_retries_count | Default retry count for public_request() |
| public_request_retries_timeout | Delay between public_request() retries |
| session_retry_total | Adapter retry count for Requests transports; private curl does not use this setting |
| session_retry_backoff_factor | Backoff factor for Requests adapter retries; private curl does not use this setting |
| public_transport | Public web transport: requests by default, or curl when instagrapi[curl] is installed |
| private_transport | Private mobile API transport: curl by default for HTTP/2 with h2-only ALPN; requests for compatibility |
| public_transport_impersonate | Browser fingerprint used by the optional curl public transport |
| tls_verify | TLS certificate verification: True by default, False for temporary trusted MITM debugging, or a CA bundle path |
Login
| Method | Return | Description |
|---|---|---|
| login(username: str, password: str) | bool | CAA login by username and password; validate and reuse a saved session when present |
| login(username: str, password: str, verification_code: str) | bool | CAA login with a supported TOTP, SMS, backup or profile verification code |
| login_legacy(username: str, password: str, relogin: bool = False, verification_code: str = "") | bool | Explicit compatibility entry point for the previous login flow |
| relogin() | bool | Re-login with clean cookies (required cl.username and cl.password) |
| login_by_sessionid(sessionid: str) | bool | Lightweight compatibility login using a session cookie value |
| inject_sessionid_to_public() | bool | Inject sessionid from Private Session to Public Session |
| logout() | bool | Logout |
login() uses CAA directly and does not automatically fall back to login_legacy(). Both entry points accept the same arguments. See the login migration guide for compatibility and saved-session behavior.
login_by_sessionid() only works when Instagram accepts that sessionid for the private mobile API. A browser/web sessionid can be rejected with login_required or invalidated server-side; for long-lived automation, prefer login() once, then dump_settings() and reuse the saved settings.
When login_by_sessionid() needs to recover the account username after a private profile lookup failure, it tries the private mobile profile stream before falling back to public/web GraphQL.
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",
},
"authorization_data": {}, # sessionid / ds_user_id / authorization values
"cookies": {}, # saved cookies
"last_login": 1596069420.0000145,
"device_settings": {
"cpu": "h1",
"dpi": "640dpi",
"model": "h1",
"device": "RS988",
"resolution": "1440x2392",
"manufacturer": "LGE/lge",
"android_release": "6.0.1",
"android_version": 23,
},
"user_agent": "Instagram 385.0.0.47.74 Android (...)",
"country": "US",
"country_code": 1,
"locale": "en_US",
"timezone_offset": -14400,
"request_timeout": 1,
"public_request_retries_count": 3,
"public_request_retries_timeout": 2,
"session_retry_total": 3,
"session_retry_backoff_factor": 2,
"session_retry_statuses": [429, 500, 502, 503, 504],
"public_transport": "requests",
"private_transport": "curl",
"public_transport_impersonate": "chrome136",
"tls_verify": True,
}
cl = Client(settings)
Settings
Store and manage uuids, device configuration, user agent, authorization data (aka cookies) and other session settings
| Method | Return | Description |
|---|---|---|
| get_settings() | dict | Return settings dict |
| set_settings(settings: dict) | bool | Set session settings |
| load_settings(path: Path, override_app_version: bool = False) | dict | Load session settings; optionally update the app version, version code and Bloks hash |
| dump_settings(path: Path) | bool | Serialize and save session settings to file |
In order for Instagram to trust you more, use one stable device profile and one stable IP (or subnet) per account whenever possible:
cl = Client()
cl.login(USERNAME, PASSWORD)
cl.dump_settings("/tmp/dump.json")
Next time:
cl = Client()
cl.load_settings("/tmp/dump.json")
cl.login(USERNAME, PASSWORD)
cl.dump_settings("/tmp/dump.json")
Manage device, proxy and other account settings
New clients use the Instagram 446.0.0.49.77 app profile. Saved settings for the previous
428.0.0.47.67 profile retain their version and receive the matching Bloks hash when it is missing.
You can also select that profile explicitly with cl.set_app("428.0.0.47.67").
| Method | Return | Description |
|---|---|---|
| set_proxy(dsn: str) | dict | Support socks and http/https proxy scheme://host:port |
| private.proxies | dict | Stores used proxy servers for private (mobile, v1) requests |
| public.proxies | dict | Stores used proxy servers for public (web, graphql) requests |
| set_device(device: dict) | bool | Change device settings (Android Device Information Generator Online) |
| set_app(app: Union[str, Dict] = None) | bool | Apply a supported Instagram app version profile (app_version, version_code, bloks_versioning_id) |
| device | dict | Return device dict which we pass to Instagram |
| set_user_agent(user_agent: str = "") | bool | Change User-Agent header (User Agents) |
| cookie_dict | dict | Return cookies |
| user_id | int | Return your user_id (after login) |
| base_headers | dict | Base headers for Instagram |
| set_country(country: str = "US") | bool | Set country (advice: use the country of your proxy) |
| set_country_code(country_code: int = 1) | bool | Set country calling code. Default: +1 (USA) |
| set_locale(locale: str = "en_US") | bool | Set locale (advice: use the locale of your proxy) |
| set_timezone_offset(seconds: int) | bool | Set timezone offset in seconds |
| set_retry_config(...) | bool | Configure request timeout plus public/manual and session/transport retry settings |
| set_tls_verify(tls_verify: bool | str) | bool | Update TLS certificate verification for existing public, private and GraphQL sessions |
Example:
cl = Client(
request_timeout=0,
public_request_retries_count=4,
public_request_retries_timeout=1,
session_retry_total=5,
session_retry_backoff_factor=1,
)
cl.set_retry_config(
public_request_retries_count=2,
public_request_retries_timeout=0,
session_retry_total=3,
)
For the Requests transport (public_transport="requests" by default, or explicitly private_transport="requests"), session_retry_total controls adapter-level attempts for session_retry_statuses. After those attempts are exhausted, instagrapi receives the final response and raises its normal typed exception, such as ClientThrottledError for HTTP 429. When adapter retries are enabled, public_request() does not start a second retry package for the same configured status; when session_retry_total<=0, the existing public_request_retries_count loop remains active. Connection, TLS, DNS, and timeout exhaustion remain transport errors because there is no final HTTP response to map. The optional curl public transport uses its own adapter and is unaffected by these urllib3 settings.
For public web endpoints that are sensitive to browser TLS fingerprints, install the optional curl transport:
pip install "instagrapi[curl]"
Then opt in explicitly:
cl = Client(public_transport="curl", public_transport_impersonate="chrome136")
The default remains public_transport="requests". Configure private mobile API requests separately with private_transport.
See Public Transport for live comparison results and caveats.
Private HTTP/2 transport
The standard installation includes curl_cffi. Client() sends private mobile API requests over HTTP/2 with an ALPN offer containing only h2, including CAA login. Mobile request headers and account device settings are preserved.
cl = Client(settings=saved_settings, proxy=proxy_url)
cl.login(username, password)
cl.dump_settings("settings.json")
Transport selection is saved in settings. An explicit saved choice overrides the constructor; settings without this field preserve the constructor choice, which defaults to curl. To migrate settings that explicitly saved requests, call cl.set_retry_config(private_transport="curl") after loading them, then save again. Client(private_transport="requests") selects the previous private transport. Public and GraphQL transports have their own configuration.
The curl private transport requires curl_cffi>=0.15.0 and libcurl 8.10 or newer. With older libcurl versions, requesting HTTP/2 can still offer both h2 and http/1.1 during TLS negotiation. See the libcurl HTTP version documentation.
The TLS offer includes the hybrid X25519MLKEM768 group alongside X25519, P-256 and P-384 to address connection failures on some proxy paths. Servers without hybrid support can still select a classical group, while ALPN offers only h2.
This transport preserves requests' cookie jar, proxy selection, TLS verification, client certificates and redirects. Responses and iterable request bodies are buffered in memory, including when a response is requested with stream=True. Response decompression is handled by requests/urllib3. A numeric timeout is curl's total transfer budget; a (connect, read) tuple of numbers supplies a connection budget and a total budget of their sum. Use timeout=None for no timeout; tuples containing None and urllib3.util.Timeout objects are rejected before sending a request.
Private curl requests are sent once at the adapter level: session_retry_total, session_retry_backoff_factor and session_retry_statuses do not enable curl retries. HTTP 429 and connection failures reach the existing exception handling. login() uses CAA; login_legacy() explicitly selects the previous login flow. Transport selection does not remove account, proxy or verification restrictions.
Private mobile headers
base_headers follows the current supported Android app profile for normal private API requests, including static transport/network hints such as X-FB-HTTP-Engine, X-Tigon-Is-Retry, and X-Zero-*.
Device-bound or attestation-style headers such as x-meta-zca, x-meta-usdid, and x-ig-attest-params are not generated by default. These values are tied to Android / Google Play / device signing context, so adding fake static values is more likely to hurt trust than help.
TLS verification and debugging proxies
By default instagrapi verifies TLS certificates on all client sessions. Keep this enabled for production, residential proxies, and normal CONNECT-tunnel proxies.
If you use a trusted local debugging proxy that intercepts TLS, prefer installing its CA certificate and pointing the client at that bundle:
cl = Client(tls_verify="/path/to/proxy-ca.pem")
For short local captures you can disable verification explicitly:
cl = Client(tls_verify=False)
Do not disable TLS verification on untrusted networks or shared proxies because session cookies and passwords can be intercepted.
cl = Client()
# Los Angles user:
cl.set_proxy('http://proxy.address:8080')
cl.set_locale('en_US')
cl.set_timezone_offset(-7 * 60 * 60) # Los Angeles UTC (GMT) -7 hours == -25200 seconds
cl.get_settings()
{
...
'user_agent': 'Instagram 194.0.0.36.172 Android (26/8.0.0; 480dpi; 1080x1920; Xiaomi; MI 5s; capricorn; qcom; en_US; 301484483)',
'country': 'US',
'country_code': 1,
'locale': 'en_US',
'timezone_offset': -25200
}
# Moscow user:
cl.set_proxy('socks5://address:8080')
cl.set_locale('ru_RU')
cl.set_country_code(7) # +7
cl.set_timezone_offset(3 * 3600) # Moscow UTC+3
cl.get_settings()
{
...
'user_agent': 'Instagram 194.0.0.36.172 Android (26/8.0.0; 480dpi; 1080x1920; Xiaomi; MI 5s; capricorn; qcom; ru_RU; 301484483)',
'country': 'RU',
'country_code': 7,
'locale': 'ru_RU',
'timezone_offset': 10800
}