Action Log API: как клиенты выносят события профилей в свои системы

Action Log API: как клиенты выносят события профилей в свои системы
Alex Phillips
Alex Phillips

Customer Service Specialist

Стандартный интерфейс Octo Browser показывает, что происходит с вашим профилем прямо сейчас. Но если сотнями или тысячами профилей управляет команда — в какой-то момент нужно автоматически передавать события о профилях в CRM, систему контроля доступа или внутренний дашборд. 

Для этого Octo предоставляет Action Log — WebSocket-эндпойнт, который передает события в реальном времени. Мы добавили его для команд, у которых работа с Octo встроена в собственную CRM, ERP или систему учета. На данный момент в Action Log Octo десять типов событий — от старта и остановки профиля до передачи, удаления и изменения прокси, — и список пополняется по мере того, как команды находят новые сценарии.

Ниже — два примера того, как вы можете применять Action Log на практике: контроль доступа в реальном времени и управленческий учет на масштабе.

Содержание

Управляйте любым количеством аккаунтов без банов, рутины и лишних расходов.

Хотите попробовать Octo Browser со скидкой?
По промокоду OCTOBLOG получите 30% скидку на любую подписку. Предложение действительно только для новых пользователей.

Права доступа без ручной сверки

У одного из клиентов с профилями Octo Browser работают сотрудники из разных отделов.  У каждого свой уровень доступа через собственное расширение, используемое поверх Octo. Прежде чем выдать нужные права, система должна понять, кто сейчас работает с конкретным профилем.

Без Action Log не было видно, кто именно запускает профиль. Систему уровней доступа приходилось строить по косвенным признакам: можно было увидеть, что профиль используется, но нельзя было понять, кем именно. 

Процесс изменился, когда мы добавили в Action Log событие profiles.started: user_email приходит в момент запуска, и права применяются автоматически. Эта связка события → права стала основой большинства внутренних автоматизаций наших клиентов. 

Это постоянно работающий механизм, который реагирует на каждый запуск профиля в реальном времени. События обрабатываются на лету и сохраняются в собственной базе.

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

Учет команды за секунды вместо часов

Другой клиент готовит большой объем аккаунтов силами распределенной команды: много людей и много профилей одновременно. При таком масштабе быстро теряется общая картина: кто сколько профилей ведет, сколько готово, сколько выдано, сколько удалено, кем и почему.

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

Когда мы расширили функционал Action Log, клиент написал собственную CRM, которая через API получает события из профилей и складывает их в единую картину: сколько профилей в работе у каждого сотрудника, сколько готовых, сколько выдано, сколько удалено — с привязкой к тому, кто и когда выполнил действие. 

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

Систему разработали без привлечения штатного разработчика, с помощью AI-инструментов для написания кода. На создание рабочей версии CRM с интеграцией по API ушла неделя.

Как еще можно использовать Action Log 

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

Принцип во всех сценариях одинаков: Octo передает события о действиях с профилями в реальном времени, а клиентская система сама решает, как их использовать и хранить.

Именно реальные потребности клиентов во многом определяют развитие Action Log. События profiles.transferred, profiles.deleted, profiles.proxy_changed и другие появились по запросам команд, которые уже строили процессы вокруг API, но сталкивались с нехваткой данных. В дальнейшем набор событий будет расширяться в том же направлении.

Помимо описанных выше кейсов, Action Log можно использовать и для других задач: 

  • Биллинг и внутренние расчеты: run_duration из profiles.stopped дает точную длительность сессии — удобно, если вы тарифицируете работу сотрудников по фактическому времени с профилем, без отдельного тайм-трекера.

  • Аудит удалений: profiles.deleted и profiles.trashed с привязкой к user_email позволяют быстро находить, кто и когда удалил конкретный профиль, без необходимости спрашивать команду вручную.

  • Контроль передачи профилей: profiles.transferred содержит обе стороны в одной записи — отправителя и получателя, без сопоставления данных из разных источников.

  • Уведомления о потере данных: profiles.force_stopped означает, что запущенный профиль перевели в статус неактивного, потому что он не был закрыт штатно. Результаты работы в профиле на момент принудительной остановки не синхронизируются — стоит предупреждать коллег, которые с ним работали: их изменения не сохранятся. Подробнее в документации.

  • Учет смены прокси: тройка proxy_assigned / proxy_unassigned / proxy_changed подходит для сценариев, где внешним системам важно знать текущий прокси профиля без периодического опроса.

