Как запускать браузер на своём же рабочем столе, не отдавая ему фокус
Вы запускаете автоматизацию на той же машине, где работаете, продолжаете печатать, и через три секунды ваши нажатия уходят в автоматизированный браузер. В цикле из 200 задач это происходит 200 раз. Очевидное решение - вообще не рисовать окно, и стоит оно дороже, чем кажется.
Почему headless здесь не ответ
Headless - это не настройка отображения. Это другая конфигурация браузера, и страница это замечает. Она читает те же поверхности, что и всегда, но часть из них отвечает иначе, когда за ними нет ни настоящего окна, ни настоящего компоновщика. Тратить работу над отпечатком ради того, чтобы сэкономить одну запись в панели задач, - плохой обмен.
Свернуть окно тоже не выход, и причина проще. Свёрнутое окно сообщает document.visibilityState === 'hidden', а для страниц в этом состоянии браузер придерживает таймеры и кадры анимации. Сайты, которые откладывают работу до момента, когда вкладка станет видимой, просто её не сделают, и ваша автоматизация будет ждать того, что уже не произойдёт.
То есть требование уже, чем «спрятать»: нужно настоящее видимое окно обычного размера, которое не выходит на передний план.
Что делает запуск без фокуса
focusWindow: false в launch() делает ровно одну эту вещь:
await ab.launch({ profile: 'task-01', focusWindow: false })
Окно открывается обычного размера, в обычном порядке окон, позади того, чем вы были заняты. Оно не свёрнуто, не вынесено за пределы экрана и не headless, поэтому в отпечатке ничего не меняется. Ввод с клавиатуры остаётся там, где был.
По умолчанию значение true, и что-то меняет только явный false. Незаданная опция запускает браузер ровно так, как раньше, - это важно, потому что такой флаг обычно ставят глобально и забывают.
Порядок окон определяется ядром, а не SDK, поэтому перед тем, как на это полагаться, установите для профиля последнюю версию ядра.
Опция есть и в MCP-инструменте, где она, пожалуй, нужнее всего: агент, открывающий браузеры на вашей рабочей машине, пока вы за ней работаете, - это ровно тот случай, ради которого всё и сделано.
Что это по-прежнему не решает
Не забирать фокус и быть невидимым - разные состояния, а управляет эта опция только первым. Окно, целиком закрытое другим окном, всё ещё может быть сочтено невидимым со всеми вытекающими задержками таймеров. Если ваша автоматизация зависит от того, чтобы таймеры страницы шли в полную скорость, оставьте окну место, где его ничто не перекрывает, либо перенесите прогон на машину, за которой вы не сидите.
Никаких гарантий порядка, кроме «не поднимать наверх», тоже нет. Запустите шесть браузеров без фокуса - получите шесть окон позади вашей работы, сложенных в том порядке, в каком они открывались.
Кому это вообще не нужно
На сервере, в контейнере и на любой машине, за которой вы не сидите, эта опция решает несуществующую проблему. Фокус там никто не отбирает, и правильная схема - машина с дисплейным сервером и без человека за ней.
Если же вы хотите этого потому, что держите двадцать одновременных браузеров на одном рабочем столе, порядок окон - не ваша настоящая проблема. Двадцать видимых окон на рабочей машине - вопрос ресурсов, и отдельный хост отвечает на него лучше любого флага.
А если вы тянулись к headless по привычке, а не потому, что вам действительно нужно работать без дисплея, то честный вывод такой: скорее всего, вам не нужна ни одна из этих двух опций.
Как проверить самому
Откройте что-нибудь, куда можно печатать, оставьте фокус там и запустите браузер с focusWindow: false. Продолжайте печатать. Символы должны и дальше попадать туда, где вы их оставили, а окно браузера - быть видно позади.
Затем убедитесь, что браузер не заплатил за это своей видимостью:
await page.evaluate(() => [document.hasFocus(), document.visibilityState])
Нужен ответ [false, 'visible']. hasFocus() со значением false - это работающая функция. visibilityState, оставшийся visible, - именно то, что отличает этот режим от свёрнутого окна, и именно это значение стоит перепроверить на своей раскладке окон.
Полный список опций - в документации SDK. Про то, где держать профили таких прогонов, есть отдельная заметка: временные профили для автоматизации.
Попробуйте на бесплатном тарифе.
Неограниченное число локальных профилей, без карты. Проверьте результат детекторами сами.