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 не запущена. Для health-перевірки ключ передавати не потрібно.
Крок 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, яка віддає ті самі можливості ШІ-агентам (Claude, ChatGPT, Cursor) через Model Context Protocol. Виникає резонне питання: що використовувати - MCP чи прямий API?
| Критерій | Прямий REST API | MCP-сервер |
|---|---|---|
| Хто користувач | Розробник з кодом | ШІ-агент або людина в чаті |
| Контроль над логікою | Повний | Через промпт |
| Швидкість розробки | Повільніше (треба писати код) | Миттєво (фраза в чаті) |
| Відтворюваність | 100% (код детермінований) | Залежить від моделі |
| Підходить для CI/CD | Так | Ні (немає ШІ в пайплайні) |
| Інтеграція в наявний код | Ідеально | Не призначений |
| Рівень абстракції | Endpoint-рівень | Наміри рівня "зроби X" |
Беріть REST API, якщо:
- У вас є команда і кодова база, в яку інтеграція Afina - один з модулів.
- Потрібна повна відтворюваність і контроль (CI/CD, регулярні джоби, прод-кампанії).
- Хочеться обгорнути API у свій UI або API gateway.
Беріть MCP, якщо:
- Ви в чаті з Claude/ChatGPT і хочете "просто говорити, що потрібно".
- Прототипуєте ідеї, досліджуєте можливості.
- Команда без програмістів, але ШІ-агент уже під рукою.
У більшості серйозних команд використовуються обидва: MCP - для рисьорчу і швидких проб, REST API - для проду.
Підсумок
Антидетект-браузер без 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-запити в якомусь ліміті?
Ні. 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 між платформами немає.