Skip to main content

lkrequest

A Python HTTP client with TLS/HTTP2/TCP fingerprint control. Powered by Rust for high performance.

English | 简体中文

Features

  • Browser fingerprint emulation — TLS/HTTP2/TCP fingerprint presets for Chrome, Firefox, and Safari
  • Custom fingerprints — Fully programmable TlsProfile / H2Profile / TcpFingerprint, with JSON serialization
  • Fingerprint randomizationClient(randomize=Randomize.extension_order()) permutes TLS extension order per connection (drifts JA3, keeps JA4 stable, still a real browser); client.randomize_fingerprint() generates a unique variant to reduce correlation risk
  • Client poolClientPool automatically rotates across multiple fingerprints
  • Async & sync APIs — Both asyncio async and traditional synchronous calls
  • WebSocket — wss:// connections with consistent fingerprinting
  • Streaming responsessend_streaming() receives large files chunk by chunk
  • Cookie management — Automatic cookie jar, with manual management, attribute setting, and overrides
  • Proxy support — HTTP CONNECT / SOCKS5 proxies, authentication, and ordered multi-hop chains; QUIC/H3 works over all-SOCKS5 chains
  • Proxy pool & session pool — Built-in proxy rotation, bad-proxy marking, and session management
  • Multipart — File upload support
  • Retry strategies — Exponential backoff / fixed interval / custom callable retries
  • Middleware — Request/response interception and modification (onion model)
  • Event hooks — Lightweight request/response callbacks
  • Connection prewarmingpreconnect() / prefetch() to batch-establish connections
  • Prometheus metrics — Built-in request counters, latency histograms, exposition-format export
  • Request diagnosticsresponse.diagnostics exposes per-request phase timings (DNS/TCP/TLS/TTFB/total) plus remote_addr/protocol/cipher_suite
  • Runtime metrics snapshotmetrics_snapshot() pulls process-level wire bytes / connection / request counters (for host-side collection; real values require the telemetry feature)
  • Zero-copy Responsebytes::Bytes + PyBuffer protocol + text/json caching
  • Automatic decompression — Brotli / gzip / deflate / zstd, with controllable AcceptEncoding
  • Certificate management — Custom CA / disable verification / system certificates
  • ECH — Encrypted Client Hello support, including TLS/QUIC HelloRetryRequest handling
  • Request priorityRequestPriority (RFC 9218 urgency/incremental), session.get(url, priority=...)
  • Protocol policyProtocolPolicy / HttpIntent control H2/H3 selection, acquisition, and fallback (client / session / request level)
  • Session resumption controlSessionResumptionConfig controls TLS1.3 PSK / TLS1.2 ticket resumption
  • Request-level protocol overridepreferred_http_version / idempotency (0-RTT replay-safety declaration)
  • QUIC / HTTP3 — Optional feature (maturin develop --features quic-h3): session(http3_only=True / http3_with_fallback=True / broken_quic_policy=BrokenQuicPolicy.Resilient); Client(quic_fingerprint=..., quic_profile="chrome_150", disable_http3=True); dedicated Chrome 146/150 QuicProfile presets (available only when the feature is enabled)
  • Synthetic fingerprints (advanced) — Optional feature (maturin develop --features synthetic-fp): Client(randomize=Randomize.recombine()) synthesizes a cross-layer (TLS+H2+H3) unique identity per session; Randomize.full() additionally draws out-of-corpus values for H2/QUIC; the Layers mask (e.g. Randomize.recombine_layers(Layers.TLS | Layers.H2)) restricts which layers are synthesized. Synthetic fingerprints match no real browser and are only for blocklist (negative-model) targets — against an allowlist they fail instantly

Installation

Using pip:

pip install lkrequest

In a project managed by uv:

uv add lkrequest

Development environment

Using venv and pip:

git clone https://github.com/EZ-XLabs/lkrequest-py
cd lkrequest-py
python3 -m venv .venv                 # Linux/macOS
# py -m venv .venv                    # Windows
source .venv/bin/activate             # Linux/macOS
# .venv\Scripts\Activate.ps1          # Windows PowerShell
python -m pip install --upgrade pip
python -m pip install maturin
python -m pip install -e ".[test,lint]"

Using uv (creates and manages .venv automatically):

