Skip to content

feat!: replace requests with httpcloak for TLS fingerprinting (#2363)#2364

Closed
iiviie wants to merge 2 commits intosubzeroid:masterfrom
iiviie:addHttpCloak
Closed

feat!: replace requests with httpcloak for TLS fingerprinting (#2363)#2364
iiviie wants to merge 2 commits intosubzeroid:masterfrom
iiviie:addHttpCloak

Conversation

@iiviie
Copy link
Copy Markdown

@iiviie iiviie commented Jan 26, 2026

Summary

Replaces the requests library with httpcloak to bypass Instagram's TLS fingerprinting bot detection, fixing login and API blocking issues.
Closes #2363

Problem

Instagram uses JA3/JA4 TLS fingerprinting to detect and block automated requests. Python's requests library has a distinct fingerprint that Instagram easily identifies and blocks, causing login failures and "challenge required" errors.

Solution

Integrated HTTPCloak library which mimics real browser TLS fingerprints:

  • Private API: ios-chrome-143 preset (mobile Instagram app)
  • Public API: safari-18 preset (web browser)
  • Uses tls_only=True mode to maintain custom User-Agent while keeping browser TLS fingerprint
    Major File Changes

Core Integration

pyproject.toml

  • Version bump: 2.x.x → 3.0.0
  • Dependency: requests==2.32.5httpcloak>=1.0.0
    instagrapi/__init__.py
  • Import change: requestshttpcloak
  • Updated set_proxy(): Now calls session.set_proxy() method instead of setting proxies dict
    instagrapi/mixins/private.py
  • Replaced requests.Session() with httpcloak.Session(preset="ios-chrome-143", tls_only=True)
  • Removed HTTPAdapter and Retry strategy (httpcloak handles internally)
  • Added get_header_value() helper for httpcloak's list-style headers
  • Added None value filtering for headers before sending
    instagrapi/mixins/public.py
  • Replaced requests.Session() with httpcloak.Session(preset="safari-18", tls_only=True)
  • Removed HTTPAdapter and Retry strategy
  • Updated request methods to use httpcloak session
    instagrapi/mixins/auth.py
  • Updated cookie_dict property: cookies.get_dict()cookies (already a dict)
  • Updated init(): Use set_cookie() method instead of cookies.update()
  • Updated session save/restore: Now saves httpcloak_session_data via marshal()/unmarshal()
  • Updated inject_sessionid_to_public(): Use set_cookie() method
    instagrapi/mixins/password.py
  • Added get_header_value() import and usage for header handling

Download Methods

instagrapi/mixins/photo.py, video.py, track.py

  • Changed from standalone requests.get() to self.private.get() for consistent fingerprinting
  • Updated download method: response.rawresponse.iter_content(chunk_size=8192)
    instagrapi/image_util.py
  • External image downloads now use httpcloak.Session(preset="safari-18", tls_only=True)

Proxy/Cookie Handling

instagrapi/mixins/account.py, challenge.py

  • Updated proxy access: session.proxiessession.get_proxy() with dict conversion
    Tests
    tests.py
  • Line 11: Import change requestshttpcloak
  • Line 126-131: Updated to use httpcloak.Session().get()
  • Line 371: Fixed HTTPCloak Response compatibility (no .request attribute)

Breaking Changes

For advanced users only (public API unchanged):

Operation v2.x (requests) v3.x (httpcloak)
Get cookies client.private.cookies.get_dict() client.private.cookies
Set cookie client.private.cookies.set("name", "val") client.private.set_cookie("name", "val")
Clear cookies client.private.cookies.clear() client.private.clear_cookies()
Get proxy client.private.proxies.get("https") client.private.get_proxy()

Testing

Comprehensive test suite created and verified locally:

  • Basic client instantiation with httpcloak sessions
  • Cookie management (set, get, clear operations)
  • Session persistence (save/restore with TLS state)
  • Proxy handling (set_proxy/get_proxy methods)
  • Real account login with TLS fingerprinting
  • API calls (user_info, username lookup, timeline feed)
  • Session save/restore after login
  • Sessionid injection to public session
  • HTTPCloak preset verification
    All core functionality verified working with no Instagram blocks detected.
    Documentation
  • Updated README.md with HTTPCloak integration section
  • Added docs/httpcloak.md - User guide, migration instructions, and troubleshooting

Migration

End users: No code changes required! Just upgrade:
pip install instagrapi --upgrade
Your existing code works as-is

Advanced users: See docs/httpcloak.md (docs/httpcloak.md) for session object changes.

Tested Presets

Preset Status Notes
ios-chrome-143 Works Used for private API
ios-safari-17 Works Alternative mobile
safari-18 Works Used for public API
android-chrome-143 Blocked Instagram detects
chrome-143 Blocked Instagram detects

@ishiadv
Copy link
Copy Markdown

ishiadv commented Feb 5, 2026

I have tested this httpcloak version, but it didn't work in my environment which old version worked.
Finished with the message.
instagrapi.exceptions.ClientBadRequestError: HTTP 400: Bad Request.

@iiviie
Copy link
Copy Markdown
Author

iiviie commented Feb 7, 2026

@ishiadv hey yeah i encountered the same issue today, changing the Instagram outdated version 269.0.0.18.75 (OnePlus 6T) to 358.0.0.47.96 (Pixel 6 Pro) at libs/instagrapi/instagrapi/mixins/auth.py seemed to fix the issue

@ishiadv
Copy link
Copy Markdown

ishiadv commented Feb 8, 2026

@iiviie
Isn't the httpcloak preset iOS...?
Does this really work by changing to Pixel 6 Pro?

@iiviie
Copy link
Copy Markdown
Author

iiviie commented Feb 8, 2026

@ishiadv yup the httpcloak preset is ios, but i tried the android and chrome presets and they didnt seem to work, also as far as i know instagrapi overrides the agent anyways. But httpcloak alteast hides the TLS signature.
I've been using this config for over a week, haven't been flagged as bot yet

@favorPotato
Copy link
Copy Markdown
Contributor

Good work, I did something similar too.
I analyzed the Instagram apk file and found that it downgrades to use okhttp.
So I created a combination based on rnet + okhttp.
I haven't uploaded the code yet (no time to test it), perhaps we could exchange ideas with each other.

@iiviie
Copy link
Copy Markdown
Author

iiviie commented Feb 16, 2026

@favorPotato hey thanks, sounds good to me, is discord good ? My username is iiv.ii on discord

@Wawilow
Copy link
Copy Markdown

Wawilow commented Feb 16, 2026

Facebook uses its own close-source Tibon http library in all of the apps. Trying to mimic chrome's tls with mobile api wouldn't help you a bit.

The proper solution would require some kind of implementation or Fizz TLS (https://github.com/facebookincubator/fizz) or Apple's Network.framework (https://developer.apple.com/documentation/network)

Repository owner deleted a comment from adw0rd Feb 25, 2026
@subzeroid
Copy link
Copy Markdown
Owner

Code Review

Thanks for the PR — TLS fingerprinting is a real problem and the idea is solid. However, there are several issues that
need to be addressed before this can be merged.

Bugs

  1. Two except Exception blocks in public.py — the second except Exception as e: (ConnectionError handling)
    is unreachable because the first one catches everything. This means ClientConnectionError will never be raised for
    public requests.

  2. Unreachable code in private.py — after raise ClientRequestTimeout(...) on status 408, there's another
    raise ClientError(...) that can never execute.

  3. Broken imports of requestschallenge.py (line 114) and account.py (reset_password) still use
    requests.Session() and requests.post() directly, but requests is removed from dependencies. This will cause
    ImportError at runtime unless the user installs the legacy extra, which is not documented as required.

  4. image_util.py uses chrome-143 preset — which is listed as Blocked by Instagram in your own
    documentation. Should be safari-18.

  5. android-chrome-143 in session restore fallback (auth.py, init() method) — the fallback preset when
    restoring a session is android-chrome-143, which you also list as blocked. Should be ios-chrome-143.

Security Concern

httpcloak is a relatively unknown package with limited community review. Since it controls the entire TLS layer, it
has full access to all request/response data including credentials and session tokens. The package should be audited before

Breaking Changes / Regressions

  1. Retry mechanism removedRetry + HTTPAdapter (3 retries with backoff on 429/5xx) are removed entirely. The
    comment says "httpcloak handles internally" but this should be verified — losing automatic retries is a significant
    reliability regression.

  2. video_download_by_url completely rewritten — Content-Length validation removed, file writing removed. The
    method now just returns response.content without saving to disk. This breaks the documented behavior (returns
    Path, not bytes).

  3. video_download_by_url_origin deleted — this is a public API method, removing it is a breaking change that
    needs migration documentation.

Code Quality

  1. Fragile error handlingexcept Exception with "HTTPError" in e.__class__.__name__ string matching is
    brittle. If httpcloak provides specific exception classes, import and catch them directly. If not, this is a red flag
    about the library's API design.

  2. Headers not applied in init() — the old code did self.private.headers.update(headers) with auth headers.
    The new code has a comment "httpcloak manages headers internally" but auth headers (Authorization) still need to be
    sent. Verify this doesn't break session restoration.

Summary

The approach is promising but the implementation needs another pass. The critical items are #1-5 (actual bugs) and
#6-8 (silent regressions).

@iiviie
Copy link
Copy Markdown
Author

iiviie commented Feb 25, 2026

hey thanks for the review, i'll address the bugs that you've mentioned, speaking of httpcloak, the security concerns you mentioned are genuine. Till httpcloak get audited I can make it optional behind a flag

@subzeroid
Copy link
Copy Markdown
Owner

Thanks for the follow-up. I re-checked the PR and the current discussion still points to this needing another pass before merge. The existing blockers from review are still the right bar here: the public/private transport regressions, broken/leftover requests usage, blocked preset choices in code, and API contract breaks like video_download_by_url returning bytes instead of a Path. Keeping this open for rework rather than merging as-is.

@subzeroid
Copy link
Copy Markdown
Owner

Closing this PR because the current branch is no longer mergeable and the previously reviewed blockers are still present.

The remaining issues are not small cleanup items: requests was removed from required dependencies while default-imported modules still import/use it, video_download_by_url now returns bytes instead of the documented Path, public/private exception handling has unreachable/brittle branches, and the transport/session behavior still needs a clearer compatibility story.

For this to move forward, please open a fresh rebased PR with the transport change scoped behind an explicit opt-in path, no regression to existing download APIs, no undeclared requests imports, green CI, and tests that verify the new session/header behavior.

@subzeroid subzeroid closed this May 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Introduce TLS fingerprinting protection

5 participants