Skip to main content
Pre-release

This release is a pre-release and may not be stable for production use.

wulu-geetest-bypass

GitHub Actions Workflow Status Python License Geetest v4 downloads

English | 简体中文

A lightweight, pure Python library to automatically solve Geetest Behavioral CAPTCHA v4 without Node.js or headless browsers. Features dynamic mouse trajectory simulation, 7 built-in risk type solvers, accessible voice bypass, and an extensible custom solver registry.

✨ Features

  • 🚀 Pure Python 3.11+ — Zero Node.js, headless browsers, or external runtime dependencies required.
  • 🛡️ Multi-Risk Type Support — Out-of-the-box solvers for 7 risk types (see full table).
  • 🎯 Human-like Track Simulation — Dynamically generated mouse trajectories for every run (no fixed replays).
  • 🔁 Smart Auto-Retry — One-call resolve() automatically retries up to 3 times on transient failures.
  • 🕹️ Granular Step-by-Step Flow — Separate load() and verify() steps for intercepting payloads and tokens.
  • ♿ Accessible Voice Bypass — Seamlessly switch to offline speech recognition when the voice channel is enabled.
  • 🔌 Extensible Solver Registry — Easily plug in custom OCR / Vision models, or override built-in solvers.
  • 🌐 Advanced Networking — Native support for proxy chains, browser TLS fingerprint emulation, and custom headers.

🧩 Supported Risk Types

Type Description Dependency Support
ai Silent verification none ✅
slide Slider puzzle [slide] ✅
match 3×3 connect none ✅
winlinze Gomoku none ✅
svg_seed SVG 3x3 image selection [svg] ✅
svg_icon SVG 2x2 icon selection [svg] ✅
voice Voice verification [voice] ✅
icon Direction icon click [icon] 🧪
Similarity icon click none ❌
word Word click none ❌
nine Nine-grid none ❌
phrase Phrase recognition none ❌
pencil Doodle none ❌
space Spatial reasoning none ❌

The Dependency column refers to the dependency groups below.

  • ✅ — Built-in solver, ready to use.
  • 🧪 — Experimental solver; not fully validated.
  • ❌ — No built-in solver; register your own via custom solvers.

📦 Installation

uv is recommended (faster, more modern Python package manager):

uv add "wulu-geetest-bypass[all]"

You can also use pip:

pip install "wulu-geetest-bypass[all]"

Dependency groups (install only what you need):

# voice verification
uv add "wulu-geetest-bypass[voice]"

# slide puzzle (requires opencv)
uv add "wulu-geetest-bypass[slide]"

# SVG icon & seed selection
uv add "wulu-geetest-bypass[svg]"

# icon click (direction-type questions)
uv add "wulu-geetest-bypass[icon]"
wulu-geetest download icon  # prefetch the model

# Install everything
uv add "wulu-geetest-bypass[all]"

Command line

New in 0.5.0. The wulu-geetest command, the downloads entry point group and the --endpoint flag do not exist in 0.4.x and earlier. Upgrade with uv add -U wulu-geetest-bypass.

The package installs a wulu-geetest command. Extensions that ship a large model register a downloader through the wulu_geetest_bypass.downloads entry point group, and the CLI discovers them — one command covers all of them:

wulu-geetest download --list    # models the installed extensions can provide
wulu-geetest download <name>    # download one (skipped when already cached)
wulu-geetest download --all     # download every registered model
wulu-geetest download --all -f  # force a re-download

Models are fetched on first use anyway; the command is for prefetching, e.g. when baking them into an image. --quiet hides the progress bar, which is also hidden automatically when stderr is not a terminal. --endpoint <url> routes the download through a mirror instead — e.g. --endpoint https://hf-mirror.com when the default host is unreachable.

For extension authors: register download_model(progress=None, *, force=False) -> Path under the same entry point group — the name you pick becomes the CLI argument. The full contract is in the wulu_geetest_bypass.cli.discover_downloads docstring.

🚀 Quick Start

import asyncio
from wulu_geetest_bypass import Geetest


async def main():
    g = Geetest(captcha_id='your_captcha_id', risk_type='slide')
    result = await g.resolve()
    print(result)
    # {
    #     "captcha_id": "xxx",
    #     "lot_number": "xxx",
    #     "pass_token": "xxx",
    #     "gen_time": "xxx",
    #     "captcha_output": "xxx"
    # }