git clone https://github.com/EZ-XLabs/lkrequest-py
cd lkrequest-py
uv sync --extra test --extra lint

Quick Start

Async API

import asyncio
import lkrequest

async def main():
    client = lkrequest.Client.chrome_144()
    session = client.session()

    # GET request
    resp = await session.get("https://httpbin.org/get", params={"key": "value"})
    print(resp.status_code)  # 200
    print(resp.json())

    # POST JSON
    resp = await session.post("https://httpbin.org/post", json={"hello": "world"})
    print(resp.json())

    # Concurrent requests
    urls = [f"https://httpbin.org/get?id={i}" for i in range(5)]
    responses = await asyncio.gather(*[session.get(url) for url in urls])

asyncio.run(main())

Sync API

from lkrequest.blocking import Client

client = Client.chrome_131()
session = client.session()

resp = session.get("https://httpbin.org/get")
print(resp.status_code)
print(resp.text())
print(resp.json())

All HTTP methods

session.get(url)
session.post(url, json={"key": "value"})
session.put(url, json={"key": "value"})
session.patch(url, json={"field": "new_value"})
session.delete(url)
session.head(url)
session.options(url)

Authentication

# Bearer Token
resp = session.get("https://httpbin.org/bearer", bearer_auth="my-token")

# Basic Auth
resp = session.get(
    "https://httpbin.org/basic-auth/user/pass",
    basic_auth=("user", "pass"),
)

Custom client

client = lkrequest.Client(
    tls_profile="chrome_144",
    h2_profile="chrome_144",
    tcp_fingerprint="chrome_win",
    default_headers={"Accept-Language": "zh-CN"},
    header_order=["Host", "User-Agent", "Accept"],
    total_timeout=30.0,
    tcp_connect_timeout=10.0,
    max_connections_per_session=16,
    h2_fallback_h1=True,
    proxy_fallback_direct=True,
)

Retry strategies

# Exponential backoff retry
session = client.session(
    retry=lkrequest.ExponentialBackoff(max_retries=3, base_delay=0.5, max_delay=30.0, jitter=True)
)

# Fixed interval retry
session = client.session(
    retry=lkrequest.FixedInterval(max_retries=5, interval=1.0)
)

# Custom retry strategy (callable)
def my_retry(attempt: int, error: str | None, status: int | None) -> float | None:
    if status == 429:
        return min(2 ** attempt, 30)
    if attempt < 3:
        return 1.0
    return None  # give up

session = client.session(retry=my_retry)

Middleware

def log_request(req_dict):
    print(f"{req_dict['method']} {req_dict['url']}")
    return req_dict

def log_response(resp_dict):
    print(f"  → {resp_dict['status']}")
    return resp_dict

# Client-level middleware
client = lkrequest.Client(
    middleware=[lkrequest.Middleware("logger", on_request=log_request, on_response=log_response)]
)

# Session-level middleware
session = client.session(
    middleware=[lkrequest.Middleware("auth", on_request=inject_auth)]
)

Event hooks

A lighter-weight callback mechanism than middleware, for observing requests/responses without modifying them.

def on_req(method, url, headers):
    print(f"→ {method} {url}")

def on_resp(status_code, url, elapsed):
    print(f"← {status_code} {url} ({elapsed:.3f}s)")

# Bind when creating the session
session = client.session(on_request=on_req, on_response=on_resp)

# Or add dynamically
session.on_request(on_req)
session.on_response(on_resp)

Cookie management

# Basic operations
session.set_cookie("https://example.com", "token", "abc123")
val = session.get_cookie("https://example.com", "token")
cookies = session.get_cookies("https://example.com")
header = session.cookie_header("https://example.com")

# With attributes
session.set_cookie_with_attrs(
    "https://example.com", "secure_token", "xyz",
    path="/api", domain="example.com", secure=True, http_only=True,
)

# Remove and clear
session.remove_cookie("https://example.com", "token")
session.clear_cookies()

# Request-level cookie override
resp = session.get(url, cookie_override={"token": "override_value"})

Multipart file upload

mp = lkrequest.Multipart()
mp.text("title", "File upload")
mp.file("document", "report.pdf", "application/pdf", pdf_bytes)
resp = session.post("https://example.com/upload", multipart=mp)

Streaming responses

