PRODUCTION

pfpulse.tech

Независимый сервис распознавания капч Яндекс — принимает картинки и метаданные, возвращает готовый ответ. Интеграция — одна HTTPS-пара запросов (create + result), ничего на стороне клиента разворачивать не нужно.

SmartCaptcha
98.5%
success rate · 80-120ms avg
PazlCaptcha
99.4%
exact match · 17ms median
TextCaptcha
89.5%
OCR · ~1s avg · бесплатно (бесплатно)

Метрики собраны на реальном трафике (smart) и независимой валидации против референсных сольверов (pazl) — см. раздел каждого типа ниже.

Как работает интеграция

Клиентский софт делает два HTTPS-запроса к нашему API:

  1. POST /create — отдаёт данные капчи (картинки + меташку), получает task_id.
  2. POST /result — опрашивает по task_id, получает готовый ответ.

Всё. Никаких прокси, никаких hosts, никаких MITM — обычный JSON over HTTPS к нашему хосту. Среднее время решения капчи в одном полном цикле (create → solve → result) — <200 ms в p50.

# flow:
your client ──POST /create──▶ pfpulse.tech API
            ◀─── task_id ──
            ──POST /result─▶
            ◀── solution ──
(your client applies solution to the captcha widget)

Quickstart

Минимальный цикл для SmartCaptcha:

# 1) отправляем картинки капчи
curl -X POST https://pfpulse.tech/captcha/create \
  -H "Content-Type: application/json" \
  -d '{
    "type":  "SmartCaptcha",
    "click": "<base64 PNG/JPG — основная картинка, на которой надо кликнуть>",
    "task":  "<base64 PNG/JPG — картинка с целевыми силуэтами, в нужном порядке>"
  }'
# ← {"task_id": "9051d4b4-…", "status": "pending"}

# 2) опрашиваем результат (1-2 сек обычно достаточно)
curl -X POST https://pfpulse.tech/captcha/result \
  -H "Content-Type: application/json" \
  -d '{"task_id": "9051d4b4-…"}'
# ← {"status": "ready", "solution": "coordinates:x=34.7,y=108.0;…", "solve_time_ms": 87}

Для PazlCaptcha:

curl -X POST https://pfpulse.tech/captcha/create \
  -H "Content-Type: application/json" \
  -d '{
    "type":  "PazlCaptcha",
    "image": "<base64 PNG — сама картинка паззла>",
    "task":  "[10,24,5,9,8,9,15,…]"
  }'
# ← {"task_id": "…", "status": "pending"}

curl -X POST https://pfpulse.tech/captcha/result -d '{"task_id":"…"}' -H "Content-Type: application/json"
# ← {"status": "ready", "solution": "14"}  — номер шага слайдера

Для TextCaptcha:

curl -X POST https://pfpulse.tech/captcha/create \
  -H "Content-Type: application/json" \
  -d '{
    "type":  "TextCaptcha",
    "task":  "<base64 PNG/JPG — картинка с текстом капчи>"
  }'
# ← {"task_id": "…", "status": "pending"}

curl -X POST https://pfpulse.tech/captcha/result -d '{"task_id":"…"}' -H "Content-Type: application/json"
# ← {"status": "ready", "solution": "молоко дерево"}  — 2 русских слова

SmartCaptcha

PRODUCTION

Яндекс-капча типа «silhouette»: две картинки. На click — область с иконками-силуэтами (обычно 5-7 штук). На task — те силуэты, которые нужно кликнуть на click-картинке, нарисованные слева-направо в правильном порядке. Решение = список координат кликов в том же порядке что идут силуэты на task-картинке.

Что присылает клиент

{
  "type":  "SmartCaptcha",
  "click": "<base64 PNG/JPG>",   // основная картинка с иконками, 320×180 native или 300×300 CSS
  "task":  "<base64 PNG/JPG>",   // картинка с целевыми силуэтами в нужном порядке
  "coord_space": "native"       // optional: "native" | "css300" (default "css300")
}

coord_space: в каком пиксельном пространстве вернуть координаты. native — пиксели исходной картинки как ты её прислал; css300 — нормированные в 300×300 (для CSS-widget). Большинству клиентов нужен native.

Что возвращает сольвер

"solution": "coordinates:x=34.7,y=108.0;x=234.3,y=72.3;x=72.5,y=62.6;..."

Список пар (x,y) через ; в том же порядке, в котором целевые силуэты идут на task-картинке (слева-направо). То есть i-я пара — это координата на click-картинке для i-го силуэта из task. Клиент применяет клики в этом порядке (human-like задержки 100-300 мс между кликами рекомендуются).

Как мы решаем