При этом есть важное ограничение: Action Log работает в потоковом режиме и хранит данные только за последние 24 часа. Поэтому если события нужны для аудита или долгосрочной аналитики, их необходимо сохранять в собственной системе по мере поступления. 

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

Как работает Action Log в Octo Browser

  • Тип: WebSocket

  • URL: wss://app.octobrowser.net/api/v2/automation/ws/action_log

  • Авторизация: токен в заголовке X-Octo-Api-Token

После подключения сервер сам присылает события по мере их появления — повторные запросы не нужны. Каждое сообщение — StreamPage: массив событий и watermark.

{
  "items": [
    {
      "uuid": "550e8400-e29b-41d4-a716-446655440000",
      "action": "profiles.started",
      "time": 1707053400,
      "user_email": "user@example.com",
      "object_type": "profile",
      "object_id": "a1b2c3d4e5f67890abcdef1234567890",
      "object_title": "Octo Browser Profile",
      "data": {
        "connection_data": {
          "ip": "203.0.113.42",
          "countryCode": "FR",
          "countryName": "France",
          "subdivisions": ["Île-de-France", "Paris"],
          "postalCode": "75008",
          "cityName": "Paris",
          "timezone": "Europe/Paris",
          "lat": 48.8566,
          "lon": 2.3522,
          "languages": ["fr", "en-US", "en"],
          "isp": "Example Networks Ltd",
          "connectionType": "Cable/DSL"
        }
      }
    }
  ],
  "watermark": {
    "uuid": "550e8400-e29b-41d4-a716-446655440000",
    "time": 1707053400
  }
}
{
  "items": [
    {
      "uuid": "550e8400-e29b-41d4-a716-446655440000",
      "action": "profiles.started",
      "time": 1707053400,
      "user_email": "user@example.com",
      "object_type": "profile",
      "object_id": "a1b2c3d4e5f67890abcdef1234567890",
      "object_title": "Octo Browser Profile",
      "data": {
        "connection_data": {
          "ip": "203.0.113.42",
          "countryCode": "FR",
          "countryName": "France",
          "subdivisions": ["Île-de-France", "Paris"],
          "postalCode": "75008",
          "cityName": "Paris",
          "timezone": "Europe/Paris",
          "lat": 48.8566,
          "lon": 2.3522,
          "languages": ["fr", "en-US", "en"],
          "isp": "Example Networks Ltd",
          "connectionType": "Cable/DSL"
        }
      }
    }
  ],
  "watermark": {
    "uuid": "550e8400-e29b-41d4-a716-446655440000",
    "time": 1707053400
  }
}

Сейчас Action Log поддерживает десять типов событий:

  • profiles.started — профиль запущен;

  • profiles.stopped — профиль остановлен;

  • profiles.force_stopped — профиль принудительно завершен;

  • profiles.transferred — профиль передан другому пользователю;

  • profiles.trashed — профиль перемещен в корзину;

  • profiles.deleted — профиль удален;

  • profiles.updated — профиль изменен;

  • profiles.proxy_assigned — прокси назначен профилю;

  • profiles.proxy_unassigned — прокси снят с профиля;

  • profiles.proxy_changed — прокси изменен на другой.

Для устойчивости к разрывам связи в каждом сообщении есть watermark — UUID и время последнего события. При переподключении достаточно передать этот UUID в параметре after_uuid: стрим отправит все, что произошло за время простоя, не теряя и не дублируя события. Второй способ — стартовать с конкретного момента через from_timestamp. Ограничение одно: события хранятся 24 часа, это живой поток, а не архив.

Это работает и при массовых операциях: если сотрудник перемещает в корзину сразу сто профилей, в потоке появятся все сто событий, каждое со своим object_id — ни одно не потеряется и не задвоится.

Подробнее о работе Action Log можно прочитать в документации.