# Async
stream = await session.send_streaming("GET", "https://example.com/large-file")
async for chunk in stream:
    process(chunk)

# Or read all at once
body = await stream.bytes()
text = await stream.text()

Connection prewarming

Establish TLS connections ahead of time to reduce first-request latency.

# Batch prewarming
results = await session.prefetch([
    "https://api.example.com",
    "https://cdn.example.com",
])
for r in results:
    print(f"{r['url']}: {'ok' if r['success'] else r['error']} ({r['duration_ms']:.0f}ms)")

# Single-connection prewarming
await session.preconnect("https://api.example.com")

# Sync version
session.preconnect("https://api.example.com")
results = session.prefetch(["https://api.example.com"])

WebSocket

# Async
ws = await session.ws_connect("wss://echo.websocket.events")
await ws.send_text("hello")
msg = await ws.recv()
async for msg in ws:
    print(msg)
    break
await ws.close()

# Sync
ws = session.ws_connect("wss://echo.websocket.events")
ws.send_text("hello")
msg = ws.recv()
ws.close()

Proxy

# Single proxy
session = client.session(proxy="socks5://user:pass@host:1080")

# Multi-hop chain: client -> hop1 -> hop2 -> target
chain = lkrequest.ProxyConfig.parse_chain([
    "socks5://user:pass@hop1:1080",
    "socks5h://user:pass@hop2:1080",
])
session = client.session(proxy=chain, http3_with_fallback=True)

# Request-level proxy override
resp = await session.get("https://example.com", proxy="http://other-proxy:8080")

# Proxy pool
pool = lkrequest.ProxyPool(
    ["socks5://proxy1:1080", "socks5://proxy2:1080", "http://proxy3:8080"],
    rotation="round_robin",  # or "random"
    bad_proxy_config=lkrequest.BadProxyConfig(
        failure_threshold=5, window=120.0, cooldown_duration=300.0, max_cooldowns=5,
    ),
    health_check=lkrequest.HealthCheckConfig(
        interval=30.0, timeout=3.0, target_host="www.google.com", target_port=443,
    ),
)
proxy = await pool.acquire()

TCP-based HTTP supports mixed HTTP CONNECT and SOCKS5 hops. QUIC/HTTP3 requires every hop in the chain to be SOCKS5; a chain containing an HTTP hop falls back to H2 when http3_with_fallback=True.

Session pool

# Async
pool = lkrequest.SessionPool(client=client, proxies=[...], max_sessions=10)
guard = await pool.acquire()
async with guard as session:
    resp = await session.get("https://example.com")

# Sync
from lkrequest.blocking import Client, SessionPool
pool = SessionPool(client=client, proxies=[...])
with pool.acquire() as session:
    resp = session.get("https://example.com")

Client pool

Automatically rotate across multiple fingerprints to reduce fingerprint correlation.

pool = lkrequest.ClientPool(
    [lkrequest.Client.chrome_144(), lkrequest.Client.firefox_147(), lkrequest.Client.safari_26()],
    rotation="round_robin",  # or "random"
)
client = pool.acquire()
pool.add(lkrequest.Client.chrome_131())  # add dynamically
print(len(pool))  # 4

Custom fingerprints

Fully programmable TLS, HTTP/2, and TCP fingerprint configuration.

# Custom TLS Profile
tls = lkrequest.TlsProfile(
    "my_browser",
    cipher_suites=[0x1301, 0x1302, 0x1303, 0xc02b, 0xc02f],
    extensions=[
        lkrequest.ExtensionSpec(lkrequest.ExtType.SNI),
        lkrequest.ExtensionSpec(lkrequest.ExtType.ALPN),
        lkrequest.ExtensionSpec(lkrequest.ExtType.SUPPORTED_GROUPS),
        lkrequest.ExtensionSpec(lkrequest.ExtType.KEY_SHARE),
        lkrequest.ExtensionSpec(lkrequest.ExtType.SUPPORTED_VERSIONS),
        lkrequest.ExtensionSpec(lkrequest.ExtType.SIGNATURE_ALGORITHMS),
    ],
    alpn_protocols=["h2", "http/1.1"],
    grease=lkrequest.GreaseConfig(extensions=True, key_share=True),
    padding=lkrequest.PaddingStrategy.block_align(128, 512),
)