Пайплайн из 4 ML-компонент, обученных на ~100K размеченных сэмплов реального трафика:

  1. Object detection — находим координаты всех силуэтов на click-картинке.
  2. Task counter — предсказываем сколько силуэтов на task-картинке (обычно 5-7).
  3. Task parser — режем task-картинку на N отдельных силуэтов в порядке слева-направо.
  4. Contrastive matcher — эмбеддим каждый детект из click и каждый силуэт из task в общее пространство, считаем similarity-матрицу, Hungarian-матчинг → какой детект соответствует какому силуэту → порядок кликов.

Каждая компонента дообучается периодически на сложных кейсах из uncertain-бакета. Модели не публичные.

PazlCaptcha

PRODUCTION

Яндекс-капча типа «пазл/калейдоскоп»: картинка разбита на сетку N×N квадратных плиток, и строки плиток сдвинуты серией pair-swap операций. Снизу — слайдер с диапазоном 0..max, который контролирует сколько swap'ов применено. При правильной позиции слайдера картинка становится целой. Решение = номер правильного шага слайдера.

Что присылает клиент

Два формата на выбор:

Формат V2 (рекомендуемый)
{
  "type":  "PazlCaptcha",
  "image": "<base64 PNG>",       // сама картинка паззла (скрамблированная)
  "task":  "[10,24,5,9,8,...]"   // JSON-массив swap-индексов из DOM-стейта капчи
}

Где клиенту взять поля:

  • image — загрузить по URL из JS-стейта (imageSrc), потом base64.
  • task — массив из JS-стейта (task). Плоский JSON-массив целых чисел, длина всегда чётная.

Регекспы: imageSrc:"(https://[^"]+)" и task:"(\[[\d,]+\])".

Формат V1 (Capsola-совместимый)
{
  "type":  "PazlCaptcha",
  "task":  "<base64 полной HTML-страницы капчи>"
}

Клиент отправляет всю HTML-страницу капчи в base64. Сервер сам парсит HTML, извлекает imageSrc и task permutation, скачивает картинку и решает. Полностью совместим с Capsola API /create.

Что возвращает сольвер

"solution": "14"   // номер шага слайдера, целое число 0..max

max = len(task) / 2. Клиент применяет ответ любым из двух способов:

  • Клики — нажимает стрелку «→» на слайдере ровно N раз.
  • Drag — тащит ползунок в позицию N / max вдоль длины трека.

Оба способа эквивалентны — в submit капча шлёт значение rep=N которое читается из aria-valuenow слайдера.

Как мы решаем

Чистый детерминистический CV, без обучения. Алгоритм — реверс-инжиниринг JS-рендера капчи:

  1. Размер сетки N = ceil(sqrt(max(task)+1)). Для текущей версии капчи всегда 5×5 (25 тайлов).
  2. Для каждого кандидата t ∈ 0..max: начинаем с identity-перестановки [0..N²−1], применяем первые t swap-пар из task-массива.
  3. Рендерим картинку-гипотезу: для каждой клетки i берём тайл source[perm[i]].
  4. Считаем joint coherence — среднюю L1-разницу цвета в 7-пиксельном окне по обе стороны каждого шва между плитками.
  5. Аrgmin по t → правильный шаг.

Проверено 99.4% exact совпадение с референсным сольвером на 353 независимых сэмплах. Latency ≈17 мс median. Zero-ML — numpy-only. Масштабируется тривиально.

TextCaptcha

BETA БЕСПЛАТНО

Капча типа «введите текст с картинки» — Яндекс отдаёт её ночью или подозрительным клиентам. На картинке — два искажённых русских слова. Сольвер на базе OCR принимает изображение, возвращает распознанную строку. Точность — 89.5% на реальных сэмплах. На период бесплатно-теста решение бесплатно.

Точность
89.5%
на реальном трафике
Latency
~1s
среднее время решения
Цена
0 ₽
бесплатно на период бесплатно

Что присылает клиент

{
  "type":  "TextCaptcha",
  "task":  "<base64 PNG/JPG — картинка с текстом>"
}

Поле task содержит base64-картинку капчи с искажённым текстом. Совместим с Capsola API.

Что возвращает сольвер

"solution": "молоко дерево"   // 2 русских слова через пробел

Строка из двух русских слов, разделённых пробелом. Клиент вводит строку целиком в поле ответа капчи.

Как мы решаем

TPS-STN (Thin Plate Spline Spatial Transformer Network) для выравнивания искажений + OCR-модель attention-based, дообученная на реальных и синтетических сэмплах. Post-processing: pymorphy3-коррекция для исправления ошибок на уровне русской морфологии.

Формат ответа