Что лежит в data — разбор по событиям

Набор полей внутри data зависит от action. Вот что приходит для каждого из десяти типов:

Событие

Что в data

profiles.started

connection_data — информация о соединении

profiles.stopped

run_duration — длительность сессии

profiles.deleted

manual — было ли удаление ручным

profiles.updated

changeset — только те поля, которые реально изменились

profiles.transferred

receiver — почта получателя (отправитель — в user_email)

profiles.proxy_assigned / profiles.proxy_unassigned

proxy_uuid, proxy_title, url, temporary

profiles.proxy_changed

те же поля с префиксами old_ и new_

profiles.stopped

Длительность сессии приходит в формате ISO 8601, а не как число секунд:

{
  "action": "profiles.stopped",
  "data": {
    "run_duration": "PT19.627134S"
  }
}
{
  "action": "profiles.stopped",
  "data": {
    "run_duration": "PT19.627134S"
  }
}

profiles.updated

changeset — не фиксированный список полей, а динамический дифф: в нем только то, что поменялось в этот раз. Например, при изменении нескольких настроек профиля сразу приходит вот что:

{
  "action": "profiles.updated",
  "data": {
    "changeset": {
      "description": {
        "old_value": "",
        "new_value": "Test action log"
      },
      "start_pages": {
        "added": ["http://google.com", "http://facebook.com"],
        "removed": []
      },
      "storage_options": {
        "added": ["serviceworkers", "localstorage"],
        "removed": []
      },
      "bookmarks": {
        "added": ["https://ebay.com", "https://amazon.com"],
        "removed": []
      },
      "launch_args": {
        "added": ["--start-maximized"],
        "removed": []
      },
      "images_load_limit": {
        "old_value": null,
        "new_value": 10240
      },
      "local_cache": {
        "old_value": false,
        "new_value": true
      },
      "fingerprint": {}
    }
  }
}
{
  "action": "profiles.updated",
  "data": {
    "changeset": {
      "description": {
        "old_value": "",
        "new_value": "Test action log"
      },
      "start_pages": {
        "added": ["http://google.com", "http://facebook.com"],
        "removed": []
      },
      "storage_options": {
        "added": ["serviceworkers", "localstorage"],
        "removed": []
      },
      "bookmarks": {
        "added": ["https://ebay.com", "https://amazon.com"],
        "removed": []
      },
      "launch_args": {
        "added": ["--start-maximized"],
        "removed": []
      },
      "images_load_limit": {
        "old_value": null,
        "new_value": 10240
      },
      "local_cache": {
        "old_value": false,
        "new_value": true
      },
      "fingerprint": {}
    }
  }
}

Видны два паттерна: 

  • для одиночных значений (description, images_load_limit, local_cache) приходит пара old_value/new_value

  • для списков (start_pages, storage_options, bookmarks, launch_args) — added/removed

fingerprint — исключение: ключ появляется, когда отпечаток действительно менялся, но всегда как пустой объект, без деталей, что конкретно поменялось внутри. Общее правило простое: если поле не менялось, его ключа в changeset не будет.

profiles.deleted

{
  "action": "profiles.deleted",
  "data": {
    "manual": true
  }
}
{
  "action": "profiles.deleted",
  "data": {
    "manual": true
  }
}

profiles.proxy_changed

Сравнивает старый и новый прокси одним событием:

{
  "action": "profiles.proxy_changed",
  "data": {
    "old_proxy_uuid": "370b0ce963194f68803a812dd42db4be",
    "old_proxy_title": "Netlabs GB England",
    "old_url": "socks5://user:pass@proxy.example.com:1080",
    "new_proxy_uuid": "9c51385c3e2b417d9b34fc305a49d4f6",
    "new_proxy_title": "Netlabs GB England Towcester",
    "new_url": "socks5://user:pass@proxy2.example.com:1080"
  }
}
{
  "action": "profiles.proxy_changed",
  "data": {
    "old_proxy_uuid": "370b0ce963194f68803a812dd42db4be",
    "old_proxy_title": "Netlabs GB England",
    "old_url": "socks5://user:pass@proxy.example.com:1080",
    "new_proxy_uuid": "9c51385c3e2b417d9b34fc305a49d4f6",
    "new_proxy_title": "Netlabs GB England Towcester",
    "new_url": "socks5://user:pass@proxy2.example.com:1080"
  }
}

