Skip to main content

Advanced TLS/SSL wrapper for Python

Project description

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"]},
)

: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


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

noble_tls-0.1.8.tar.gz (29.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

noble_tls-0.1.8-py3-none-any.whl (30.2 kB view details)

Uploaded Python 3

File details

Details for the file noble_tls-0.1.8.tar.gz.

File metadata

  • Download URL: noble_tls-0.1.8.tar.gz
  • Upload date:
  • Size: 29.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.10.11

File hashes

Hashes for noble_tls-0.1.8.tar.gz
Algorithm Hash digest
SHA256 a841d35994995bd8df46f4dc383d17f8a6897a17a8599862500271bbfc6228cb
MD5 73a3c1e106da9ed47c44f1a1bd119301
BLAKE2b-256 d057301957bee0eeddf3b659ee96deb09113dbc74a548d213567a01e5ddb7b22

See more details on using hashes here.

File details

Details for the file noble_tls-0.1.8-py3-none-any.whl.

File metadata

  • Download URL: noble_tls-0.1.8-py3-none-any.whl
  • Upload date:
  • Size: 30.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.10.11

File hashes

Hashes for noble_tls-0.1.8-py3-none-any.whl
Algorithm Hash digest
SHA256 e9fc2d961335e57f1912e73187829ff1d8b8fc102882d87bc91f93ebae7593da
MD5 d68282e27925c435d6cc93e78b018834
BLAKE2b-256 3d30849f1ae1ee1e8469b63e09df9bbcc5ddb8ee768e2b120e9d7f6dbaf30eeb

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page