App store optimization
A/B-тестирование скриншотов App Store для небольшого приложения
Это бесплатно и встроено в App Store Connect. Но для небольшого приложения трафика, скорее всего, недостаточно, чтобы надёжно отличить две похожие страницы друг от друга, поэтому основная работа заключается в том, чтобы выбирать варианты, которые отличаются действительно сильно.
Встроенный способ Apple для A/B-тестирования скриншотов App Store называется Product Page Optimization: можно создать до 3 альтернативных версий страницы приложения, которые Apple называет treatments, и сравнивать их с оригиналом. Каждая версия показывается случайной доле пользователей, открывающих страницу, причём эту долю вы настраиваете сами.
Это бесплатно и встроено в App Store Connect. Но для небольшого приложения трафика, скорее всего, недостаточно, чтобы надёжно отличить две похожие страницы друг от друга, поэтому основная работа заключается в том, чтобы выбирать варианты, которые отличаются действительно сильно.
Вот как я настроил всё это для Reckon, своего приложения для ведения дневника принятия решений: этапы тестирования, что трафик небольшого приложения способен и не способен показать, а также скрипт, который Claude Code написал для загрузки treatments через App Store Connect API. Генерация самих скриншотов заслужила отдельную статью.
Сначала правила Apple, поскольку некоторые из них практически определяют весь дальнейший подход:
- Одновременно может выполняться только один тест, в котором разрешено до 3 дополнительных treatments. Treatment может менять скриншоты, app preview или иконку, причём альтернативная иконка должна заранее присутствовать в binary приложения.
- Вы выбираете traffic proportion — долю посетителей, которым будут показываться treatments вместо оригинала, — а Apple равномерно распределяет этот трафик между treatments.
- Если приложение работает на iPad, для каждого treatment необходимо добавить и комплект скриншотов для iPad, иначе тест нельзя отправить.
- Тестируется только default product page. Custom product pages в тест не входят, поэтому пользователь, пришедший на такую страницу по её ключевым словам или рекламе, в эксперимент не попадает.
- Новые скриншоты проходят App Review при запуске теста; если альтернативная иконка не используется, ждать выпуска новой версии приложения не нужно.
- Тест может идти до 90 дней или пока вы сами его не остановите. Остановленный тест нельзя перезапустить — придётся создать новый с теми же treatments.
- Применение treatment к оригинальной странице завершает тест.
- Treatment получает метку «Performing Better» или «Performing Worse» только после достижения 90% confidence, и Apple рекомендует ждать этой метки перед применением treatment или остановкой теста. Но при низком трафике до такого уровня можно вообще не добраться.
Именно эту метку и стоит считать результатом теста.
Оценочный коэффициент конверсии рядом с каждым вариантом может выглядеть очень точным числом, но при небольшом количестве данных он заметно скачет. Само по себе число дней, в течение которых идёт тест, мало о чём говорит: нишевому приложению могут понадобиться недели, чтобы накопить хоть сколько-нибудь значимые данные.
Планирование раундов
Поскольку одновременно можно запускать только один тест с максимум 3 treatments, я планирую раунды, а не отдельные скриншоты. В каждом раунде меняется одна вещь — от самых крупных изменений к самым мелким:
- Round 0 — страница по умолчанию; лучший вариант на момент запуска и контрольная версия, с которой сравниваются все treatments.
- Round 1 тестирует «зацепки» (hook): 3 разных обещания при одной и той же визуальной структуре.
- Round 2 сохраняет победивший текст и пробует 3 разных визуала на первом скриншоте.
- Round 3 сохраняет победившую пару и в каждом treatment меняет одну структурную вещь: меньше скриншотов, сравнительный скриншот, другой layout и так далее.
Round 1 требует больше всего размышлений, потому что «зацепки» могут дать как очень положительный, так и очень отрицательный эффект.
Три treatments должны быть тремя действительно разными обещаниями, каждое из которых последовательно проводится через весь набор скриншотов, а не тремя формулировками одного и того же обещания. Для Reckon я выбрал результат («Make better decisions.»), зафиксированную память («Remember what you really thought.», которая дальше продолжается фразой «No rewriting») и вопрос для последующей оценки («Would you make that call again?», продолженный позже как «Still the right call?»).
Первый скриншот каждого treatment в Round 1: «Make better decisions.», «Remember what you really thought.» и «Would you make that call again?», при этом во всех трёх вариантах используются одни и те же три карточки уже принятых решений.