# Custom H2 Profile
h2 = lkrequest.H2Profile(
    [
        lkrequest.H2Setting("header_table_size", 65536),
        lkrequest.H2Setting("initial_window_size", 6291456),
        lkrequest.H2Setting("max_header_list_size", 262144),
    ],
    15663105,  # window_update
    ["method", "authority", "scheme", "path"],
    headers_priority=lkrequest.HeadersPriority(0, 255, True),
)

# Custom TCP Fingerprint
tcp = lkrequest.TcpFingerprint(window_size=65535, mss=1460, window_scale=8, ttl=128)

# Combine them
client = lkrequest.Client(tls_profile=tls, h2_profile=h2, tcp_fingerprint=tcp)

# Serialize / deserialize
json_str = tls.to_json()
restored = lkrequest.TlsProfile.from_json(json_str)

# Fingerprint randomization
randomized = client.randomize_fingerprint(shuffle_extensions=True)

# Randomization strategy (Randomize): pass to Client(randomize=...)
# Tier 1 (always available): permute TLS extension order per connection, drift JA3 but stay a real browser
client = lkrequest.Client(tls_profile="chrome_146",
                          randomize=lkrequest.Randomize.extension_order())

# Tier 3a/3b (requires the synthetic-fp feature): synthesize a cross-layer unique identity per session
#   from lkrequest import Randomize, Layers
#   client = lkrequest.Client(tls_profile="chrome_146",
#                             randomize=Randomize.recombine())                 # all layers
#   client = lkrequest.Client(tls_profile="chrome_146",
#                             randomize=Randomize.recombine_layers(Layers.TLS | Layers.H2))

Fingerprint consistency validation

result = lkrequest.validate_fingerprint_consistency(
    tls_profile="chrome_144", h2_profile="chrome_144", tcp_fingerprint="chrome_win",
)
print(result["valid"])     # True
print(result["warnings"])  # []

Timeout configuration

# Client-level timeouts
client = lkrequest.Client(
    dns_timeout=5.0,
    tcp_connect_timeout=10.0,
    tls_handshake_timeout=10.0,
    ttfb_timeout=15.0,
    total_timeout=30.0,
)

# Request-level timeout override
resp = session.get("https://example.com", timeout=5.0)

# TimeoutConfig object
tc = lkrequest.TimeoutConfig(total=30.0, tcp_connect=10.0)

# ResourceLimits
rl = lkrequest.ResourceLimits(max_response_body_size=10*1024*1024, max_connections_per_session=16)

AcceptEncoding control

ae = lkrequest.AcceptEncoding

# Session level
session = client.session(accept_encoding=ae.GZIP | ae.BR)

# Request level
resp = session.get(url, accept_encoding=ae.GZIP)

# Disable automatic decompression
resp = session.get(url, no_decompress=True)

Header / Cookie order

header_order (header send order) and cookie_order (ordering within the Cookie header) can be set at three levels, with lower levels overriding higher ones:

# Client level (applies to all sessions of this client)
client = lkrequest.Client(
    header_order=["host", "user-agent", "accept", "accept-encoding", "cookie"],
    cookie_order=["session_id", "csrf_token"],
)

# Session level (overrides client level)
session = client.session(
    header_order=["host", "user-agent", "accept"],
    cookie_order=["session_id", "csrf_token"],
)

# Request level (overrides session and client levels)
resp = await session.get(
    url,
    header_order=["host", "user-agent", "accept"],
    cookie_order=["session_id", "csrf_token"],
)

Ordered / duplicate headers, params, data

headers, params, and data accept either a dict (preserves insertion order) or a list[tuple[str, str]] (preserves order and allows duplicate keys, for repeated params like ?tag=a&tag=b):

# Duplicate query params: ?tag=a&tag=b
resp = session.get(url, params=[("tag", "a"), ("tag", "b")])

# Duplicate form fields
resp = session.post(url, data=[("k", "1"), ("k", "2")])

# Explicit header ordering (a dict is also sent in insertion order)
resp = session.get(url, headers=[("user-agent", "..."), ("accept", "*/*")])

base_url, generic request(), connection pool cleanup

# base_url: relative paths are auto-joined; passing an absolute URL overrides base_url
session = client.session(base_url="https://api.example.com")
resp = await session.get("/v1/users", params={"page": "1"})

# Generic request(): specify the method explicitly (any case)
resp = await session.request("PATCH", "/v1/users/1", json={"name": "x"})

# Only allow redirects to HTTPS; clear the connection pool
session = client.session(https_only=True)
session.pool_clear()

HSTS / http→https upgrade policy

Browsers upgrade http:// requests to https:// before connecting for known HSTS (or preloaded) hosts. The default (no hsts) is a stateless "first visit" that performs no upgrade. Host matching is suffix-based (equivalent to HSTS includeSubDomains).

# Dynamically learn HSTS hosts within the session from response Strict-Transport-Security headers (like a long-running browser)
session = client.session(hsts=lkrequest.Hsts.dynamic())

# Seed known HSTS hosts (e.g. replay state learned in a previous session)
session = client.session(hsts=lkrequest.Hsts.dynamic(seed=["example.com"]))

# Fixed allowlist; preloaded_tlds=True also upgrades Chrome's fully-preloaded gTLDs (.dev/.app/…)
session = client.session(hsts=lkrequest.Hsts.static_(["example.com"], preloaded_tlds=True))

Request-level protocol override

# Each request can override session-level protocol policy / intent, plus HTTP/3-specific header order
resp = await session.get(
    url,
    protocol_policy=lkrequest.ProtocolPolicy.chrome_conservative(),
    http_intent=lkrequest.HttpIntent.H2Only,
    h3_header_order=["host", "user-agent", "accept"],
)

h3_header_order can also be set on Client(...) and session(...) (same three levels as header_order).

Prometheus metrics

collector = lkrequest.enable_metrics()

# View stats after making requests
stats = collector.snapshot()
print(collector.prometheus_text())
collector.reset()

Request diagnostics & runtime metrics

response.diagnostics returns per-request phase timings (no OpenTelemetry dependency, collected directly by the Rust engine):

resp = await session.get("https://example.com")
print(resp.diagnostics)
# {'dns_ms': 3, 'tcp_ms': 0, 'tls_ms': 423, 'ttfb_ms': 193, 'total_ms': 621,
#  'remote_addr': '93.184.216.34:443', 'protocol': 'h2', 'cipher_suite': '0x1301'}
# dns_ms/tcp_ms/tls_ms are None on a reused connection (that phase did not occur)

metrics_snapshot() pulls process-level runtime counters for you to feed into your own Prometheus / OTel pipeline:

snap = lkrequest.metrics_snapshot()
# {'bytes_in': ..., 'bytes_out': ..., 'requests_total': ...,
#  'requests_failed': ..., 'active_connections': ..., 'total_connections': ...}

Counters are all 0 by default; only building with the telemetry feature (maturin build --features telemetry) enables transport-layer byte counting.

Certificate management

client = lkrequest.Client(ca_cert="/path/to/ca.pem")       # file path
client = lkrequest.Client(ca_cert_pem=pem_bytes)            # PEM bytes
client = lkrequest.Client(ca_cert_der=der_bytes)            # DER bytes
client = lkrequest.Client(verify=False)                      # disable verification (dev only)
client = lkrequest.Client(use_native_certs=True)             # system certificates
client = lkrequest.Client(ech_config=ech_bytes)              # ECH support

Zero-copy Response

resp = session.get("https://example.com")

mv = memoryview(resp)       # zero-copy access to body
text = resp.text()          # cached after first decode
data = resp.json()          # cached after first parse

Logging

lkrequest.set_log_level("info")                          # global level
lkrequest.set_log_level("lkrequest=debug,lktls=trace")   # module filter
lkrequest.set_log_level("info", format="compact")        # log format
lkrequest.set_log_level("off")                           # disable

Error handling

try:
    resp = session.get(url, timeout=10.0)
    resp.error_for_status()
except lkrequest.LkTimeoutError:
    print("timed out")
except lkrequest.LkConnectionError:
    print("connection failed")
except lkrequest.TlsError:
    print("TLS error")
except lkrequest.HttpStatusError as e:
    print(f"HTTP error: {e}")
except lkrequest.TooManyRedirectsError:
    print("too many redirects")
except lkrequest.RequestError as e:
    print(f"request error: {e}")

Available Browser Fingerprints

