- π Async & Sync Support
- π Simple & Intuitive API
- β Type-safe response handling
- π‘οΈ Enhanced security validation
PyTurnstile simplifies Cloudflare Turnstile token validation. It handles all communication with Cloudflare's API.
sequenceDiagram
participant Frontend as π₯οΈ Frontend
participant Backend as π Your Backend
participant Cloudflare as βοΈ Cloudflare
Frontend->>Cloudflare: 1. Complete challenge
Cloudflare-->>Frontend: 2. Return token
Frontend->>Backend: 3. Submit form + token
rect rgb(50, 179, 238)
Note over Backend,Cloudflare: π PyTurnstile handles this
Backend->>Cloudflare: 4. Verify token
Cloudflare-->>Backend: 5. Valid β
/ Invalid β
end
Backend->>Frontend: 6. Allow / Deny request
Learn more at: https://developers.cloudflare.com/turnstile/
Install the package using your preferred dependency manager.
uv add pyturnstilepip install pyturnstileTip
You can follow this documentation and create your own Turnstile secret key at the Cloudflare Turnstile dashboard.
PyTurnstile provides two ways to validate tokens:
from pyturnstile import Turnstile
turnstile = Turnstile(secret="your-secret-key")
response = turnstile.validate(token="user-token-from-frontend")
# or validate asynchronously
# response = await turnstile.async_validate(token="user-token-from-frontend")
if response.success:
print("β
Token is valid!")from pyturnstile import validate, async_validate
response = validate(
token="user-token-from-frontend",
secret="your-secret-key"
)
# or validate asynchronously
# response = await async_validate(
# token="user-token-from-frontend",
# secret="your-secret-key"
# )
if response.success:
print("β
Token is valid!")Note
For more details on all available parameters, see the Cloudflare documentation
response = turnstile.validate(
token="user-token", # The token from the client-side widget
idempotency_key="unique-uuid", # Optional: UUID for retry protection
expected_remoteip="203.0.113.1", # Optional: The visitor's IP address that the challenge response must match
expected_hostname="example.com", # Optional: The hostname that the challenge response must match
expected_action="submit_form", # Optional: The action identifier that the challenge must match
timeout=10 # Optional: request timeout in seconds
)Note
For more details on all response fields, see the Cloudflare documentation
The TurnstileResponse object contains:
response.success # bool: Whether validation succeeded
response.error_codes # list[TurnstileErrorCodes]: Error codes (if any)
response.challenge_ts # str: ISO timestamp of challenge completion
response.hostname # str: Hostname where challenge was served
response.action # str: Custom action identifier
response.cdata # str: Custom data payload from client-side
response.metadata["ephemeral_id"] # Device fingerprint ID (Enterprise only)Any contributions are greatly appreciated. If you have a suggestion that would make this project better, please fork the repo and create a Pull Request. You can also open an issue.
Published under the MIT License.