документация

всё что нужно для интеграции qcaptcha на свой сайт

что это

qcaptcha — капча-сервис с двумя режимами: пазл (поворот фрагментов изображения) и текст (ввод символов с картинки). при каждом запросе система оценивает риск по ip, user-agent и частоте запросов, и решает сколько капч показать — от 1 до 3.

работает через iframe и серверную валидацию. никаких тяжёлых sdk или трекинг-скриптов.

быстрый старт

получаешь api-ключи, подключаешь виджет, валидируешь на сервере. всё.

  1. создай api-ключи через эндпоинт
  2. подключи скрипт виджета и добавь контейнер
  3. виджет покажет чекбокс "Я не робот", по клику — попап с капчей
  4. после прохождения вызывается callback с токеном
  5. отправь токен на сервер и провалидируй через api
HTML — подключаем виджет
<!-- контейнер для виджета -->
<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 эндпоинты

POST /api/keys/create

создаёт пару ключей. site_key — публичный, идёт в iframe. secret_key — приватный, остаётся на сервере.

тело запроса

не требуется

ответ
{
  "site_key": "qc_site_abc123...",
  "secret_key": "qc_secret_xyz789..."
}
POST /api/embed/start

начинает сессию капчи. iframe вызывает автоматически. возвращает сколько капч нужно решить по результатам оценки риска.

тело запроса
{ "sitekey": "ТВОЙ_SITE_KEY" }
ответ
{
  "session_token": "abc123...",
  "required_solves": 2,
  "risk_score": 45,
  "mode": "puzzle"
}

modepuzzle или text. при высоком риске режимы чередуются.

POST /api/embed/solve

вызывается после каждой решённой капчи. когда все решены — возвращает validation_token.

тело запроса
{ "session_token": "abc123..." }
ответ
{
  "completed": 1,
  "required": 2,
  "validation_token": null,
  "next_mode": "text"
}

когда completed == required, приходит validation_token. его шлёшь на сервер.

POST /api/validate

серверная проверка. бэкенд отправляет токен + ключи, получает результат.

тело запроса
{
  "token": "VALIDATION_TOKEN",
  "sitekey": "ТВОЙ_SITE_KEY",
  "secret": "ТВОЙ_SECRET_KEY"
}
ответ
{
  "success": true,
  "score": 45,
  "solves": 2,
  "ip": "203.0.113.1"
}
GET /api/risk-check

проверка риска для текущего 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"
  }
}

пример интеграции

полный флоу: виджет (чекбокс "Я не робот" + попап) + серверная валидация.

  1. подключаешь скрипт виджета на страницу
  2. создаёшь экземпляр QCaptcha с контейнером и callback
  3. пользователь нажимает "Я не робот" — открывается попап с капчей
  4. внутри попапа загружается /embed, система оценивает риск и показывает 1-3 капчи
  5. после прохождения — callback возвращает токен, попап закрывается
  6. токен отправляется на сервер для валидации через /api/validate
Полный пример — HTML + JS
<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>
Сервер — Python (Flask)
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'
Сервер — Node.js (Express)
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 — 301
средний30 — 602
высокий60+3 (микс puzzle + text)

при высоком риске капчи чередуются — сначала пазл, потом текст или наоборот. цель — минимизировать нагрузку на обычных пользователей, усложняя прохождение для ботов.