profiles.proxy_assigned и profiles.proxy_unassigned отдают те же поля, но без префиксов old_/new_ — по одному набору на событие, а не сравнение. 

Отдельно поле temporary: true означает, что прокси вставлен через быстрое действие (например, вставкой строки), а не назначен обычным способом через настройки профиля.

profiles.trashed и автоудаление

profiles.trashed приходит с пустым data — как и force_stopped. Если профиль не восстановить и не удалить вручную, он удалится сам через 72 часа — подробнее в документации о корзине

profiles.transferred

Одно событие содержит обе стороны сразу:

{
  "action": "profiles.transferred",
  "user_email": "sender@example.com",
  "data": {
    "receiver": "receiver@example.com"
  }
}
{
  "action": "profiles.transferred",
  "user_email": "sender@example.com",
  "data": {
    "receiver": "receiver@example.com"
  }
}

user_email — как и в любом другом событии, тот, кто выполнил действие, то есть отправитель трансфера. 

data.receiver — получатель.

Подключение и переподключение

Подключиться можно любым клиентом с поддержкой WebSocket. 

На Node.js это выглядит так:

const WebSocket = require('ws');

const ws = new WebSocket('wss://app.octobrowser.net/api/v2/automation/ws/action_log', {
  headers: {
    'X-Octo-Api-Token': 'Octo API Token'
  }
});

ws.on('open', () => console.log('Connected!'));
ws.on('message', (data) => {
  const parsed = JSON.parse(data.toString());
  console.log(JSON.stringify(parsed, null, 2));
  console.log('');
});
ws.on('error', (err) => console.log('Error:', err.message));
ws.on('close', () => console.log('Connection closed'));
const WebSocket = require('ws');

const ws = new WebSocket('wss://app.octobrowser.net/api/v2/automation/ws/action_log', {
  headers: {
    'X-Octo-Api-Token': 'Octo API Token'
  }
});

ws.on('open', () => console.log('Connected!'));
ws.on('message', (data) => {
  const parsed = JSON.parse(data.toString());
  console.log(JSON.stringify(parsed, null, 2));
  console.log('');
});
ws.on('error', (err) => console.log('Error:', err.message));
ws.on('close', () => console.log('Connection closed'));

Что означает каждое поле в пришедшем событии:

  • uuid — идентификатор самого события, а не профиля; уникален для каждой записи, даже если несколько событий произошли в одну секунду;

  • action — тип действия из списка выше;

  • time — время события в Unix-формате;

  • user_email — почта пользователя, который совершил действие;

  • object_type — тип объекта, к которому относится событие;

  • object_id — идентификатор самого профиля, отдельный от UUID события;

  • object_title — название профиля на момент события;

  • data — детали, зависящие от action, разбор выше.

Если профиль остановить, придет второе событие — profiles.stopped, с новым uuid, но тем же object_id, потому что профиль тот же. По object_id можно связывать все события одного профиля в единую историю на своей стороне — object_id не меняется на всем протяжении жизни профиля, от старта до удаления.

Чтобы продолжить стрим после разрыва связи, достаточно сохранить uuid из последнего полученного watermark и передать его в after_uuid:

const WebSocket = require('ws');

const ws = new WebSocket('wss://app.octobrowser.net/api/v2/automation/ws/action_log?after_uuid=UUID', {
  headers: {
    'X-Octo-Api-Token': 'Octo API Token'
  }
});

ws.on('open', () => console.log('Connected!'));
ws.on('message', (data) => {
  const parsed = JSON.parse(data.toString());
  console.log(JSON.stringify(parsed, null, 2));
  console.log('');
});
ws.on('error', (err) => console.log('Error:', err.message));
ws.on('close', () => console.log('Connection closed'));
const WebSocket = require('ws');

const ws = new WebSocket('wss://app.octobrowser.net/api/v2/automation/ws/action_log?after_uuid=UUID', {
  headers: {
    'X-Octo-Api-Token': 'Octo API Token'
  }
});

