Skip to content

rawandahmad698/noble-tls

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

81 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Noble TLS

Python 3.10

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-style history and allow_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"]},
)

🛡️ 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.

About

TLS-Spoofing HTTP library, based on requests. Automatically updates JA3 fingerprints.

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages