Перейти к содержимому

Browser-workflow мониторы (автоматизация браузера)

Обычный HTTP-монитор и content-монитор видят только тот HTML, что сервер отдал в первом ответе. Для современных SPA, страниц с тяжёлым JavaScript и всего, что прячется за авторизацией, этого мало: нужный текст появляется только после логина, нескольких кликов и отрисовки фронтендом.

Browser-workflow монитор прогоняет заданную последовательность действий в настоящем headless Chromium — как маленький Selenium-сценарий — и проверяет, что сценарий по-прежнему доходит до конца. Если любой шаг падает (элемент пропал, текст не совпал, страница не загрузилась) — приходит alert. Дополнительно монитор умеет извлекать текст со страницы и слать уведомление при его изменении.

Монитор описывается полями:

  • startUrl — начальный URL (обязателен, только http/https). С него начинается каждый прогон.
  • steps — JSON-массив шагов, от 1 до 20 штук. Выполняются строго последовательно.
  • cookies — опционально: захваченная сессия для авторизованных сценариев (см. ниже). Хранится в зашифрованном виде и наружу никогда не отдаётся.
  • proxy — опциональный egress-прокси scheme://[user:pass@]host:port для сайтов, режущих IP датацентра. Пусто — прямое соединение.
  • timeoutSec — таймаут на один шаг. По умолчанию 60, максимум 120.
  • intervalSec — как часто прогонять сценарий. Минимум 300 (5 минут), максимум 86400 (сутки).
  • alertMessage (обязателен, до 2000 символов), alertTitle, alertMessageMarkdown, alertPriority (0…10) — что и с каким приоритетом слать при падении.
  • notifyOnChange / notifyOnChangeVars — режим «уведомлять при изменении» извлечённых значений (см. ниже).

Каждый элемент массива steps — это объект:

ПолеНазначение
nameчеловеко-читаемое имя шага (обязательно, попадает в alert при падении)
descriptionописание шага на естественном языке — по нему ИИ подбирает action + selector
actionдействие (см. таблицу ниже)
selectorCSS-селектор цели
valueзначение: URL / текст / клавиша; поддерживает подстановку {{переменная}}
extractNameимя переменной для extractText
authшаг авторизации: выполняется только при невалидной сессии

Поддерживаются ровно девять действий:

actionЧто делаетНужен selectorНужен value
navigateперейти на URL (value = URL)да (URL)
clickкликнуть по элементуда
typeввести value в поледатекст
selectвыбрать value в <select>дазначение опции
pressнажать клавишу value (например Enter)клавиша
waitForдождаться появления селекторада
assertTextпроверить, что текст селектора содержит valueдаожидаемый текст
extractTextизвлечь текст селектора в переменную extractNameда
scrollпрокрутить страницу: value = top | bottom либо пиксели (300 вниз, -300 вверх)

Шаги click, type, select, waitFor, assertText, extractText требуют непустой selector — без него создание/обновление монитора вернёт 400. Для navigate обязателен value (URL). Для extractText обязателен extractName.

Проверяем, что после логина в личном кабинете виден баланс и он не «0»:

[
{"name": "Открыть дашборд", "action": "waitFor", "selector": "#dashboard"},
{"name": "Раскрыть счёт", "action": "click", "selector": "button.account-toggle"},
{"name": "Дождаться баланса", "action": "waitFor", "selector": ".balance-value"},
{"name": "Проверить, что не пусто", "action": "assertText", "selector": ".balance-value", "value": ""},
{"name": "Запомнить баланс", "action": "extractText", "selector": ".balance-value", "extractName": "balance"}
]

Вручную подбирать CSS-селекторы скучно и хрупко. Поэтому есть эндпоинт POST /browser-workflow/build-step: вы описываете шаг словами (description), а ИИ сам подбирает action и стабильный selector, после чего тут же проверяет кандидата в реальном браузере и возвращает результат.

Как это работает под капотом:

  1. Сервис открывает startUrl, применяет переданные cookies и воспроизводит уже подтверждённые steps — получая актуальное состояние страницы.
  2. LLM по описанию и разметке страницы предлагает действие и до трёх ранжированных селекторов-кандидатов.
  3. Кандидаты дёшево предвалидируются по HTML (синтаксис + наличие на странице), затем все проверяются за один прогон браузера.
  4. Если действие сработало — возвращается verified: true вместе с примером значения (sampleValue) для extractText/assertText. Если нет — последнее предложение с verified: false и пояснением в note.

Тело запроса:

{
"startUrl": "https://app.example.com/login",
"steps": [ /* уже подтверждённые шаги */ ],
"description": "нажать кнопку «Войти»",
"cookies": [ /* опционально: сохранённая сессия */ ],
"proxy": "",
"sessionId": "",
"timeoutSec": 60
}

Ответ:

{
"action": "click",
"selector": "button[type=submit]",
"value": "",
"extractName": "",
"label": "Войти",
"reason": "...",
"sampleValue": "",
"verified": true,
"availableVars": ["balance"],
"cookies": [ /* итоговые cookies сессии */ ]
}