asyncio.run(main())

That is all you need for the common case. See Advanced Usage for retry control, the step-by-step flow, voice mode, custom solvers, and HTTP configuration.

💡 Advanced Usage

Automatic retry and one-call resolve()

resolve() is load() + verify() in one call, with automatic retry on failure:

g = Geetest(captcha_id='your_captcha_id', risk_type='slide')
result = await g.resolve()  # default: up to 3 attempts
result = await g.resolve(retry=5)  # override the attempt count

On the final failure it raises VerifyError instead of returning a partial result.

Step-by-step flow: load() → verify()

When you need to intervene between the two stages (log, inspect the payload, run your own recognition), call them separately:

g = Geetest(captcha_id='your_captcha_id', risk_type='slide')
data = (
    await g.load()
)  # init data: captcha_type, lot_number, payload, process_token, pow_detail, ...
response = await g.verify(data)  # full response: status + data

load() returns a dict whose fields can be passed directly into verify(). The return types are listed under Data Models.

Accessible (voice) mode

Some Geetest v4 sites enable the voice channel (accessible mode) server-side. When a site supports it, regardless of the original risk type, you can force voice verification via voice=True, bypassing the original slider / click behavioral checks:

# Originally a slide verification, but the site supports accessible mode
g = Geetest(captcha_id='your_captcha_id', risk_type='slide', voice=True)
result = await g.resolve()

The flow becomes: load voice captcha → download audio → recognize digits offline → submit verification. No browser environment or image recognition needed.

Note: Not all sites enable the accessible channel. If unsupported, the show_voice field in load() returns false, and setting voice=True has no effect — the original risk_type is still used.

Register custom solvers

For risk types without built-in support, inject a custom solver via register_solver:

from wulu_geetest_bypass import Geetest


def solve_icon(imgs: bytes, ques: list[bytes]) -> list[tuple[float, float]]: ...


Geetest.register_solver('icon', solve_icon)

Once registered, generate_w() calls it automatically with the corresponding payload fields. Click/draw solvers return normalized coordinates in [0, 1] relative to the verification image — the library takes care of scaling them to the window/payload formats (e.g. userresponse uses image-based percent × 10000) and of generating the click tracks (including the final submit-button click for icon/word/phrase):

Type Solver signature
icon / word (imgs: bytes, ques: list[bytes]) -> list[tuple[float, float]]
phrase (imgs: bytes) -> list[tuple[float, float]]
nine (imgs: bytes, ques: list[bytes], nine_nums: int) -> list[tuple[int, int]]
pencil (imgs: bytes) -> list
space Not built-in separately; Geetest routes space to svg_icon (solved by the SVG solver)

Built-in solvers can also be overridden, either by passing the solver directly or as a decorator:

Geetest.register_solver('slide', my_custom_slide_solver)
@Geetest.register_solver('slide')
def my_custom_slide_solver(bg, slice, ypos): ...

Proxy and HTTP client configuration

Geetest forwards all HTTP concerns to wreq, so proxies, custom headers, and client emulation are configured once at construction time. Pass a ClientConfig via client_options, or an already-constructed client via client (which takes priority):

from wreq import Client, ClientConfig

config = ClientConfig(...)  # proxy chains, headers, emulation, timeouts, ...

g = Geetest(captcha_id='your_captcha_id', risk_type='slide', client_options=config)
# equivalent, when you need to build the client yourself first:
g = Geetest(captcha_id='your_captcha_id', risk_type='slide', client=Client(config))

📖 API Reference

Configuration — Geetest(**options)

Parameter Type Description
captcha_id str Verification ID (required)
risk_type RiskType Risk type, default 'ai'
client_type ClientType Client type, 'web' / 'web_mobile' / 'android' / 'ios'
lang Lang Language, 'zho' / 'eng' / 'fra' / 'deu' and 13 more
challenge str Custom challenge (auto-generated if omitted)
user_info Any Extra user info (reserved)
voice bool Enable accessible voice verification (requires [voice])
client_options wreq.ClientConfig HTTP client config (proxy, headers, emulation, etc.)
client wreq.Client | None Custom HTTP client (takes priority over client_options)

Data models

