Как первые пользователи нашли два бага, которых мы сами не увидели — и что мы из этого вынесли
Зиберов
В первые две недели после запуска платных тарифов в Subsly мы получили два неожиданных подарка от пользователей — два критических бага, которые наша команда упустила. Один скрывал реальные расходы в дашборде в 10 раз меньше реальности. Второй создавал 15 несуществующих подписок на 298 000 ₽ из служебных строк банковской выписки. Оба бага жили в коде месяцами и могли убить активацию десятков пользователей.
Делимся опытом — что произошло, как чинили, и почему ранние пользователи оказались дороже любого QA.
Контекст: что мы делаем
Subsly — сервис аудита SaaS-расходов для бизнеса. Загружаете банковскую выписку → видите все подписки компании, дубли, переплаты. Запустили платные тарифы в начале мая, сейчас активно тестируем гипотезы на ранних пользователях. Объявления крутим в РСЯ (Яндекс.Директ), посевы в Telegram-каналах.
Кейс 1. Валюты, спрятанные в RUB
Один из первых платных пользователей зарегистрировался, добавил 7 подписок через ручной импорт и написал нам: «продукт хороший, но в дашборде расходы как-то меньше реальных».
Открыли его кабинет. У него Anthropic Claude добавлен как 108,90 ₽. Anthropic тарифицируется в долларах — 108,90 это $108.90, что по курсу ЦБ ≈ 10 000 ₽. Дашборд показывал в 100 раз меньше реального расхода на этот сервис. Аналогично — Hostinger ($19.29 → 19,29 ₽), Hugging Face ($9.13 → 9,13 ₽).
Общий показатель «Расходы/мес» на дашборде: 1 411 ₽. Реальная сумма с правильной конверсией: 14 409 ₽.
В чём была дыра
На странице добавления подписки есть поле «Стоимость» и рядом селектор валюты с тремя опциями: RUB / USD / EUR. По умолчанию стоит RUB. Пользователь вводит «108.90», селектор остаётся на RUB, в БД сохраняется cost=108.90, currency=RUB.
На бэке функция расчёта общих расходов просто суммировала sub.cost по всем подпискам — без учёта валюты. То есть $108.90 + 100 ₽ + 7900 ₽ складывались как 8108.90. Бессмыслица, но проходила компиляцию.
Это типовая ошибка для финансовых продуктов — мы делали аналитику исходя из предположения «все в рублях», потому что 80% наших пользователей действительно в рублях.
Что починили (1 рабочий день)
Четыре фикса:
- Конвертация валют на бэке. Подключили API ЦБ РФ (cbr-xml-daily.ru — публичное зеркало, отдаёт JSON, работает без VPN). Кешируем курсы на 24 часа — Я.Метрика обновляется раз в день, чаще не нужно. Все агрегации (15+ мест в коде) теперь идут через единую функцию, которая знает про валюту.
- Tooltip с конверсией в таблице. Под валютной ценой каждой подписки появилась мелкая серая строка «≈ 9 354 ₽ по курсу ЦБ 85.90». Пользователь видит реальный рублёвый эквивалент сразу, без калькулятора.
- Подсказка на дашборде. Под общей суммой «Расходы/мес» теперь добавляется «из них €10 + $138 (12 935 ₽ по курсу ЦБ)» — если у пользователя есть подписки в валюте. Объясняет откуда цифра.
- Автовалюта по сервису — это самое важное. Добавили в каталог сервисов колонку «валюта по умолчанию». Для 73 западных SaaS проставили USD: Anthropic, OpenAI, GitHub, Cursor, Notion, Slack, Figma, Linear, AWS, Cloudflare, Stripe, HubSpot и др. Когда пользователь выбирает Anthropic из автокомплита — валюта автоматически переключается на USD. Никаких больше «108 ₽ за Claude».
Дашборд этого пользователя стал показывать 14 409 ₽ вместо 1 411 ₽. Мы написали ему отдельно, объяснили что произошло, и подарили 3 месяца тарифа Starter (1 290 ₽/мес × 3 = 3 870 ₽) бесплатно. За критический баг это самое меньшее что можно сделать.
Кейс 2. 15 фальш-подписок на 298 000 ₽
Через день после первой истории — другой пользователь. Пришёл с рекламы в Яндекс.Директе, кликнул на наше объявление про аудит SaaS-расходов, зарегистрировался, загрузил выписку из банка. И получил картину которая в реальности никак не могла быть его расходами на SaaS:
10:48 Прочие операции + 26 232 ₽/мес
22:30 Перевод СБП 25 418 ₽/мес
12:52 Оплата по QR–коду СБП 18 233 ₽/мес
12:56 Оплата по QR–коду СБП 18 033 ₽/мес
13:03 Оплата по QR–коду СБП 17 733 ₽/мес…
… и ещё 10 таких же
15 «подписок» на сумму 298 474 ₽ в месяц. Все 15 — мусор. Это не подписки на сервисы, а служебные строки выписки: переводы по СБП другим людям, оплаты по QR-коду в магазинах, разовые переводы между счетами. Парсер ошибочно сгруппировал их и сделал из них recurring-подписки.
Что мы себе представляли
Стандартный путь пользователя который мы продаём в рекламе: заходишь → загружаешь выписку → видишь свои реальные подписки → понимаешь сколько тратишь и где переплачиваешь → конвертация в платящего.
Что увидел этот человек: зашёл с рекламы → загрузил выписку → получил 15 непонятных «подписок» на 298 000 ₽ → закрыл вкладку. Полная потеря лида на финальном шаге воронки. Деньги за клик заплатили, а пользователь ушёл с впечатлением что наш продукт не понимает банковские данные.
Почему так получилось
Когда мы делали парсер, исходили из того что в выписке есть названия мерчантов: «AmoCRM», «Yandex.Cloud», «Adobe». Логика группировки простая — если одно и то же название встречается несколько раз с одинаковой суммой, это подписка. Работает для 80% случаев.
Но банки иногда выгружают выписки в которых имя мерчанта не заполнено, а вместо него — описание операции вроде «12:52 Оплата по QR-коду СБП». И таких строк может быть много с разными суммами. Парсер видел повторяющийся текст, считал что это бренд-сервис, группировал — получались фальш-подписки.
У нас в коде был список того что точно НЕ подписки — супермаркеты, рестораны, заправки, такси. Но «СБП», «QR-код», «перевод между своими счетами» в этот список не входило. Просто потому что мы сами никогда такие выписки руками не разбирали — у нас в тестах были корпоративные выписки с настоящими мерчантами.
Что починили
За полдня:
- Добавили в список «не подписки» все типовые описания операций: переводы СБП, оплаты по QR-коду, прочие операции, пополнения счёта, снятия наличных, комиссии, возвраты — около 20 паттернов
- Научили парсер игнорировать строки которые начинаются с временной метки (например «10:48 Прочие операции») — это явный маркер служебной строки выписки
- Удалили 15 фальш-подписок из аккаунта этого пользователя вручную через админку — чтобы при следующем заходе он не видел мусор
- Заодно добавили автозаполнение даты следующего списания: если парсер распознал подписку, дата прогнозируется из последней транзакции + цикла оплаты. Раньше это поле оставалось пустым, теперь сразу работает напоминание «списание через 7 дней»
Написали пользователю — объяснили что произошло, что почистили дашборд от мусора, предложили перезалить выписку. Подарили 3 месяца Starter бесплатно. История получилась хорошим уроком, а человек получил рабочий продукт за наш счёт.
Что мы из этого вынесли
1. Ранние пользователи находят то, что не найдёт QA
Оба бага существовали в коде месяцами. У нас были unit-тесты на аналитику, на парсер, на форму подписки — ни один не падал. Потому что мы тестировали свои сценарии, которые сами придумали. А пользователь заходит с реальной выпиской из своего реального банка, со своей коллекцией реальных подписок — и сразу же ломает то, что нам в голову не пришло проверить.
Никакая внутренняя QA-команда меньше чем за полгода работы с продуктом не даст той широты сценариев, которые дают первые пользователи.
2. Скорость ответа важнее красоты решения
Каждый из двух багов закрыли за один рабочий день. Не самым идеальным способом — где-то хардкодом, где-то простой регулярки вместо нормального ML-классификатора. «Правильное» решение заняло бы неделю на каждый. Но через неделю пользователь уже забыл бы про нас.
Сейчас они увидели что мы реагируем за день, получили апгрейд тарифа, остались. Через 3 месяца, если активно используют — конвертируются в платящих. Если нет — мы хотя бы заработали репутацию, что в стартапе на старте важнее перфекционизма.
3. Подарок за фидбек окупается
3 месяца Starter стоят 3 870 ₽ на каждого. Если эти пользователи останутся платящими хотя бы 6 месяцев на тарифе Solo (2 940 ₽ выручки) — мы вернём подарок чистой маржой. Плюс с большей вероятностью расскажут о Subsly коллегам и в своих чатах — это виральный канал, который не купишь рекламой.
Для сравнения: один клик в РСЯ по теме «аудит SaaS» стоит 60-120 ₽, регистрация — около 1 400 ₽. Подарок в 3 870 ₽ эквивалентен 2-3 регистрациям с рекламы. Если хотя бы 1 из 3 вернётся виральным реферралом — сделка положительная.
4. UX-дефолты — главная дыра
Оба бага в сути своей были про дефолтные значения. Валюта по умолчанию RUB — а человек добавляет долларовый сервис. Парсер по умолчанию считает всё подпиской — а в выписке половина строк не подписки.
Дефолт всегда работает против edge-кейсов. Решение в обоих случаях оказалось одно и то же — заменить «глупый дефолт» на «умный»:
- Валюта = USD для известных западных сервисов (Anthropic, OpenAI, GitHub и 70+ других в каталоге). Юзер выбирает Anthropic — валюта сама становится USD.
- Парсер выписки = расширенный блэклист служебных операций. Не считаем «Оплата по QR-коду СБП» подпиской ни при каких условиях.
Если у вас в продукте есть форма с дефолтными значениями — вероятно у вас есть похожие баги. Они не падают в тестах, не показываются в метриках поверхности, но молча убивают конверсию для части пользователей.
Что дальше
В конце мая опубликуем open metrics за полный месяц: CAC по каналам (Яндекс.Директ, Telegram-посевы, органика), конверсии в активацию и платящего, удержание. По-честному — что зашло, что нет, без приукрашивания.
Параллельно работаем над онбордингом — гипотеза что 4 фичи которые выкатили в прошлом месяце (демо-режим, туториал по выгрузке выписки, шаринг отчёта, social proof) должны поднять конверсию из посетителя в активного пользователя в 2-3 раза. Цифры будут в майских метриках.
Если у вас есть свой опыт с ранними пользователями и неожиданными багами — расскажите в комментариях, всегда интересно сравнить.
— Команда Subsly
Subsly — аудит SaaS-подписок за 2 минуты без регистрации
Subsly inside — постоянные апдейты по цифрам, продукту и факапам