API Afina: автоматизация антидетект-браузера через REST

Один POST-запрос - и у вас уже создано 100 профилей с уникальными отпечатками, привязанными прокси и поднятыми браузерами в режиме headless или с CDP-эндпоинтом для Puppeteer. Никаких облачных лимитов, токенов на тарифах и API-rate-limit-ов: API Afina полностью локальный, работает на 127.0.0.1:50778, и единственный, кто решает, сколько вы делаете запросов - это ваша машина.
В этой статье разбираем, как устроен API антидетект-браузера Afina: 79 endpoint-ов, схема авторизации, как поднять первый профиль и подцепить к нему Puppeteer или Playwright за 5 минут, какие сценарии перестают быть болью при переходе с UI на API, и где проходит граница между REST API и MCP-сервером для тех, кто думает "что выбрать".
Зачем нужен API антидетект-браузера
Если вы работаете с мультиаккаунтингом на сотнях профилей, рутина в UI быстро становится ограничивающим фактором:
- Аффилиатный маркетинг. Создание 200 профилей под кампанию руками - два часа. Через API - один цикл с
forи 30 секунд работы. - Фарминг аккаунтов. Подготовка профилей по геолокациям с проксями, тегами и автологинами. Прокси с ротацией, прогрев - всё это не существует без скриптинга.
- Веб-скрапинг. Параллельный сбор данных с десятков сайтов - каждый профиль свой fingerprint, своя cookie-jar, своя прокся. UI на это не рассчитан.
- E-commerce и мониторинг конкурентов. Цены, описания, акции - собирать вручную невозможно, через API - ровно столько, сколько ваша инфраструктура потянет.
- Bonus hunting и airdrop-кампании. Сложные расписания запусков с распределением во времени для обхода антифрод-кластеризации - это всё API + cron.
- Ставки и арбитраж. Скорость реакции в секундах, синхронные действия на десятках профилей. Только программный путь.
Если вы делаете что-то одно и то же больше двух раз - это уже задача для API. Afina даёт REST-интерфейс, который покрывает 100% возможностей UI - всё, что вы можете кликнуть, можно вызвать одним HTTP-запросом.
Чем API Afina отличается от облачных аналогов
Большинство антидетект-браузеров (Octo, Multilogin, Dolphin) предоставляют облачные API - ваши запросы идут на сервер вендора, проходят квоту по тарифу, и оттуда уже доводятся до локального приложения. У такого подхода есть обратная сторона:
- Лимиты по подписке. 1000-5000 запросов в сутки на старших тарифах - для серьёзной автоматизации этого мало.
- Сетевая задержка. Каждый вызов идёт через интернет дважды - до облака и обратно к локальному клиенту.
- Привязка к доступности облака. Упал сервер вендора - упала вся ваша автоматизация, даже если своё железо работает.
- Передача данных за пределы машины. Что бы вендор ни обещал, метаданные ваших профилей и параметров запросов уходят в их инфраструктуру.
API Afina устроен иначе: это локальный HTTP-сервер на 127.0.0.1, который запускается вместе с десктоп-приложением. Никаких облачных посредников, никаких rate-лимитов, никакой задержки выше миллисекунд. Запрос идёт прямо в Rust-бэкенд приложения, который и так выполняет всю работу - API просто открывает к нему второй канал.
| Параметр | Облачный API (Octo и пр.) | Локальный API Afina |
|---|---|---|
| Лимит запросов в день | По подписке (1k-10k) | Не ограничен |
| Latency | 50-300 мс | 1-10 мс |
| Зависит от облака вендора | Да | Нет |
| Данные уходят за пределы машины | Да | Нет |
| Работает offline | Нет | Да (для локальных операций) |
| Стоимость | По тарифу | Бесплатно |
| Прямой доступ к CDP | Нет, только команды-обёртки | Да, wsEndpoint отдаётся в ответе |
Эта разница принципиально меняет архитектуру решений. Вы можете гонять десятки тысяч вызовов в час без оглядки на квоты, держать боты в локальной сети без выхода в интернет (для всего, что не требует внешних сервисов), и подключаться напрямую к Chrome DevTools Protocol для самых тонких сценариев.
5 минут на старт
Шаг 1. Получить API-ключ
Запустите Afina, откройте Настройки -> API и скопируйте ключ. Это строка из 32 символов [A-Za-z0-9], которая генерируется автоматически при первом запуске и хранится зашифрованной (libsodium sealed-box) в локальной базе.
Ключ передаётся в заголовке X-API-Key каждого запроса. Без валидного ключа сервер силентно закрывает соединение - без ответа и без HTTP-кода. Это сделано намеренно: атакующий не получает информации о причине отказа и не может отличить "неправильный ключ" от "сервер не отвечает".
Шаг 2. Проверить, что сервер живой
curl http://127.0.0.1:50778/api/health
Ответ:
{ "status": "ok", "version": "2.0.4" }
Если получили Connection refused - Afina не запущена. Здоровья не требуется передавать ключ.
Шаг 3. Получить список профилей
curl http://127.0.0.1:50778/api/profiles/list \
-H "X-API-Key: ВАШ_КЛЮЧ"
Ответ:
{
"data": [
{ "accountId": "550e8400-...", "name": "Profile 1", "tags": ["test"], "isRunning": false },
{ "accountId": "660e8400-...", "name": "Profile 2", "tags": ["prod"], "isRunning": true }
],
"count": 2
}
Если этот вызов прошёл - у вас всё работает. Дальше уже только дело фантазии.
Анатомия API: 79 endpoint-ов по категориям
Все эндпоинты сгруппированы по доменам сущностей. Базовый URL - http://127.0.0.1:50778, все принимают Content-Type: application/json и заголовок X-API-Key. Полный список ниже.
Профили (аккаунты) - 10 эндпоинтов
| Path | Method | Назначение |
|---|---|---|
/api/profiles/list | GET | Все аккаунты с фильтрами по тегам/группам |
/api/profiles/get | GET, POST | Один аккаунт по ID или UUID |
/api/profiles/create | POST | Создать постоянный профиль |
/api/profiles/one-time | POST | Создать одноразовый (auto-delete на стопе) |
/api/profiles/update | POST | Обновить параметры |
/api/profiles/start | POST | Запустить браузер -> возвращает wsEndpoint для CDP |
/api/profiles/stop | POST | Остановить (graceful shutdown с дописыванием cookies) |
/api/profiles/delete | POST | Soft-delete (в корзину, восстановимо) |
/api/profiles/hard-delete | POST | Окончательное удаление с очисткой данных |
/api/profiles/cookies/set, /cookies/export | POST | Импорт/экспорт cookie-jar |
При создании профиля все параметры идут одним JSON - прокси, теги, группы, экран, языки, шумы фингерпринта, стартовые URL, заблокированные порты, extraArgs, settings. Уникальный fingerprint (user agent, WebGL renderer, CPU/memory, fonts, time zone) генерируется тем же бэкендом, что использует UI - это не "случайные значения", а валидные комбинации, которые проходят даже сложные проверки фингерпринта.
Soft-delete и hard-delete разделены намеренно: первый кладёт профиль в корзину (восстанавливается одним кликом или вызовом), второй удаляет всё - включая папку с профилем, cookies, кэш и токен в keychain. Запущенный браузер при hard-delete стопится gracefully, без потери данных.
Управление браузером (CDP-команды) - 5 эндпоинтов
| Path | Method | Назначение |
|---|---|---|
/api/profiles/eval | POST | Выполнить JavaScript в текущей вкладке |
/api/profiles/screenshot | POST | Скриншот страницы -> base64 PNG |
/api/profiles/cookies/set | POST | Установить cookie через CDP Network.setCookies |
/api/profiles/cookies/export | POST | Прочитать все cookie через CDP |
Это инструменты "быстрого касания" - для одноразовых операций без полноценного скрипта. Для серьёзной автоматизации (заполнение форм, навигация, ожидание элементов) лучше использовать Puppeteer/Playwright через wsEndpoint - про это ниже.
eval принимает JavaScript-выражение, выполняет его в контексте активной страницы, авто-await промисов, returnByValue. Можно вернуть строку, число, объект - всё, что сериализуется в JSON.
RPA-скрипты - 7 эндпоинтов
| Path | Method | Назначение |
|---|---|---|
/api/scripts/list | GET | Все RPA-скрипты |
/api/scripts/get | GET | Один скрипт по ID |
/api/scripts/create | POST | Создать RPA-скрипт (JSON блоков) |
/api/scripts/update | POST | Обновить |
/api/scripts/run | POST | Запустить скрипт на профиле -> task_uuid |
/api/scripts/run-logs | GET | Логи прямого запуска |
/api/scripts/stop | POST | Остановить выполнение |
RPA-скрипты Afina - это JSON-структура с блоками (click, type, goto, condition, loop, executeModule и т.д.) и связями между ними. Каждый блок описывает шаг сценария, executor выполняет их по графу.
Для автоматического создания скриптов из своего кода - передайте полный JSON с массивами elements и connections в /api/scripts/create. Структура совпадает с тем, что видит визуальный конструктор, и любой созданный через API скрипт можно открыть и редактировать в UI.
RPA-модули - 7 эндпоинтов
| Path | Method | Назначение |
|---|---|---|
/api/modules/list | GET | Все модули |
/api/modules/get | GET | Один модуль + список файлов |
/api/modules/create | POST | Скаффолд (index.js, utils_<id>.js, package.json, settings.json) + npm install |
/api/modules/update | POST | Обновить файлы или метаданные |
/api/modules/resign | POST | Пересчитать Ed25519-подпись |
/api/modules/delete | POST | Soft-delete |
/api/modules/hard-delete | POST | Окончательное удаление |
Когда визуальных RPA-блоков не хватает - пишется кастомный JavaScript-модуль. Через API всё делается end-to-end: создание (с автоматической npm install для зависимостей), правка файлов, переподпись.
Важная деталь: каждый модуль подписан Ed25519 поверх MD5-манифеста папки. Любое изменение файлов без вызова resign ломает подпись - executor блокирует запуск с понятной ошибкой. Это защита от подмены кода: вы не запустите модуль, который кто-то поменял за вашей спиной.
Группы задач и задачи - 17 эндпоинтов
| Path | Method | Назначение |
|---|---|---|
/api/task-groups/list | GET | Список групп |
/api/task-groups/get | GET | Группа со своими задачами |
/api/task-groups/tasks | GET | Только задачи группы |
/api/task-groups/create | POST | Создать группу с расписанием |
/api/task-groups/update | POST | Обновить расписание/название |
/api/task-groups/start | POST | Активировать (active=1) |
/api/task-groups/stop | POST | Деактивировать + остановить running-задачи |
/api/task-groups/restart | POST | Перезапустить error/finished задачи |
/api/task-groups/delete | DELETE, POST | Soft-delete |
/api/task-groups/hard-delete | POST | Окончательное удаление |
/api/tasks/list | GET | Все задачи (фильтры по status, scriptId) |
/api/tasks/active | GET | Только выполняемые сейчас |
/api/tasks/logs | GET | Логи по task_uuid |
/api/tasks/create | POST | Добавить задачи в группу (bulk) |
/api/tasks/update | POST | Изменить статус/executeAt/тег |
/api/tasks/delete | POST | Soft-delete (массово) |
/api/tasks/stop | POST | Остановить выполнение (с опцией closeBrowser) |
Это самая мощная категория API. Группа - это конфигурация расписания (окна времени, повторы, таймауты, лимит параллелизма), задача - единичный запуск скрипта на конкретном аккаунте.
Расписание поддерживает естественные форматы дат для поля executeAt:
"now"- сразу"in 5m"- через 5 минут"+1h"- через час"tomorrow 09:00"- завтра в 9:00 локального времени"2026-05-15 14:30"- конкретный момент- ISO 8601:
"2026-05-15T14:30:00Z" - Unix epoch:
1715787000
Окна времени и параллелизм задаются на уровне группы:
{
"schedule": true,
"timeFrom": "09:00",
"timeTo": "18:00",
"scheduleTime": true,
"startHour": 9.0,
"endHour": 18.0,
"activeSession": 5,
"isRepeatable": true,
"repeatCount": 2,
"timeout": 300
}
Группа будет запускать максимум 5 задач параллельно, только в окне 09:00-18:00, повторит каждую дополнительно 2 раза, и каждая задача автоматически таймаутится через 5 минут. Это конфигурация для серьёзных продакшен-кампаний - обычно для UI это 10 минут кликов, а через API - один POST.
Прокси - 3 эндпоинта
| Path | Method | Назначение |
|---|---|---|
/api/proxies/add | POST | Добавить и проверить |
/api/proxies/check | POST | Проверка одного/нескольких |
/api/proxies/check-all | POST | Аудит всех в таблице |
Все проверки делаются с реальным сетевым тестом, включая UDP-тест для SOCKS5 (критично, потому что Afina поддерживает HTTP/3 поверх SOCKS5 с QUIC). Прокси, которые не прошли - не сохраняются. Это даёт уверенность, что в базе только живые соединения.
Подробнее про типы и сценарии прокси - в материале про прокси и их виды.
Базы данных, переменные, ключи - 15 эндпоинтов
| Path | Method | Назначение |
|---|---|---|
/api/databases/* | GET/POST | CRUD подключений (SQLite/MySQL/PostgreSQL) для RPA-блока database |
/api/global-vars/* | GET/POST | CRUD глобальных переменных ${name}, доступных во всех скриптах |
/api/keys/* | GET/POST | Каталог ключей и API-токенов (OpenAI, Telegram, ChatGPT) |
/api/accounts/vars | GET | Все переменные аккаунта (plain + encrypted) |
/api/accounts/vars/set | POST | Записать (plain или encrypted) |
/api/accounts/vars/delete | POST | Удалить |
Особое внимание - на account_vars. Они хранятся в двух режимах:
| Хранилище | Где | Видно по API |
|---|---|---|
| Plain | account.settings | Да |
| Encrypted | account_data_blob | Нет (только запись и чтение по ключу) |
Encrypted-переменные шифруются sealed-box (libsodium). Через API можно записать значение и потом прочитать по тому же ключу - но сам plaintext по API никогда не отдаётся. Расшифровка происходит только в executor-е скрипта прямо перед выполнением. Это идеальное хранилище для 2FA-секретов, паролей и приватных ключей крипто-кошельков.
Email / IMAP - 2 эндпоинта
| Path | Method | Назначение |
|---|---|---|
/api/emails/list | GET | Список настроенных email-адресов |
/api/emails/toggle | POST | Вкл/выкл мониторинг IMAP |
Управление IMAP-подключениями для автоматического разбора писем (коды подтверждения, ссылки восстановления, внутренние нотификации).
Выбор языка: Node, Python или что-то ещё
API Afina - это обычный HTTP+JSON. Ему всё равно, чем вы делаете запросы. Самые ходовые варианты:
| Язык | Когда использовать | Рекомендуемые библиотеки |
|---|---|---|
| Node.js | Если уже работаете с Puppeteer/Playwright (они тоже Node) | axios, node-fetch, undici |
| Python | Дата-сайнс, парсинг, ML-обвязка | requests, httpx, aiohttp |
| Go | Высоконагруженные параллельные обработки | стандартная net/http |
| Bash + curl | Скрипты деплоя, оркестрация, CI | curl + jq |
| PHP, Ruby, C#, Java | Под существующий стек команды | любая HTTP-библиотека |
Если код есть на одном языке, а нужно перевести на другой - попросите ChatGPT или Claude. С обычным REST это работает безотказно. Структура одна и та же: URL, метод, заголовок X-API-Key, JSON-тело.
Под Puppeteer/Playwright/Selenium всё равно потребуется Node или Python - они нужны не для API Afina, а для управления самим браузером после start_browser. Эти три инструмента - стандарт индустрии для автоматизации на CDP/WebDriver, и Afina с ними дружит из коробки.
Связка с Puppeteer и Playwright через wsEndpoint
Самая мощная фишка API Afina - прямой доступ к Chrome DevTools Protocol. Когда вы запускаете профиль через /api/profiles/start, в ответе приходит wsEndpoint - это полноценный CDP WebSocket, к которому можно подцепить любой инструмент.
Пример на Node.js + Puppeteer
import axios from 'axios';
import puppeteer from 'puppeteer';
const API = 'http://127.0.0.1:50778';
const KEY = process.env.AFINA_API_KEY;
const headers = { 'X-API-Key': KEY };
async function main() {
// 1. Запускаем профиль через API Afina
const { data } = await axios.post(
`${API}/api/profiles/start`,
{ profileId: '550e8400-e29b-41d4-a716-446655440000' },
{ headers }
);
console.log('Browser started, CDP:', data.wsEndpoint);
// 2. Подключаем Puppeteer к существующему браузеру
const browser = await puppeteer.connect({
browserWSEndpoint: data.wsEndpoint,
defaultViewport: null,
});
// 3. Дальше - обычный Puppeteer
const page = (await browser.pages())[0] || await browser.newPage();
await page.goto('https://example.com');
await page.waitForSelector('h1');
const title = await page.$eval('h1', el => el.innerText);
console.log('H1:', title);
// 4. Отключаемся (браузер остаётся запущенным)
await browser.disconnect();
// 5. Закрываем профиль через API
await axios.post(`${API}/api/profiles/stop`,
{ profileId: '550e8400-e29b-41d4-a716-446655440000' },
{ headers }
);
}
main().catch(console.error);
Пример на Python + Playwright
import os
import requests
from playwright.sync_api import sync_playwright
API = 'http://127.0.0.1:50778'
KEY = os.environ['AFINA_API_KEY']
HEADERS = {'X-API-Key': KEY}
profile_id = '550e8400-e29b-41d4-a716-446655440000'
# 1. Запускаем профиль
resp = requests.post(
f'{API}/api/profiles/start',
json={'profileId': profile_id},
headers=HEADERS,
).json()
ws = resp['wsEndpoint']
print('CDP:', ws)
# 2. Playwright connect
with sync_playwright() as p:
browser = p.chromium.connect_over_cdp(ws)
context = browser.contexts[0]
page = context.pages[0] if context.pages else context.new_page()
page.goto('https://example.com')
print('Title:', page.title())
browser.close()
# 3. Закрываем профиль
requests.post(
f'{API}/api/profiles/stop',
json={'profileId': profile_id},
headers=HEADERS,
)
Selenium WebDriver
Selenium тоже работает - через chromedriver с флагом --remote-debugging-port. Чуть менее удобно (требует дополнительной настройки), но для legacy-проектов - рабочая опция. Подробности в гайде по автоматизации действий в браузере.
Готовые рецепты для типовых сценариев
Рецепт 1. Создать 100 профилей с прокси за минуту
import axios from 'axios';
const API = 'http://127.0.0.1:50778';
const headers = { 'X-API-Key': process.env.AFINA_API_KEY };
const proxies = JSON.parse(await fs.readFile('proxies.json', 'utf8'));
for (let i = 0; i < 100; i++) {
await axios.post(`${API}/api/profiles/create`, {
name: `Campaign-1 #${i + 1}`,
tags: ['campaign-1', 'phase-1'],
proxy: proxies[i % proxies.length],
settings: {
languages: ['en-US', 'en'],
startupURLs: ['https://example.com/landing'],
},
}, { headers });
}
100 профилей с уникальными отпечатками, привязанными прокси и тегами - готовы к запуску через минуту. То же самое в UI заняло бы час.
Рецепт 2. Bulk-запуск скрипта на 50 аккаунтах с расписанием
// 1. Создаём группу с расписанием
const group = (await axios.post(`${API}/api/task-groups/create`, {
tag: 'warmup-batch-1',
active: false,
schedule: true,
timeFrom: '09:00',
timeTo: '18:00',
activeSession: 5,
isRepeatable: false,
}, { headers })).data;
// 2. Получаем список аккаунтов с тегом
const accounts = (await axios.get(
`${API}/api/profiles/list?tag=campaign-1`, { headers }
)).data.data;
// 3. Добавляем задачу для каждого с разносом во времени
const tasks = accounts.map((acc, i) => ({
accountId: acc.accountId,
scriptId: 42,
executeAt: `+${i * 3}m`,
}));
await axios.post(`${API}/api/tasks/create`, {
groupId: group.id,
tasks,
}, { headers });
// 4. Запускаем группу
await axios.post(`${API}/api/task-groups/start`,
{ id: group.id }, { headers });
Прогрев 50 аккаунтов с интервалом 3 минуты, в окне 09:00-18:00, максимум 5 параллельно - один файл, 30 строк кода, ровно один запуск.
Рецепт 3. Получить логи всех упавших задач за день
curl "http://127.0.0.1:50778/api/tasks/list?status=error&since=2026-05-14T00:00:00Z" \
-H "X-API-Key: $AFINA_API_KEY" \
| jq -r '.data[] | .taskUuid' \
| while read uuid; do
echo "=== $uuid ==="
curl -s "http://127.0.0.1:50778/api/tasks/logs?uuid=$uuid" \
-H "X-API-Key: $AFINA_API_KEY" \
| jq -r '.data[] | "\(.time) [\(.level)] \(.message)"'
done
Все ошибки за день в один отчёт. Можно скармливать LLM или парсить регулярками для разметки причин падений.
Рецепт 4. Eval JavaScript на запущенном браузере
curl -X POST http://127.0.0.1:50778/api/profiles/eval \
-H "X-API-Key: $AFINA_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"profileId": "550e8400-...",
"code": "JSON.stringify({ url: location.href, title: document.title, cookies: document.cookie })"
}'
Ответ:
{
"result": "{\"url\":\"https://example.com\",\"title\":\"Example Domain\",\"cookies\":\"\"}"
}
Промежуточный вариант между ничем и полноценным Puppeteer - для быстрых проверок и пробинга страниц.
Рецепт 5. Бэкап cookie всех профилей с тегом
import requests, json, os
API = 'http://127.0.0.1:50778'
H = {'X-API-Key': os.environ['AFINA_API_KEY']}
accounts = requests.get(f'{API}/api/profiles/list?tag=prod', headers=H).json()['data']
for a in accounts:
cookies = requests.post(
f'{API}/api/profiles/cookies/export',
json={'profileId': a['accountId']},
headers=H,
).json()
with open(f'backup/{a["accountId"]}.json', 'w') as f:
json.dump(cookies, f)
Полный бэкап cookie-jars всех продакшен-профилей - под каждый чих CI/CD, после крупного апдейта или просто как страховка.
Безопасность
API Afina проектировался с учётом, что любая локальная поверхность атаки - это поверхность атаки. Что сделано:
- Только localhost. Сервер биндится только на
127.0.0.1. С внешней сети до него не достучаться даже теоретически. Если нужен удалённый доступ - делайте через SSH-tunnel (ssh -L 50778:127.0.0.1:50778 user@host) и сами решайте, кому даёте доступ к туннелю. - API-ключ в каждом запросе. Без
X-API-Keyсервер дропает соединение силентно, без HTTP-ответа. Атакующий не может определить, рабочий ли там сервер вообще, не говоря про брутфорс ключей. - Encrypted account vars. Чувствительные данные (2FA, пароли, seed-фразы) шифруются sealed-box и не отдаются по API в plaintext. Доступ к ним есть только у RPA-executor-а в момент запуска скрипта.
- Подписанные модули. Любой кастомный JS-модуль подписан Ed25519. Подмена файлов без
resignломает подпись - executor блокирует запуск. Это защищает от сценариев "кто-то получил доступ к диску и подменилindex.js". - Изоляция профилей. Базовая фича Afina, не специфичная для API: каждый профиль - своя cookie-jar, localStorage, IndexedDB, кэш. Подключение API не размывает эту изоляцию.
- Лимит соединений. 128 одновременных запросов одновременно - защита от случайного DoS со стороны вашего же кода.
- Лимит размера запроса. 16 МБ на запрос - отрезает атаки через гигантские payload-ы.
API или MCP: что выбрать
У Afina есть MCP-сервер - это отдельный продукт, тонкая обёртка поверх REST API, которая отдаёт те же возможности AI-агентам (Claude, ChatGPT, Cursor) через Model Context Protocol. Возникает резонный вопрос: что использовать - MCP или прямой API?
| Критерий | Прямой REST API | MCP-сервер |
|---|---|---|
| Кто пользователь | Разработчик с кодом | AI-агент или человек в чате |
| Контроль над логикой | Полный | Через промпт |
| Скорость разработки | Медленнее (надо писать код) | Мгновенно (фраза в чате) |
| Воспроизводимость | 100% (код детерминирован) | Зависит от модели |
| Подходит для CI/CD | Да | Нет (нет AI в пайплайне) |
| Интеграция в существующий код | Идеально | Не предназначен |
| Уровень абстракции | Endpoint-уровень | Намерения уровня "сделай X" |
Берите REST API, если:
- У вас есть команда и кодовая база, в которую интеграция Afina - один из модулей.
- Нужна полная воспроизводимость и контроль (CI/CD, регулярные джобы, прод-кампании).
- Хочется обернуть API в свой UI или API gateway.
Берите MCP, если:
- Вы в чате с Claude/ChatGPT и хотите "просто говорить, что нужно".
- Прототипируете идеи, исследуете возможности.
- Команда без программистов, но AI-агент уже под рукой.
В большинстве серьёзных команд используются оба: MCP - для рисёрча и быстрых проб, REST API - для прода.
Итог
Antidetect-браузер без API - это инструмент для одиночек. UI хорош, пока вы делаете десятки операций. На сотнях он замедляет, на тысячах - становится невозможным.
API превращает Afina в платформу. Один и тот же бэкенд обслуживает и кнопки в интерфейсе, и REST-вызовы из ваших скриптов - ничего не теряется в трансляции, никаких облачных посредников, никаких лимитов на запросы. Подключайте Puppeteer или Playwright через wsEndpoint, оркестрируйте задачи через task-groups, шифруйте чувствительное в encrypted-переменных, подписывайте свой JS-код - и получаете полноценную инфраструктуру для мультиаккаунтинга на любом масштабе.
Если ваш текущий браузер (Octo, Multilogin, Dolphin) ограничивает вас облачными квотами и 1000 запросами в день - переход на Afina с локальным API даёт сразу два порядка масштаба и убирает зависимость от чужих серверов.
Установите Afina Browser бесплатно, получите API-ключ в настройках за 30 секунд и попробуйте первый запрос - начните с /api/health, дальше уже само пойдёт. Через час у вас будет автоматизация, на которую в UI вы тратили дни.
FAQ — Часто задаваемые вопросы
Безопасно ли держать API открытым? Можно ли украсть данные через API?
API биндится только на 127.0.0.1 - снаружи доступа нет, локальный фаервол не нужен. Внутри машины - любой процесс, знающий ключ, может вызывать API. Если на машине есть недоверенные процессы (вы запускаете чужой код) - это в принципе не та машина, на которой стоит держать антидетект. Encrypted-переменные не отдаются даже с правильным ключом.
Учитываются ли локальные API-запросы в каком-нибудь лимите?
В текущей версии порт 50778 зашит в feature_flags.rs. Можно поменять перед компиляцией. В runtime - пока нет, но если 50778 занят, сервер автоматически пробует 50779-50787.
Как узнать, что профиль действительно запущен и готов к CDP?
Ответ /api/profiles/start приходит уже после того, как браузер запустился и открыл CDP-эндпоинт. Если получили wsEndpoint - можно сразу подключаться. Если получили ошибку - браузер не стартовал, читайте error в ответе.
Что будет, если API запросов очень много одновременно?
Лимит - 128 одновременных соединений. Сверху - ждут в очереди. Если нужно больше - батчите запросы (большинство эндпоинтов поддерживают bulk-операции: tasks/create принимает массив, proxies/check тоже, и т.д.).
Можно ли API вызывать с другой машины в локальной сети?
Напрямую нет (только 127.0.0.1). Но можно прокинуть через SSH-tunnel или поставить локальный nginx/Caddy в reverse-proxy - на свой страх и риск. Лучший вариант - держать всё на одной машине либо использовать командный доступ Afina с разделением ролей.
Поддерживается ли Webhook - чтобы API сам присылал события?
В текущей версии - через polling (/api/tasks/active, /api/tasks/list?status=error). Webhook-и в roadmap.
А если хочу не возиться с raw HTTP, а взять готовую библиотеку?
Под Node есть пакет afina-mcp - он, помимо MCP-серверной части, экспортирует typed-клиент к REST API. Можно использовать его как обычную библиотеку без MCP-моста. Под Python готового SDK пока нет, но обвязка над requests пишется за час.
Сколько живёт wsEndpoint?
Пока запущен браузер. После /api/profiles/stop или ручного закрытия браузером - endpoint становится недействительным. Если процесс упал и браузер перезапустился, новый wsEndpoint надо получить через повторный start (он отдаст alreadyRunning: true и текущий wsEndpoint без рестарта).
Будет ли это работать на macOS, Windows, Linux одинаково?
Да. API Afina - это HTTP-сервер внутри десктоп-приложения, и оно собирается под все три платформы из одного Rust-кода. Различий в API между платформами нет.