Одни и те же карточки во всех трёх вариантах — намеренно.
Визуал первого скриншота — это уже вопрос Round 2, и если изменить его одновременно с текстом, то победителя будет невозможно объяснить: сработало обещание или картинка?
Собственная аналитика Apple подталкивает к тому же подходу. Для теста, который может не собрать достаточно данных для 90% уверенности за 90 дней, одна из рекомендаций Apple — «тестирование более радикального изменения, которое может обеспечить более значительный прирост». Большая разница требует меньше недель данных, чтобы проявиться, чем маленькая. Для небольшого приложения, на мой взгляд, именно с этого и стоит начинать, а не оставлять такие изменения на потом.
Чтобы найти три варианта, перечислите все обещания, которые приложение реально способно выполнить, а затем выберите те, которые отличаются как страницы, а не как отдельные строки. Результат, боль пользователя, механизм и самый характерный вопрос приложения обычно становятся хорошими кандидатами, а реальное число, которое показывает приложение, может само по себе стать «крючком».
Между раундами применяйте победителя к дефолтной странице перед запуском следующего теста, иначе следующий раунд будет сравниваться со старой страницей. Поэтому я и не экспортирую и не загружаю Round 2 или Round 3 заранее: их текст зависит от победителя Round 1, иначе пришлось бы делать одну и ту же работу дважды.
Оригинал тоже остаётся участником соревнования. Раунд может закончиться так, что ни один treatment не превысит порог 90%, что особенно вероятно, когда трафик нового приложения делится между четырьмя версиями. В таком случае оригинал просто остаётся, либо я сам принимаю решение, ориентируясь на результаты Apple — % улучшения и уверенность.
Теперь весь этот процесс оформлен как навык Claude Code рядом с инструкцией по созданию скриншотов и шагами загрузки. Следующее приложение начнёт с готового плана, а не с того, что я смогу вспомнить.
Трафик небольшого приложения
Насколько маленький трафик считается маленьким? Первый раунд Reckon получил от 15 до 19 уникальных показов на treatment, где уникальный показ — это отдельное устройство, увидевшее данный вариант.
При таком объёме всего пара загрузок определяет весь рейтинг.
Если каждый treatment получает примерно одинаковые загрузки, то вариант с меньшим числом посетителей покажет более высокий estimated rate, но это говорит что-то о трафике и практически ничего о самой странице.
Небольшая разница между страницами при таком объёме данных практически не проявится; шанс есть только у большого различия. Именно поэтому Round 1 сравнивает три разных обещания, а не три формулировки одного.
А что делать, если ни один вариант не достигает 90%? Либо оставить оригинал, либо выбрать вариант самостоятельно — главное не принимать такое решение за настоящий результат теста.
Первый раунд Reckon даже близко не подошёл к этому уровню, поэтому я самостоятельно выбрал хук для дефолтной страницы. Round 2 и Round 3 столкнутся с тем же объёмом трафика, и пока я не знаю, имеет ли вообще смысл запускать их в таких условиях — всё ещё думаю об этом.
Проигравшие наборы тоже не пропадают зря. Каждый из них — законченная страница со своим аргументом, поэтому её можно превратить в custom product page для подходящих поисковых запросов. Назначьте ей ключевые слова соответствующего интента, и она будет показываться по ним вместо дефолтной; одна комбинация ключевых слов может принадлежать только одной странице.
Но custom product page не может заменить результат A/B-теста.
Её посетители приходят по собственным ключевым словам или рекламе, поэтому сравнение двух таких страниц одновременно сравнивает разные группы пользователей и разные скриншоты. Тест, напротив, показывает каждый вариант одной и той же аудитории, попадающей на страницу по умолчанию.
Рост конверсии на custom pages почти ничего не говорит о том, какое обещание победило бы на дефолтной странице. Для оценки custom page более чистый вариант — запустить её и дефолтную как рекламные варианты на одних и тех же ключевых словах в Apple Ads.
Загрузка treatments через API
Вручную один раунд означает загрузку 36 скриншотов через App Store Connect: по 6 на набор, iPhone и iPad, 3 treatments. Это довольно много, особенно если приходится переделывать всё после изменения одного скриншота.
Есть fastlane deliver, но, насколько я выяснил, он ничего не знает об экспериментах, поэтому Claude Code вместо этого написал скрипт поверх experiment endpoints в App Store Connect API. Это один Swift-файл без зависимостей: CryptoKit подписывает ES256-токен, который ожидает API — короткоживущий JSON Web Token, подписанный .p8-ключом из App Store Connect, — а URLSession выполняет запросы. Позже в той же сессии я попросил добавить возобновление работы и повторные попытки.
Скрипт принимает 3 параметра: папку, название эксперимента и названия treatments. Он ищет эксперимент с таким именем среди экспериментов приложения и создаёт новый, если его нет. Затем для каждого treatment читает соответствующую папку на диске, внутри которой находятся iphone и ipad со скриншотами, пронумерованными в нужном порядке, и проверяет, что treatment, его локализацию и оба набора скриншотов существуют в App Store Connect.
Каждый скриншот загружается чанками в соответствии с требованиями Apple, затем коммитится с checksum, после чего скрипт ждёт, пока Apple его обработает. В конце скрипт явно фиксирует порядок, поскольку Apple добавляет загруженные изображения в том порядке, в котором завершается их обработка.
Сначала я запускаю его с --dry-run: он читает папки, проверяет, что скриншоты пронумерованы без пропусков и повторов, и выводит план, не обращаясь ни к ключу, ни к сети:
swift ppo-upload.swift \ --frames marketing/screenshots/ppo \ --experiment "Round 1 · hook" \ --treatments 01-outcome,02-memory,03-follow-up \ --dry-run
Приватный ключ хранится вне репозитория, в папке, которую Claude Code не имеет права читать — песочница запрещает доступ к ней; скрипт загружает ключ во время выполнения и никогда его не печатает.
Некоторые особенности API совершенно не очевидны из документации.
Первая — trafficProportion: доля посетителей, которую treatments получают вместе, в целых процентах. Оригинал должен получать не меньше трафика, чем любой отдельный treatment. Поэтому при 3 treatments они могут получить максимум 75% трафика вместе — по 25% каждый, столько же, сколько оригинал. При 2 treatments максимум составляет 66%, а при 1 — 50%. Если запросить больше, API вернёт 409 с сообщением: «Control cannot receive less traffic than treatment, trafficProportion cannot be greater than 75%».
После создания эксперимента web UI вообще не показывает это распределение — или, по крайней мере, я его не нашёл, — поэтому доверять стоит значению из API.
Далее — автоматически созданные копии. Apple заполняет каждый новый treatment копиями скриншотов текущей live page, и в запросе создания нет способа это отключить. Скрипт не обрабатывает их как-то отдельно: он просто приводит каждый набор в App Store Connect в соответствие с папкой на диске. Скриншот, которого нет в папке, удаляется — вместе с автоматически созданными копиями, второй копией того же изображения, картинкой, которую Apple так и не закончила обрабатывать, или файлом, который изменился после загрузки.
Всё остальное сохраняется, и именно это позволяет повторному запуску той же команды продолжить работу: скрипт повторно использует существующий эксперимент и treatments, пропускает то, что Apple уже получила, и загружает только отсутствующие или изменившиеся файлы.
Наконец, скрипт намеренно не запускает сам тест. Запуск отправляет treatments на ревью, поэтому финальная проверка каждого варианта и кнопка Start остаются в App Store Connect. Пока эксперимент находится в черновиках, он ни к чему вас не обязывает. А поскольку тесты сравниваются с live page, приложение, которое ещё не вышло, создаёт эксперимент только после одобрения launch-версии.
Есть ещё превью видео. Treatments тоже могут содержать видео, но в поисковой выдаче preview воспроизводится на месте первого скриншота, поэтому пользователь видит видео раньше «зацепки». Treatment с видео тестирует само видео не меньше, чем обещание, поэтому это должен быть отдельный раунд поверх уже победившего набора. Создание такого видео разбиралось в предыдущей статье.
-
Разработка4 недели назадДаем ИИ видеть SwiftUI: Xcode Preview MCP на практике — проблемы и надежды
-
Новости4 недели назадВидео и подкасты о мобильной разработке 2026.40
-
Новости3 недели назадВидео и подкасты о мобильной разработке 2026.41
-
Новости2 недели назадВидео и подкасты о мобильной разработке 2026.42