load() -> dict returns init data containing captcha_type, lot_number, payload, process_token, pow_detail and other fields, passable directly into verify().

verify(data) -> VerifyResponse:

class VerifyResponse:
    status: str  # "success" / "error"
    data: VerifyData  # VerifyDataSuccess | VerifyDataFail, discriminated by `result`


class VerifyDataSuccess:  # result == "success"
    lot_number: str
    result: str
    fail_count: int
    seccode: Seccode  # success only
    score: str
    payload: str
    process_token: str
    payload_protocol: int


class VerifyDataFail:  # result == "fail" / "forbidden" / "continue" — no seccode
    lot_number: str
    result: str
    fail_count: int
    score: str
    payload: str
    process_token: str
    payload_protocol: int

resolve(retry=3) -> Seccode:

class Seccode:
    captcha_id: str
    lot_number: str
    pass_token: str
    gen_time: str
    captcha_output: str
Parameter Type Description
retry int Retries on fail, default 3; forbidden raises at once

Exceptions

Exception Description
GeetestError Base class of all custom exceptions
VerifyError /verify did not return success; carries .result / .fail_count

VerifyError.result is the raw server value: fail (scored and rejected — wrong answer, bad headers or low risk score; retryable), forbidden (rejected before scoring — an IP-level rate limit, not an answer problem; back off or change the exit IP) or continue (another round of the same challenge is wanted, match only).

⚖️ Disclaimer

This project is for learning and research purposes only. Users should comply with applicable laws and platform terms of service; any illegal use is prohibited. The author assumes no responsibility for any legal issues arising from the use of this project.

🤝 Support & Updates

  • This project continuously tracks Geetest v4 behavioral verification changes and updates the bypass logic and solvers promptly.
  • Please open an Issue if you encounter problems, and PRs are welcome.
  • If this project helps you, feel free to give it a ⭐ Star to encourage continued development.

🙏 Credits

The icon solver uses a third-party YOLO model rather than one trained here. Both the ONNX file and the direction mapping table in _config.py come from gaogzhen/GeekedTest under the MIT License — see THIRD_PARTY_NOTICES.md for the full text.

Thanks also to xKiian/GeekedTest, which gaogzhen/GeekedTest builds on.

📄 License

Released under the MIT License — see LICENSE.

Metadata

Release files for wulu-geetest-bypass 0.5.0b1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for wulu-geetest-bypass 0.5.0b1
File Size Uploaded
wulu_geetest_bypass-0.5.0b1.tar.gz 172.0 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for wulu-geetest-bypass 0.5.0b1
File Interpreter ABI Platform
wulu_geetest_bypass-0.5.0b1-py3-none-any.whl Python 3 none any Details

Total release size: 209.6 kB

Release files / wulu_geetest_bypass-0.5.0b1.tar.gz

Download URL wulu_geetest_bypass-0.5.0b1.tar.gz
Size 172.0 kB
Tags Source
SHA-256 checksum
How to use checksums
d4f69578585a9ac1c16c02731ec32f00b2d1b1cb771f2e255569b315e3a3f684
BLAKE2b-256 checksum
How to use checksums
2f9d49d88a0038225a8cb6192b240a72686d3132e637eb9ded51bcbc395857e7
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.13.0 {"installer":{"name":"uv","version":"0.13.0","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / wulu_geetest_bypass-0.5.0b1-py3-none-any.whl

Download URL wulu_geetest_bypass-0.5.0b1-py3-none-any.whl
Size 37.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
8e38961fa0a8a074a36197186f747ed48189f01542bf6ba1eb4b0a3ba8af4c56
BLAKE2b-256 checksum
How to use checksums
5658a20fb2b74573426c0989df425a888715ec33a42605e65e70867a1a863096
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.13.0 {"installer":{"name":"uv","version":"0.13.0","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release history Release notifications | RSS feed

This release

0.5.0b1 This release

2 release files

0.4.2

2 release files

0.4.1

2 release files

0.4.0

2 release files

0.3.5

2 release files

0.3.4

2 release files

0.3.3

2 release files

0.3.2

2 release files

0.3.1

2 release files

0.3.0

2 release files

0.2.2

2 release files

0.2.1

2 release files

0.2.0

2 release files

0.1.4

2 release files

0.1.3

2 release files

0.1.1

2 release 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