Method TLS HTTP/2 TCP
Client.chrome_131() Chrome 131 Chrome 131 Chrome
Client.chrome_144() Chrome 144 Chrome 144 Chrome
Client.chrome_145() Chrome 145 Chrome 145 Chrome
Client.chrome_146() Chrome 146 Chrome 146 Chrome
Client.chrome_147() Chrome 147 Chrome 147 Chrome
Client.chrome_148() Chrome 148 Chrome 148 Chrome
Client.chrome_149() Chrome 149 Chrome 149 Chrome
Client.chrome_150() Chrome 150 Chrome 150 Chrome
Client.firefox_133() Firefox 133 Firefox 133 Firefox
Client.firefox_147() Firefox 147 Firefox 147 Firefox
Client.safari_18() Safari 18 Safari 18 Safari
Client.safari_26() Safari 26 Safari 26 Safari

TCP fingerprints are OS-specific: chrome_win / chrome_linux / chrome_macos / firefox_win / firefox_linux / firefox_macos / safari

API Reference

Client

Parameter Description
tls_profile TLS fingerprint (string name or TlsProfile object)
h2_profile HTTP/2 fingerprint (string name or H2Profile object)
tcp_fingerprint TCP fingerprint (string name or TcpFingerprint object)
default_headers Default request headers
header_order Header send order
cookie_order Cookie send order
dns_timeout / tcp_connect_timeout / tls_handshake_timeout / ttfb_timeout / total_timeout / quic_connect_timeout Timeout control
max_response_body_size / max_connections_per_session / max_header_count / max_header_size / max_headers_total_size / min_transfer_rate(+ min_transfer_rate_window) Resource limits / DoS protection
h2_fallback_h1 / proxy_fallback_direct / retry_on_connection_close Fault-tolerance options
middleware Middleware list
ca_cert / ca_cert_pem / ca_cert_der / verify / use_native_certs Certificate configuration
ech_config ECH configuration
dns Custom DNS
keylog TLS key log file path
Method Description
session(...) Create a session
fingerprint_info() Return a fingerprint info dict
randomize_fingerprint(shuffle_extensions=True) Return a new Client with a randomized fingerprint

Session

All HTTP methods (get/post/put/delete/head/patch/options) support:

Parameter Description
headers Request headers
params URL query params
json / data / body / multipart Request body
cookies / cookie_override Cookie control
timeout Request timeout (seconds)
bearer_auth / basic_auth Authentication
proxy Request-level proxy override
no_decompress / accept_encoding Encoding control
Method Description
send_streaming(method, url, ...) Streaming request
ws_connect(url, *, headers, protocols) WebSocket connection
preconnect(url) / preconnect_many(urls) / prefetch(urls) Connection prewarming
pool_stats() Connection pool stats (PoolStats)
on_request(callback) / on_response(callback) Register event hooks
set_cookie() / set_cookie_with_attrs() / set_cookie_raw() Set cookies
get_cookie() / get_cookies() / get_cookie_values() / cookie_header() Read cookies
remove_cookie() / clear_cookies() Remove cookies

Response

Attribute/Method Description
status_code HTTP status code
ok status code < 400
url Final URL
version HTTP version (HttpVersion.H2 / HttpVersion.HTTP11)
headers Response headers (HeaderMap, case-insensitive)
headers_list Response headers list (list[tuple[str, str]])
content Raw bytes
content_length Content-Length
text() UTF-8 text (cached)
json() Parse JSON (cached)
cookies Response cookies
encoding Character encoding
elapsed Request duration (seconds)
diagnostics Per-phase timing dict: dns_ms/tcp_ms/tls_ms/ttfb_ms/total_ms + remote_addr/protocol/cipher_suite (None for phases not measured)
was_redirected Whether it went through a redirect
history Redirect chain (list[RedirectRecord])
error_for_status() Raise HttpStatusError on 4xx/5xx
memoryview(resp) Zero-copy access to body
len(resp) / bool(resp) Length / success

HeaderMap

Method Description
headers["name"] Get header (KeyError if missing)
headers.get("name", default) Get header (returns default if missing)
headers.get_all("name") Get all headers with that name
"name" in headers Check existence
len(headers) Header count
headers.keys() / values() / items() Iterate
headers.to_dict() Convert to a dict

Fingerprint configuration

Class Description
TlsProfile TLS fingerprint config; presets / custom / JSON serialization
H2Profile HTTP/2 fingerprint config
TcpFingerprint TCP fingerprint config; supports JA4T format
ExtType TLS extension type constants
ExtensionSpec TLS extension spec
GreaseConfig GREASE injection config
PaddingStrategy Padding strategy (block_align / fixed_target / no_padding)
RandomizationConfig Fingerprint randomization config
H2Setting HTTP/2 setting (string name or integer ID)
HeadersPriority Headers priority
PriorityFrame Priority frame
ClientPool Client pool, multi-fingerprint rotation

Module functions

Function Description
set_log_level(level, *, format="compact") Set the log level
enable_metrics() Enable Prometheus metrics, returns a MetricsCollector
metrics_snapshot() Pull a process-level runtime counter dict (real values require the telemetry feature)
validate_fingerprint_consistency(...) Validate fingerprint-combination consistency

Exceptions

Exception Description
RequestError Base class
TlsError TLS handshake failure
ProxyError Proxy connection failure
HttpStatusError HTTP status error (4xx/5xx)
LkConnectionError Connection failure
LkTimeoutError Timeout
TooManyRedirectsError Too many redirects
ResourceLimitError Resource limit exceeded

Examples

The examples/ directory contains complete examples for every feature:

Example Description
basic_requests.py Basic sync/async GET/POST usage, concurrent requests
http_methods.py GET/POST/PUT/PATCH/DELETE/HEAD/OPTIONS
authentication.py Bearer Token / Basic Auth
response_inspection.py All Response attributes, HeaderMap, memoryview, redirect history
cookie_management.py Cookie CRUD, set_cookie_with_attrs, cookie_override
multipart_upload.py Multipart text + file upload, fine-grained Part control
websocket.py Sync/async WebSocket, WsMessage types
middleware.py Request/response interception, header injection, multi-layer onion model
retry_strategies.py ExponentialBackoff / FixedInterval / callable / lambda
event_hooks.py on_request/on_response callbacks
proxy_pool.py Single proxies, multi-hop chains, BadProxyConfig, HealthCheckConfig, ProxyPool
session_pool.py SessionPool / BlockingSessionPool
client_pool.py ClientPool multi-fingerprint rotation
browser_fingerprints.py 6 preset fingerprints, string specification, fingerprint randomization
custom_fingerprint.py Fully custom TlsProfile / H2Profile / TcpFingerprint
fingerprint_validation.py validate_fingerprint_consistency
streaming_response.py StreamingResponse chunked / full reads
connection_prewarming.py preconnect / preconnect_many / prefetch
metrics.py enable_metrics / snapshot / prometheus_text
timeout_config.py Timeout configuration, ResourceLimits
accept_encoding.py AcceptEncoding control, no_decompress
certificate_config.py CA cert PEM/DER/file, verify, ECH
logging_config.py set_log_level, filter directives
error_handling.py All exception types, general error-handling patterns
pool_stats.py PoolStats connection pool statistics
redirect_history.py Redirect chain, RedirectRecord

Run an example:

maturin develop
python examples/basic_requests.py

Testing

Using venv and pip:

# After completing the development setup above, run all tests
just test

# Or manually
python -m pip install -e ".[test]"
python -m pytest tests/ -v

# Run only the unit tests that don't need network
python -m pytest tests/ -v -k "not httpbin and not echo"

Using uv:

uv sync --extra test --extra lint
just test
# Or:
uv run pytest tests/ -v

Benchmark

maturin develop --release
python benchmarks/bench_latency.py     # single-request latency
python benchmarks/bench_throughput.py   # concurrent throughput
python benchmarks/bench_memory.py      # memory usage
python benchmarks/verify_fingerprint.py # TLS fingerprint verification

Download files

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

Source Distribution

lkrequest-0.1.1.tar.gz (159.9 kB view details)

Uploaded Source

Built Distributions

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

lkrequest-0.1.1-cp39-abi3-win_amd64.whl (7.2 MB view details)

Uploaded CPython 3.9+Windows x86-64

lkrequest-0.1.1-cp39-abi3-manylinux_2_28_x86_64.whl (7.5 MB view details)

Uploaded CPython 3.9+manylinux: glibc 2.28+ x86-64