ws.on('open', () => console.log('Connected!'));
ws.on('message', (data) => {
  const parsed = JSON.parse(data.toString());
  console.log(JSON.stringify(parsed, null, 2));
  console.log('');
});
ws.on('error', (err) => console.log('Error:', err.message));
ws.on('close', () => console.log('Connection closed'));

Соединение сразу отправит события, случившиеся после этого UUID, а затем продолжит работать как обычный стрим — повторный after_uuid нужен только при следующем разрыве.

Если сохраненного watermark нет — например, после долгого простоя вы знаете только примерное время отключения — можно стартовать по времени через from_timestamp (Unix-время в секундах):

const WebSocket = require('ws');

const ws = new WebSocket('wss://app.octobrowser.net/api/v2/automation/ws/action_log?from_timestamp=TIMESTAMP', {
  headers: {
    'X-Octo-Api-Token': 'Octo API Token'
  }
});

ws.on('open', () => console.log('Connected!'));
ws.on('message', (data) => {
  const parsed = JSON.parse(data.toString());
  console.log(JSON.stringify(parsed, null, 2));
  console.log('');
});
ws.on('error', (err) => console.log('Error:', err.message));
ws.on('close', () => console.log('Connection closed'));
const WebSocket = require('ws');

const ws = new WebSocket('wss://app.octobrowser.net/api/v2/automation/ws/action_log?from_timestamp=TIMESTAMP', {
  headers: {
    'X-Octo-Api-Token': 'Octo API Token'
  }
});

ws.on('open', () => console.log('Connected!'));
ws.on('message', (data) => {
  const parsed = JSON.parse(data.toString());
  console.log(JSON.stringify(parsed, null, 2));
  console.log('');
});
ws.on('error', (err) => console.log('Error:', err.message));
ws.on('close', () => console.log('Connection closed'));

Если вы только начинаете работать с автоматизацией, то подробнее про API Octo Browser мы рассказали в отдельной статье.

Заключение

Action Log позволяет использовать события Octo Browser как часть собственной инфраструктуры: передавать их в CRM, систему контроля доступа, аналитику или другие внутренние инструменты. Octo сообщает, что произошло с профилем, а дальше вы сами определяете, как обработать, сохранить и использовать эти данные.

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

Управляйте любым количеством аккаунтов без банов, рутины и лишних расходов.

Хотите попробовать Octo Browser со скидкой?
По промокоду OCTOBLOG получите 30% скидку на любую подписку. Предложение действительно только для новых пользователей.

Права доступа без ручной сверки

У одного из клиентов с профилями Octo Browser работают сотрудники из разных отделов.  У каждого свой уровень доступа через собственное расширение, используемое поверх Octo. Прежде чем выдать нужные права, система должна понять, кто сейчас работает с конкретным профилем.

Без Action Log не было видно, кто именно запускает профиль. Систему уровней доступа приходилось строить по косвенным признакам: можно было увидеть, что профиль используется, но нельзя было понять, кем именно. 

Процесс изменился, когда мы добавили в Action Log событие profiles.started: user_email приходит в момент запуска, и права применяются автоматически. Эта связка события → права стала основой большинства внутренних автоматизаций наших клиентов. 

Это постоянно работающий механизм, который реагирует на каждый запуск профиля в реальном времени. События обрабатываются на лету и сохраняются в собственной базе.

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

Учет команды за секунды вместо часов

Другой клиент готовит большой объем аккаунтов силами распределенной команды: много людей и много профилей одновременно. При таком масштабе быстро теряется общая картина: кто сколько профилей ведет, сколько готово, сколько выдано, сколько удалено, кем и почему.

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

Когда мы расширили функционал Action Log, клиент написал собственную CRM, которая через API получает события из профилей и складывает их в единую картину: сколько профилей в работе у каждого сотрудника, сколько готовых, сколько выдано, сколько удалено — с привязкой к тому, кто и когда выполнил действие. 

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

Систему разработали без привлечения штатного разработчика, с помощью AI-инструментов для написания кода. На создание рабочей версии CRM с интеграцией по API ушла неделя.