Все эндпоинты возвращают JSON.

POST /create

{
  "task_id": "9051d4b4-0000-44d3-a4c2-db0215227862",
  "status":  "pending"
}

POST /result

// ready — готово
{
  "task_id":       "9051d4b4-...",
  "status":        "ready",
  "solution":      "coordinates:x=34.7,y=108.0;...",
  "solve_time_ms": 87
}

// pending — ещё решается, повтори через 1-2 сек
{ "task_id": "...", "status": "pending" }

// error — не смогли решить / внутренняя ошибка
{ "task_id": "...", "status": "error", "error": "<причина>" }

Коды ошибок

Все ошибки бьются на две категории:

HTTP 400 — плохой запрос
  • Неизвестный type.
  • Отсутствуют обязательные поля под выбранный type (SmartCaptcha требует click+task, PazlCaptcha — image+task).
  • Картинка не base64 / битый формат / меньше 100 байт / больше 200 КБ.
  • task не парсится (для PazlCaptcha ожидается JSON-массив чисел).
HTTP 200 + status: "error" — сольвер не справился
  • error: "no detections" — не нашли нужные элементы в картинке (шумная/битая картинка).
  • error: "counter mismatch" — внутренние модели не согласны между собой (сохранится в uncertain-бакет для дообучения).
  • error: "timeout" — решение не завершилось за SLA (см. лимиты ниже).

При этих ошибках — обычно достаточно запросить у источника новую капчу и послать нам свежую. Retry той же картинкой не поможет.

HTTP 404 — task_id не найден
  • TTL task истёк (120 сек от момента /create).
  • Неверный task_id.

Polling

  1. POST /create → получаешь task_id.
  2. Ждёшь 1-2 секунды (внутренний solve обычно укладывается в <200 мс, но даём буфер на jitter сети).
  3. POST /result с {task_id}.
  4. Если status: "pending" — подожди 2-5 сек и повтори.
  5. Если status: "ready" — бери solution и применяй.
  6. Если status: "error" — запрашивай новую капчу у источника.
  7. TTL задачи — 120 сек. После этого task_id пропадает.

Лимиты и SLA

Propagation
create → solve → ready:
p50 <200 мс · p99 <600 мс
Throughput
sustained ~2000 solve/min на текущей ноде;
масштабируется горизонтально
Task TTL
120 секунд от /create до /result
Image size
100 байт — 200 КБ (PNG/JPG base64)

Fingerprint API

PRODUCTION

Генерация уникальных Android-отпечатков браузера. 457 реальных устройств, 9 браузеров, Canvas/WebGL хеши, сенсоры, шрифты, аудио — полный набор для антидетекта. Подписка по req/min с привязкой IP.

Эндпоинт

GET /api/v1/fingerprint/generate

Параметры

# Базовый запрос (Android Chrome, случайное устройство)
curl https://pfpulse.tech/api/v1/fingerprint/generate \
  -H "Authorization: Bearer YOUR_API_KEY"

# С параметрами
curl "https://pfpulse.tech/api/v1/fingerprint/generate?browser=yandex&perfectCanvas=true" \
  -H "Authorization: Bearer YOUR_API_KEY"

browserchrome (default), yandex, samsung, opera, edge, atom, mi, huawei, honor

osandroid (default)

perfectCanvastrue для perfect canvas хешей

chrome — фильтр по мажорной версии Chrome, напр. 146

Ответ

JSON ~70KB с полным fingerprint:

// Основные поля
{
  "ua": "Mozilla/5.0 ... Chrome/146.0...",
  "width": 412, "height": 915,
  "canvas": "0cd58ae4e8d88d57...",
  "webgl": "...",
  "audio": { ... },
  "battery": { ... },
  "sensor": { ... },
  "plugins": [ ... ],
  "fonts": [ ... ],
  "webgl_properties": { ... },
  "perfectcanvas": { ... }  // если perfectCanvas=true
}

Тарифы

S
1 600 ₽
50 req/min
M
2 000 ₽
100 req/min
L
2 400 ₽
200 req/min
XL
2 800 ₽
300 req/min
XXL
4 000 ₽
500 req/min
Ultra
5 600 ₽
1000 req/min

Безлимит — по запросу. Все тарифы: подписка/мес, привязка IP обязательна.

Legacy API режим

Сервис также поддерживает совместимый «legacy» формат запросов/ответов для клиентов, которые используют стороннюю API-схему и не могут переключиться на нашу нативную. В этом режиме отдаются поля status: 1/0, response: <...> и стандартные error-коды сторонней схемы.

Документация и примеры интеграции для legacy-режима предоставляются по запросу — напиши в поддержку с описанием кейса.