Поле description — от 1 до 500 символов. availableVars показывает переменные, которые уже извлечены предыдущими шагами (через extractText) и доступны для подстановки {{var}} на этом шаге. Возвращаемые cookies стоит накапливать на клиенте и передавать в следующий build-step, чтобы авторизованные шаги не пришлось переигрывать заново.

Чтобы мониторить страницы за логином, нужна валидная сессия. Эндпоинт POST /browser-workflow/login выполняет шаги логина (type пароля, click кнопки и т.п.) в headless-браузере и возвращает итоговые cookies в открытом виде — вы затем передаёте их в поле cookies при создании/обновлении монитора, где они шифруются перед сохранением.

Окно терминала
curl -X POST "$NOTIFLY_URL/browser-workflow/login" \
-H "X-Notifly-Key: C..." \
-H "Content-Type: application/json" \
-d '{
"startUrl": "https://app.example.com/login",
"steps": [
{"action": "type", "selector": "#email", "value": "me@example.com"},
{"action": "type", "selector": "#password", "value": "secret"},
{"action": "click", "selector": "button[type=submit]"}
],
"timeoutSec": 60
}'

Ответ:

{ "cookies": [ /* массив cookie */ ], "count": 7, "url": "https://app.example.com/dashboard" }

Перед сохранением весь сценарий целиком можно прогнать через POST /browser-workflow/test-step — это «кнопка Проверить». Сервис выполняет все шаги и сообщает, дошёл ли до конца.

Окно терминала
curl -X POST "$NOTIFLY_URL/browser-workflow/test-step" \
-H "X-Notifly-Key: C..." \
-H "Content-Type: application/json" \
-d '{
"startUrl": "https://app.example.com/dashboard",
"cookies": [ /* сохранённая сессия */ ],
"steps": [ /* весь сценарий */ ],
"timeoutSec": 60
}'

Ответ:

{
"ok": true,
"failedStep": -1,
"error": "",
"url": "https://app.example.com/dashboard",
"cookies": [ /* итоговые cookies всей сессии */ ],
"count": 7,
"vars": { "balance": "12 340 ₽" }
}

Если сценарий упал, ok: false, а failedStep укажет индекс сломавшегося шага и error — причину. При успехе vars содержит все извлечённые extractText значения — удобно сразу проверить, что забирается именно то, что нужно.

Если включить notifyOnChange, монитор работает не как «упал/не упал», а как трекер значений: после каждого успешного прогона он сравнивает извлечённые (extractText) переменные с прошлым успешным прогоном и шлёт уведомление, когда любое из них изменилось.

  • notifyOnChangeVars — JSON-массив имён переменных для отслеживания. Пустой массив = следить за всеми извлечёнными переменными.

Так, например, можно ловить изменение цены товара, статуса заказа или остатка на складе на странице, которая рендерится только в браузере.

Монитор создаётся со статусом pending и первой проверкой «на сейчас». Дальше он переходит в up / down (а также degraded) по результатам прогонов. Поставить на паузу и снять с паузы можно эндпоинтами POST /browser-workflow/:id/pause (статус paused) и POST /browser-workflow/:id/resume (возврат в pending). На паузе сценарий не прогоняется и алертов не шлёт.

При падении в карточке монитора видны lastError и lastFailedStep — текст последней ошибки и имя сломавшегося шага.

Все эндпоинты требуют client-token (где помечено «write» — токен с правом записи или MCP-код с доступом на запись). В ответах списка зашифрованные cookies вырезаются; вместо них отдаётся флаг hasCookies.

Метод и путьАвторизацияНазначение
GET /browser-workflowclient-tokenсписок мониторов (без cookies)
POST /browser-workflowclient-token (write)создать монитор
PUT /browser-workflow/:idclient-token (write)обновить монитор
DELETE /browser-workflow/:idclient-token (write)удалить монитор
POST /browser-workflow/:id/pauseclient-token (write)поставить на паузу (status=paused)
POST /browser-workflow/:id/resumeclient-token (write)снять с паузы (status=pending)
POST /browser-workflow/build-stepclient-token (write)ИИ-подбор и проверка одного шага
POST /browser-workflow/loginclient-token (write)прогнать логин и вернуть cookies сессии
POST /browser-workflow/test-stepclient-token (write)тестовый прогон всего сценария
Окно терминала
curl -X POST "$NOTIFLY_URL/browser-workflow" \
-H "X-Notifly-Key: C..." \
-H "Content-Type: application/json" \
-d '{
"appid": 12,
"name": "Баланс в ЛК",
"startUrl": "https://app.example.com/dashboard",
"steps": "[{\"name\":\"Дождаться баланса\",\"action\":\"waitFor\",\"selector\":\".balance-value\"},{\"name\":\"Запомнить баланс\",\"action\":\"extractText\",\"selector\":\".balance-value\",\"extractName\":\"balance\"}]",
"cookies": "[ /* plaintext cookies из /login */ ]",
"intervalSec": 900,
"timeoutSec": 60,
"notifyOnChange": true,
"alertMessage": "Сценарий «Баланс в ЛК» сломался"
}'

См. также: Активные мониторы · Content-монитор · Workflow-монитор (HTTP) · Полный API.