Как еще можно использовать Action Log 

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

Принцип во всех сценариях одинаков: Octo передает события о действиях с профилями в реальном времени, а клиентская система сама решает, как их использовать и хранить.

Именно реальные потребности клиентов во многом определяют развитие Action Log. События profiles.transferred, profiles.deleted, profiles.proxy_changed и другие появились по запросам команд, которые уже строили процессы вокруг API, но сталкивались с нехваткой данных. В дальнейшем набор событий будет расширяться в том же направлении.

Помимо описанных выше кейсов, Action Log можно использовать и для других задач: 

  • Биллинг и внутренние расчеты: run_duration из profiles.stopped дает точную длительность сессии — удобно, если вы тарифицируете работу сотрудников по фактическому времени с профилем, без отдельного тайм-трекера.

  • Аудит удалений: profiles.deleted и profiles.trashed с привязкой к user_email позволяют быстро находить, кто и когда удалил конкретный профиль, без необходимости спрашивать команду вручную.

  • Контроль передачи профилей: profiles.transferred содержит обе стороны в одной записи — отправителя и получателя, без сопоставления данных из разных источников.

  • Уведомления о потере данных: profiles.force_stopped означает, что запущенный профиль перевели в статус неактивного, потому что он не был закрыт штатно. Результаты работы в профиле на момент принудительной остановки не синхронизируются — стоит предупреждать коллег, которые с ним работали: их изменения не сохранятся. Подробнее в документации.

  • Учет смены прокси: тройка proxy_assigned / proxy_unassigned / proxy_changed подходит для сценариев, где внешним системам важно знать текущий прокси профиля без периодического опроса.

При этом есть важное ограничение: Action Log работает в потоковом режиме и хранит данные только за последние 24 часа. Поэтому если события нужны для аудита или долгосрочной аналитики, их необходимо сохранять в собственной системе по мере поступления. 

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

Как работает Action Log в Octo Browser

  • Тип: WebSocket

  • URL: wss://app.octobrowser.net/api/v2/automation/ws/action_log

  • Авторизация: токен в заголовке X-Octo-Api-Token

После подключения сервер сам присылает события по мере их появления — повторные запросы не нужны. Каждое сообщение — StreamPage: массив событий и watermark.

{
  "items": [
    {
      "uuid": "550e8400-e29b-41d4-a716-446655440000",
      "action": "profiles.started",
      "time": 1707053400,
      "user_email": "user@example.com",
      "object_type": "profile",
      "object_id": "a1b2c3d4e5f67890abcdef1234567890",
      "object_title": "Octo Browser Profile",
      "data": {
        "connection_data": {
          "ip": "203.0.113.42",
          "countryCode": "FR",
          "countryName": "France",
          "subdivisions": ["Île-de-France", "Paris"],
          "postalCode": "75008",
          "cityName": "Paris",
          "timezone": "Europe/Paris",
          "lat": 48.8566,
          "lon": 2.3522,
          "languages": ["fr", "en-US", "en"],
          "isp": "Example Networks Ltd",
          "connectionType": "Cable/DSL"
        }
      }
    }
  ],
  "watermark": {
    "uuid": "550e8400-e29b-41d4-a716-446655440000",
    "time": 1707053400
  }
}

Сейчас Action Log поддерживает десять типов событий:

  • profiles.started — профиль запущен;

  • profiles.stopped — профиль остановлен;

  • profiles.force_stopped — профиль принудительно завершен;

  • profiles.transferred — профиль передан другому пользователю;

  • profiles.trashed — профиль перемещен в корзину;

  • profiles.deleted — профиль удален;

  • profiles.updated — профиль изменен;

  • profiles.proxy_assigned — прокси назначен профилю;

  • profiles.proxy_unassigned — прокси снят с профиля;

  • profiles.proxy_changed — прокси изменен на другой.

Для устойчивости к разрывам связи в каждом сообщении есть watermark — UUID и время последнего события. При переподключении достаточно передать этот UUID в параметре after_uuid: стрим отправит все, что произошло за время простоя, не теряя и не дублируя события. Второй способ — стартовать с конкретного момента через from_timestamp. Ограничение одно: события хранятся 24 часа, это живой поток, а не архив.

Это работает и при массовых операциях: если сотрудник перемещает в корзину сразу сто профилей, в потоке появятся все сто событий, каждое со своим object_id — ни одно не потеряется и не задвоится.

Подробнее о работе Action Log можно прочитать в документации.

Что лежит в data — разбор по событиям

Набор полей внутри data зависит от action. Вот что приходит для каждого из десяти типов:

Событие

Что в data

profiles.started

connection_data — информация о соединении

profiles.stopped

run_duration — длительность сессии

profiles.deleted

manual — было ли удаление ручным

profiles.updated

changeset — только те поля, которые реально изменились

profiles.transferred

receiver — почта получателя (отправитель — в user_email)

profiles.proxy_assigned / profiles.proxy_unassigned

proxy_uuid, proxy_title, url, temporary

profiles.proxy_changed

те же поля с префиксами old_ и new_

profiles.stopped

Длительность сессии приходит в формате ISO 8601, а не как число секунд:

{
  "action": "profiles.stopped",
  "data": {
    "run_duration": "PT19.627134S"
  }
}

profiles.updated

changeset — не фиксированный список полей, а динамический дифф: в нем только то, что поменялось в этот раз. Например, при изменении нескольких настроек профиля сразу приходит вот что:

{
  "action": "profiles.updated",
  "data": {
    "changeset": {
      "description": {
        "old_value": "",
        "new_value": "Test action log"
      },
      "start_pages": {
        "added": ["http://google.com", "http://facebook.com"],
        "removed": []
      },
      "storage_options": {
        "added": ["serviceworkers", "localstorage"],
        "removed": []
      },
      "bookmarks": {
        "added": ["https://ebay.com", "https://amazon.com"],
        "removed": []
      },
      "launch_args": {
        "added": ["--start-maximized"],
        "removed": []
      },
      "images_load_limit": {
        "old_value": null,
        "new_value": 10240
      },
      "local_cache": {
        "old_value": false,
        "new_value": true
      },
      "fingerprint": {}
    }
  }
}

Видны два паттерна: 

  • для одиночных значений (description, images_load_limit, local_cache) приходит пара old_value/new_value

  • для списков (start_pages, storage_options, bookmarks, launch_args) — added/removed

fingerprint — исключение: ключ появляется, когда отпечаток действительно менялся, но всегда как пустой объект, без деталей, что конкретно поменялось внутри. Общее правило простое: если поле не менялось, его ключа в changeset не будет.

profiles.deleted

{
  "action": "profiles.deleted",
  "data": {
    "manual": true
  }
}

profiles.proxy_changed

Сравнивает старый и новый прокси одним событием:

{
  "action": "profiles.proxy_changed",
  "data": {
    "old_proxy_uuid": "370b0ce963194f68803a812dd42db4be",
    "old_proxy_title": "Netlabs GB England",
    "old_url": "socks5://user:pass@proxy.example.com:1080",
    "new_proxy_uuid": "9c51385c3e2b417d9b34fc305a49d4f6",
    "new_proxy_title": "Netlabs GB England Towcester",
    "new_url": "socks5://user:pass@proxy2.example.com:1080"
  }
}

profiles.proxy_assigned и profiles.proxy_unassigned отдают те же поля, но без префиксов old_/new_ — по одному набору на событие, а не сравнение. 

Отдельно поле temporary: true означает, что прокси вставлен через быстрое действие (например, вставкой строки), а не назначен обычным способом через настройки профиля.

profiles.trashed и автоудаление

profiles.trashed приходит с пустым data — как и force_stopped. Если профиль не восстановить и не удалить вручную, он удалится сам через 72 часа — подробнее в документации о корзине

profiles.transferred

Одно событие содержит обе стороны сразу:

{
  "action": "profiles.transferred",
  "user_email": "sender@example.com",
  "data": {
    "receiver": "receiver@example.com"
  }
}

user_email — как и в любом другом событии, тот, кто выполнил действие, то есть отправитель трансфера. 

data.receiver — получатель.

Подключение и переподключение

Подключиться можно любым клиентом с поддержкой WebSocket. 

На Node.js это выглядит так:

const WebSocket = require('ws');

const ws = new WebSocket('wss://app.octobrowser.net/api/v2/automation/ws/action_log', {
  headers: {
    'X-Octo-Api-Token': 'Octo API Token'
  }
});

ws.on('open', () => console.log('Connected!'));
ws.on('message', (data) => {
  const parsed = JSON.parse(data.toString());
  console.log(JSON.stringify(parsed, null, 2));
  console.log('');
});
ws.on('error', (err) => console.log('Error:', err.message));
ws.on('close', () => console.log('Connection closed'));

Что означает каждое поле в пришедшем событии:

  • uuid — идентификатор самого события, а не профиля; уникален для каждой записи, даже если несколько событий произошли в одну секунду;

  • action — тип действия из списка выше;

  • time — время события в Unix-формате;

  • user_email — почта пользователя, который совершил действие;

  • object_type — тип объекта, к которому относится событие;

  • object_id — идентификатор самого профиля, отдельный от UUID события;

  • object_title — название профиля на момент события;

  • data — детали, зависящие от action, разбор выше.

Если профиль остановить, придет второе событие — profiles.stopped, с новым uuid, но тем же object_id, потому что профиль тот же. По object_id можно связывать все события одного профиля в единую историю на своей стороне — object_id не меняется на всем протяжении жизни профиля, от старта до удаления.

Чтобы продолжить стрим после разрыва связи, достаточно сохранить uuid из последнего полученного watermark и передать его в after_uuid:

const WebSocket = require('ws');

const ws = new WebSocket('wss://app.octobrowser.net/api/v2/automation/ws/action_log?after_uuid=UUID', {
  headers: {
    'X-Octo-Api-Token': 'Octo API Token'
  }
});

ws.on('open', () => console.log('Connected!'));
ws.on('message', (data) => {
  const parsed = JSON.parse(data.toString());
  console.log(JSON.stringify(parsed, null, 2));
  console.log('');
});
ws.on('error', (err) => console.log('Error:', err.message));
ws.on('close', () => console.log('Connection closed'));

Соединение сразу отправит события, случившиеся после этого UUID, а затем продолжит работать как обычный стрим — повторный after_uuid нужен только при следующем разрыве.

Если сохраненного watermark нет — например, после долгого простоя вы знаете только примерное время отключения — можно стартовать по времени через from_timestamp (Unix-время в секундах):

const WebSocket = require('ws');

const ws = new WebSocket('wss://app.octobrowser.net/api/v2/automation/ws/action_log?from_timestamp=TIMESTAMP', {
  headers: {
    'X-Octo-Api-Token': 'Octo API Token'
  }
});

ws.on('open', () => console.log('Connected!'));
ws.on('message', (data) => {
  const parsed = JSON.parse(data.toString());
  console.log(JSON.stringify(parsed, null, 2));
  console.log('');
});
ws.on('error', (err) => console.log('Error:', err.message));
ws.on('close', () => console.log('Connection closed'));

Если вы только начинаете работать с автоматизацией, то подробнее про API Octo Browser мы рассказали в отдельной статье.

Заключение

Action Log позволяет использовать события Octo Browser как часть собственной инфраструктуры: передавать их в CRM, систему контроля доступа, аналитику или другие внутренние инструменты. Octo сообщает, что произошло с профилем, а дальше вы сами определяете, как обработать, сохранить и использовать эти данные.

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

Следите за последними новостями Octo Browser

Нажимая кнопку, вы соглашаетесь с нашей политикой конфиденциальности.

Следите за последними новостями Octo Browser

Нажимая кнопку, вы соглашаетесь с нашей политикой конфиденциальности.

Следите за последними новостями Octo Browser

Нажимая кнопку, вы соглашаетесь с нашей политикой конфиденциальности.

Присоединяйтесь к Octo Browser сейчас

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

Присоединяйтесь к Octo Browser сейчас

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

Присоединяйтесь к Octo Browser сейчас

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

©

2026

Octo Browser

©

2026

Octo Browser

©

2026

Octo Browser