lkrequest-0.1.1-cp39-abi3-macosx_11_0_arm64.whl (6.8 MB view details)

Uploaded CPython 3.9+macOS 11.0+ ARM64

lkrequest-0.1.1-cp39-abi3-macosx_10_12_x86_64.whl (7.1 MB view details)

Uploaded CPython 3.9+macOS 10.12+ x86-64

File details

Details for the file lkrequest-0.1.1.tar.gz.

File metadata

  • Download URL: lkrequest-0.1.1.tar.gz
  • Upload date:
  • Size: 159.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for lkrequest-0.1.1.tar.gz
Algorithm Hash digest
SHA256 4efdef483b48a026a9f5837370cc0fe2b0f884ae0c7f712ce1e913201dc1f0de
MD5 63d3416fc14eb043f0ce7b6f7cfe7cf3
BLAKE2b-256 68b415a5676331aea7885e48bdd7faf8b0af3c69e0ff798ddedd0d768f68ca9a

See more details on using hashes here.

Provenance

The following attestation bundles were made for lkrequest-0.1.1.tar.gz:

Publisher: ci.yml on EZ-XLabs/lkrequest-py

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file lkrequest-0.1.1-cp39-abi3-win_amd64.whl.

File metadata

  • Download URL: lkrequest-0.1.1-cp39-abi3-win_amd64.whl
  • Upload date:
  • Size: 7.2 MB
  • Tags: CPython 3.9+, Windows x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for lkrequest-0.1.1-cp39-abi3-win_amd64.whl
Algorithm Hash digest
SHA256 e116d9c2d5d467955bb804d470881097707bbea947955e1db48c9ff06db714fe
MD5 aed63ef3c977539f3421c51e08efe9d9
BLAKE2b-256 373679d57a415519eceef7c788a83dd1e9e9ce349b5cb150c78a2ad3e96f21f6

See more details on using hashes here.

Provenance

The following attestation bundles were made for lkrequest-0.1.1-cp39-abi3-win_amd64.whl:

Publisher: ci.yml on EZ-XLabs/lkrequest-py

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file lkrequest-0.1.1-cp39-abi3-manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for lkrequest-0.1.1-cp39-abi3-manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 bf2ff1906ece6fe8127a62d05381d9662fd9402dd72e4c3657e3fb5fccdb25ad
MD5 38bb69a2fa1a9649cdd5f85b89ea9155
BLAKE2b-256 e3ffe0e5ad0ef59ae16bb1600a905042709016429b9ba909a3bf8445a70d7b5b

See more details on using hashes here.

Provenance

The following attestation bundles were made for lkrequest-0.1.1-cp39-abi3-manylinux_2_28_x86_64.whl:

Publisher: ci.yml on EZ-XLabs/lkrequest-py

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file lkrequest-0.1.1-cp39-abi3-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for lkrequest-0.1.1-cp39-abi3-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 6ae5cb3e6b1da42884ba6653f64b662ef5731ca70d30a9db9b28aaef68e8cc24
MD5 0d4474ad27b8d5f1513215817aeeec55
BLAKE2b-256 3204e50aa6ec49402c3270661582c08fea8936253be2e3b48b0c1489fdc6b229

See more details on using hashes here.

Provenance

The following attestation bundles were made for lkrequest-0.1.1-cp39-abi3-macosx_11_0_arm64.whl:

Publisher: ci.yml on EZ-XLabs/lkrequest-py

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file lkrequest-0.1.1-cp39-abi3-macosx_10_12_x86_64.whl.

File metadata

File hashes

Hashes for lkrequest-0.1.1-cp39-abi3-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 77f1bb61b436693e7b2ff808567aadb65166a5566fde4ff705a5dba7ba773131
MD5 f2b50c78ef685ef838e46c3a468dab19
BLAKE2b-256 ea1c59a309722143b74ca392d0fdd5da51c7b06dd865bcfb64eb1e3f72ac38dc

See more details on using hashes here.

Provenance

The following attestation bundles were made for lkrequest-0.1.1-cp39-abi3-macosx_10_12_x86_64.whl:

Publisher: ci.yml on EZ-XLabs/lkrequest-py

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

0.2.1

5 files

0.2.0

5 files

This release

0.1.1 This release

5 files

0.1.0

5 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page