документация
всё что нужно для интеграции qcaptcha на свой сайт
что это
qcaptcha — капча-сервис с двумя режимами: пазл (поворот фрагментов изображения) и текст (ввод символов с картинки). при каждом запросе система оценивает риск по ip, user-agent и частоте запросов, и решает сколько капч показать — от 1 до 3.
работает через iframe и серверную валидацию. никаких тяжёлых sdk или трекинг-скриптов.
быстрый старт
получаешь api-ключи, подключаешь виджет, валидируешь на сервере. всё.
- создай api-ключи через эндпоинт
- подключи скрипт виджета и добавь контейнер
- виджет покажет чекбокс "Я не робот", по клику — попап с капчей
- после прохождения вызывается callback с токеном
- отправь токен на сервер и провалидируй через api
<!-- контейнер для виджета -->
<div id="captcha"></div>
<input type="hidden" name="captcha_token" id="captchaToken">
<!-- подключаем скрипт -->
<script src="https://qcaptcha.xyz/static/js/qcaptcha-widget.js"></script>
<script>
var widget = new QCaptcha('#captcha', {
sitekey: 'ТВОЙ_SITE_KEY',
theme: 'dark',
// mode: 'puzzle' | 'text' | '' (авто)
callback: function(token) {
document.getElementById('captchaToken').value = token;
}
});
</script>
параметр mode управляет типом капчи:
| значение | поведение |
|---|---|
'' (пусто) | сервер выбирает сам по уровню риска |
'puzzle' | всегда пазл (поворот фрагментов) |
'text' | всегда текстовая капча |
POST https://qcaptcha.xyz/api/validate
Content-Type: application/json
{
"token": "ТОКЕН_ОТ_ВИДЖЕТА",
"sitekey": "ТВОЙ_SITE_KEY",
"secret": "ТВОЙ_SECRET_KEY"
}
живой пример интеграции: demo.qcaptcha.xyz
api эндпоинты
создаёт пару ключей. site_key — публичный, идёт в iframe. secret_key — приватный, остаётся на сервере.
не требуется
{
"site_key": "qc_site_abc123...",
"secret_key": "qc_secret_xyz789..."
}
начинает сессию капчи. iframe вызывает автоматически. возвращает сколько капч нужно решить по результатам оценки риска.
{ "sitekey": "ТВОЙ_SITE_KEY" }
{
"session_token": "abc123...",
"required_solves": 2,
"risk_score": 45,
"mode": "puzzle"
}
mode — puzzle или text. при высоком риске режимы чередуются.
вызывается после каждой решённой капчи. когда все решены — возвращает validation_token.
{ "session_token": "abc123..." }
{
"completed": 1,
"required": 2,
"validation_token": null,
"next_mode": "text"
}
когда completed == required, приходит validation_token. его шлёшь на сервер.
серверная проверка. бэкенд отправляет токен + ключи, получает результат.
{
"token": "VALIDATION_TOKEN",
"sitekey": "ТВОЙ_SITE_KEY",
"secret": "ТВОЙ_SECRET_KEY"
}
{
"success": true,
"score": 45,
"solves": 2,
"ip": "203.0.113.1"
}
проверка риска для текущего ip (или конкретного через ?ip=x.x.x.x). полезно для дебага.
{
"risk": {
"score": 25,
"required_solves": 1,
"ip_score": 25,
"ua_score": 0,
"rate_score": 0
},
"ip_info": {
"proxy": false,
"hosting": true,
"isp": "OVH SAS"
}
}
пример интеграции
полный флоу: виджет (чекбокс "Я не робот" + попап) + серверная валидация.
- подключаешь скрипт виджета на страницу
- создаёшь экземпляр
QCaptchaс контейнером и callback - пользователь нажимает "Я не робот" — открывается попап с капчей
- внутри попапа загружается
/embed, система оценивает риск и показывает 1-3 капчи - после прохождения — callback возвращает токен, попап закрывается
- токен отправляется на сервер для валидации через
/api/validate
<form id="myForm" action="/submit" method="POST">
<input type="text" name="email" placeholder="email">
<input type="hidden" name="captcha_token" id="captchaToken">
<div id="captcha"></div>
<button type="submit" id="btn" disabled>отправить</button>
</form>
<script src="https://qcaptcha.xyz/static/js/qcaptcha-widget.js"></script>
<script>
var widget = new QCaptcha('#captcha', {
sitekey: 'ТВОЙ_SITE_KEY',
theme: 'dark',
callback: function(token) {
document.getElementById('captchaToken').value = token;
document.getElementById('btn').disabled = false;
}
});
</script>
import requests
@app.route('/submit', methods=['POST'])
def submit():
token = request.form.get('captcha_token')
resp = requests.post('https://qcaptcha.xyz/api/validate', json={
'token': token,
'sitekey': 'ТВОЙ_SITE_KEY',
'secret': 'ТВОЙ_SECRET_KEY',
})
result = resp.json()
if not result.get('success'):
return 'капча не пройдена', 400
return 'ok'
app.post('/submit', async (req, res) => {
const token = req.body.captcha_token;
const resp = await fetch('https://qcaptcha.xyz/api/validate', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
token,
sitekey: 'ТВОЙ_SITE_KEY',
secret: 'ТВОЙ_SECRET_KEY',
}),
});
const result = await resp.json();
if (!result.success) return res.status(400).send('капча не пройдена');
res.send('ok');
});
живой пример: demo.qcaptcha.xyz
оценка риска
каждая сессия начинается с оценки. смотрим на несколько сигналов и решаем сколько капч показать.
| сигнал | что проверяет |
|---|---|
| ip репутация | proxy, vpn, tor, хостинг-провайдеры, дата-центры |
| user-agent | пустой или подозрительный ua, паттерны ботов (selenium, puppeteer, curl) |
| rate limiting | слишком много запросов с одного ip за короткое время |
маппинг скора на количество капч:
| уровень | score | капч |
|---|---|---|
| низкий | 0 — 30 | 1 |
| средний | 30 — 60 | 2 |
| высокий | 60+ | 3 (микс puzzle + text) |
при высоком риске капчи чередуются — сначала пазл, потом текст или наоборот. цель — минимизировать нагрузку на обычных пользователей, усложняя прохождение для ботов.