Advanced TLS/SSL wrapper for Python
Project description
Noble TLS
Noble TLS is an advanced HTTP library based on requests and tls-client. Fully async, with auto-updating JA3 fingerprints.
Installation
pip install noble-tls
Features
- Auto-update TLS client libs from bogdanfinn/tls-client
- Async support
- Proxy support (HTTP, HTTPS, SOCKS4, SOCKS5)
- Custom JA3 string
- Custom H2 and H3 settings
- Custom supported signature algorithms
- Custom supported versions
- Custom key share curves (including post-quantum)
- Custom cert compression algorithm
- Custom pseudo header order
- Custom connection flow
- Custom header order
- 76 preset browser profiles (Chrome, Firefox, Opera, Safari, iOS, iPadOS, Android)
- Random TLS extension order
- HTTP/3 (QUIC) with protocol racing
- Certificate pinning (HPKP)
- ECH (Encrypted Client Hello) and ALPS
- Session lifecycle management (close, get/add cookies from Go layer)
- Response streaming to file
- Protocol detection (
response.used_protocol) - Millisecond-precision timeouts
- IPv4/IPv6 control
- SNI and Host header overrides
- Rotating proxy support
-
requests-stylehistoryandallow_redirects
What's new
Session lifecycle
You can now explicitly destroy sessions and manage cookies at the Go layer:
session = noble_tls.Session(client=Client.CHROME_133)
# Do your work...
res = await session.get("https://example.com")
# Manage cookies in the Go session directly
cookies = await session.get_cookies("https://example.com")
await session.add_cookies("https://example.com", [
{"name": "sid", "value": "abc", "domain": "example.com", "path": "/"},
])
# Free Go memory and connections when done
await session.close()
# Or nuke everything at once
await Session.close_all()
Protocol detection
Every response now tells you which protocol was actually negotiated. Using a Protocol enum:
from noble_tls import Protocol
res = await session.get("https://example.com")
print(res.used_protocol) # Protocol.HTTP_2
if res.used_protocol == Protocol.HTTP_3:
print("Running over QUIC")
HTTP/3 and protocol racing
HTTP/3 (QUIC) support, with the ability to race HTTP/2 against HTTP/3 the way Chrome does (300ms head start for H2, H3 can still win):
session = noble_tls.Session(
ja3_string="...",
protocol_racing=True,
h3_settings={"QPACK_MAX_TABLE_CAPACITY": 4096},
h3_settings_order=["QPACK_MAX_TABLE_CAPACITY"],
h3_pseudo_header_order=[":method", ":authority", ":scheme", ":path"],
h3_send_grease_frames=True,
)
You can also just disable H3 if it causes problems: disable_http3=True.
Network and security options
Per-session network and security settings:
session = noble_tls.Session(
client=Client.CHROME_133_PSK,
disable_ipv6=True, # IPv4 only
local_address="0.0.0.0:0", # Bind to specific interface (host:port)
server_name_overwrite="sni.com", # Override TLS SNI
is_rotating_proxy=True, # Force new connection per request
without_cookie_jar=True, # Disable cookie jar entirely
certificate_pinning={ # HPKP - reject if pin doesn't match
"example.com": ["sha256_pin_base64"],
},
)
# Per-request: millisecond timeout, host override, stream to file
res = await session.get(
"https://example.com",
timeout_milliseconds=2500,
request_host_override="other.host.com",
stream_output_path="/tmp/response.json",
stream_output_block_size=4096,
)
ECH, ALPS, and post-quantum curves
Encrypted Client Hello, Application Layer Protocol Settings, and post-quantum key share curves for custom TLS configurations:
session = noble_tls.Session(
ja3_string="...",
alps_protocols=["h2"],
ech_candidate_payloads=[256],
ech_candidate_cipher_suites=[
{"kdfId": "HKDF_SHA256", "aeadId": "AEAD_AES_128_GCM"},
],
key_share_curves=["GREASE", "X25519MLKEM768", "X25519"],
supported_signature_algorithms=[
"ECDSAWithP256AndSHA256",
"PSSWithSHA256",
"Ed25519",
],
record_size_limit=16384,
allow_http=True,
stream_id=1,
)
Updated browser profiles
76 profiles now, synced with the latest Go source. New additions:
| Browser | New profiles |
|---|---|
| Chrome | 130 PSK, 144, 144 PSK, 146 PSK |
| Firefox | 123, 133, 146 PSK, 147 PSK |
| Safari | iOS 18.5, iOS 26.0 |
Removed CHROME_141 and CHROME_142
Default headers (multi-value)
Separate from the regular headers dict, default_headers uses a multi-value format and acts as a fallback when no headers are specified on a request:
session = noble_tls.Session(
client=Client.CHROME_133,
default_headers={"Accept": ["text/html", "application/json"]},
)
:shield: Need antibot bypass?
TLS fingerprinting alone won't get past modern bot protection. Hyper Solutions provides API endpoints that generate valid antibot tokens for:
Akamai | DataDome | Kasada | Incapsula
No browser automation. Simple API calls that return the cookies and headers these systems expect.
Get your API key | Docs | Discord
Examples
The syntax follows requests closely. Most things work the same way.
Example 1 -- Preset browser profile:
Available client identifiers (76 profiles)
| Chrome | Safari | Firefox | Opera |
|---|---|---|---|
CHROME_103 |
SAFARI_15_6_1 |
FIREFOX_102 |
OPERA_89 |
CHROME_104 |
SAFARI_16_0 |
FIREFOX_104 |
OPERA_90 |
CHROME_105 |
SAFARI_IPAD_15_6 |
FIREFOX_105 |
OPERA_91 |
CHROME_106 |
SAFARI_IOS_15_5 |
FIREFOX_106 |
|
CHROME_107 |
SAFARI_IOS_15_6 |
FIREFOX_108 |
|
CHROME_108 |
SAFARI_IOS_16_0 |
FIREFOX_110 |
|
CHROME_109 |
SAFARI_IOS_17_0 |
FIREFOX_117 |
|
CHROME_110 |
SAFARI_IOS_18_0 |
FIREFOX_120 |
|
CHROME_111 |
SAFARI_IOS_18_5 |
FIREFOX_123 |
|
CHROME_112 |
SAFARI_IOS_26_0 |
FIREFOX_132 |
|
CHROME_116_PSK |
FIREFOX_133 |
||
CHROME_116_PSK_PQ |
FIREFOX_135 |
||
CHROME_117 |
FIREFOX_146_PSK |
||
CHROME_120 |
FIREFOX_147 |
||
CHROME_124 |
FIREFOX_147_PSK |
||
CHROME_130_PSK |
|||
CHROME_131 |
|||
CHROME_131_PSK |
|||
CHROME_133 |
|||
CHROME_133_PSK |
|||
CHROME_144 |
|||
CHROME_144_PSK |
|||
CHROME_146 |
|||
CHROME_146_PSK |
| Mobile / App |
|---|
ZALANDO_ANDROID_MOBILE, ZALANDO_IOS_MOBILE |
NIKE_IOS_MOBILE, NIKE_ANDROID_MOBILE |
CLOUDSCRAPER |
MMS_IOS, MMS_IOS_1, MMS_IOS_2, MMS_IOS_3 |
MESH_IOS, MESH_IOS_1, MESH_IOS_2 |
MESH_ANDROID, MESH_ANDROID_1, MESH_ANDROID_2 |
CONFIRMED_IOS, CONFIRMED_ANDROID |
OKHTTP4_ANDROID_7 through OKHTTP4_ANDROID_13 |
import asyncio
import noble_tls
from noble_tls import Client
async def main():
await noble_tls.update_if_necessary()
session = noble_tls.Session(
client=Client.CHROME_133,
random_tls_extension_order=True
)
res = await session.get(
"https://www.example.com/",
headers={"key1": "value1"},
proxy="http://user:password@host:port"
)
print(res.status_code)
print(res.used_protocol)
print(res.text)
await session.close()
asyncio.run(main())
Example 2 -- Custom JA3 fingerprint:
import asyncio
import noble_tls
async def main():
await noble_tls.update_if_necessary()
session = noble_tls.Session(
ja3_string="771,4865-4866-4867-49195-49199-49196-49200-52393-52392-49171-49172-156-157-47-53,0-23-65281-10-11-35-16-5-13-18-51-45-43-27-17513,29-23-24,0",
h2_settings={
"HEADER_TABLE_SIZE": 65536,
"MAX_CONCURRENT_STREAMS": 1000,
"INITIAL_WINDOW_SIZE": 6291456,
"MAX_HEADER_LIST_SIZE": 262144
},
h2_settings_order=[
"HEADER_TABLE_SIZE",
"MAX_CONCURRENT_STREAMS",
"INITIAL_WINDOW_SIZE",
"MAX_HEADER_LIST_SIZE"
],
supported_signature_algorithms=[
"ECDSAWithP256AndSHA256",
"PSSWithSHA256",
"PKCS1WithSHA256",
"ECDSAWithP384AndSHA384",
"PSSWithSHA384",
"PKCS1WithSHA384",
"PSSWithSHA512",
"PKCS1WithSHA512",
],
supported_versions=["GREASE", "1.3", "1.2"],
key_share_curves=["GREASE", "X25519"],
cert_compression_algo="brotli",
pseudo_header_order=[":method", ":authority", ":scheme", ":path"],
connection_flow=15663105,
header_order=["accept", "user-agent", "accept-encoding", "accept-language"]
)
res = await session.post(
"https://www.example.com/",
headers={"key1": "value1"},
proxy="http://user:password@host:port"
)
print(res.text)
await session.close()
asyncio.run(main())
More examples in the examples/ folder.
Pyinstaller / Pyarmor
If you want to pack the library with Pyinstaller or Pyarmor, add this to your command:
Linux - Ubuntu / x86:
--add-binary '{path_to_library}/tls_client/dependencies/tls-client-x86.so:tls_client/dependencies'
Linux Alpine / AMD64:
--add-binary '{path_to_library}/tls_client/dependencies/tls-client-amd64.so:tls_client/dependencies'
MacOS M1 and older:
--add-binary '{path_to_library}/tls_client/dependencies/tls-client-x86.dylib:tls_client/dependencies'
MacOS M2:
--add-binary '{path_to_library}/tls_client/dependencies/tls-client-arm64.dylib:tls_client/dependencies'
Windows:
--add-binary '{path_to_library}/tls_client/dependencies/tls-client-64.dll;tls_client/dependencies'
One final note
Package is named after Admiral Atticus Noble in Rebel Moon: Part One - A Child of Fire
Acknowledgements
Big shout out to Bogdanfinn for open sourcing his tls-client in Go, and FlorianREGAZ for the original Python wrapper.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file noble_tls-0.1.9.tar.gz.
File metadata
- Download URL: noble_tls-0.1.9.tar.gz
- Upload date:
- Size: 29.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.10.11
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
710a391be6846c4dbbccf5a39cd859ea77d3329d892856fe474ceab4875d28ac
|
|
| MD5 |
b451c4fab76d99f44482d6302a325d5a
|
|
| BLAKE2b-256 |
aca522a14b5328154ea2bf7832397b305ff5aaa618aa660d6c96366ace2333ea
|
File details
Details for the file noble_tls-0.1.9-py3-none-any.whl.
File metadata
- Download URL: noble_tls-0.1.9-py3-none-any.whl
- Upload date:
- Size: 30.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.10.11
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8173a95e1f79c8ab72c3680fe55ed23611383f89978ebc1905a569266a035404
|
|
| MD5 |
587464ac55cd45a411d874fc0bd9dcff
|
|
| BLAKE2b-256 |
0719c5c351490f98021377bbea45ff57f1043821934ae61efed559982b0db938
|