WordPress · 7 мин чтения

Промокоды в интернет-магазине: лимиты и защита от подбора

Промокоды в интернет-магазине - самый быстрый способ поднять конверсию на короткой акции, но именно на них чаще всего теряют деньги: код без лимита разлетается по агрегаторам скидок, а простой числовой код перебирают скриптом за полчаса. На проектах на WooCommerce и Tilda я настраивал промокоды и для разовых акций, и для постоянных программ лояльности - ниже про правила, лимиты и защиту от подбора, которые закладываю сразу, а не после того, как акция уже слита в паблик со скидками.

Зачем промокоды в интернет-магазине и какие типы встречаются

Промокод решает три разные задачи, и от того, какую именно закрывает конкретный код, зависит логика проверки:

  • привлечение новых клиентов - скидка на первый заказ, код раздаётся в рекламе или блогерам;
  • удержание и повторные покупки - персональный код в письме после заказа, часто с ограничением на одно применение;
  • управление остатками - скидка на конкретную категорию или коллекцию, чтобы разгрузить склад к сезону;
  • партнёрские и реферальные программы - именной код, который отслеживает, кто привёл покупателя.

Каждый тип требует своих правил: код для рекламной кампании должен работать без привязки к личности, а персональный код в письме - ровно наоборот, привязываться к email или телефону и сгорать после первого применения. Смешивать логику в одной сущности «промокод» без разделения типов - типичная причина, почему акция потом даёт скидку тем, кому она не предназначалась.

Правила начисления скидки: проценты, сумма, бесплатная доставка

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

Фиксированная сумма скидки требует нижней границы корзины - иначе при заказе на 300 ₽ с промокодом на 500 ₽ магазин уходит в минус. В WooCommerce это настраивается прямо в правилах купона на вкладке ограничений использования, где задаётся минимальная и максимальная сумма заказа для применения кода - переопределять эту логику руками не нужно.

Бесплатная доставка как тип промокода отдельно завязана на расчёт стоимости доставки. В Tilda стоимость по зонам считается встроенным калькулятором СДЭК в настройках корзины, и промокод на бесплатную доставку в таком случае должен обнулять именно эту рассчитанную сумму, а не просто скрывать поле оплаты доставки - иначе на этапе оформления заказа в СДЭК всё равно уйдёт платное отправление.

Бесплатный материал

🎁 Полезный скрипт в подарок

Подпишитесь на Telegram - пришлю готовый скрипт по этой теме.

Без спама. Отписка в 1 клик.

Лимиты использования: по коду, по клиенту и по времени

Лимит - это не одна настройка, а минимум четыре разных ограничения, и они комбинируются друг с другом:

Тип лимита Что ограничивает Типичный сценарий
Общий лимит использований Сколько раз код сработает суммарно по всем покупателям Акция на первые 50 заказов
Лимит на клиента Сколько раз один email или телефон применит код Скидка только на первый заказ
Лимит по времени Период действия кода с автоматическим отключением Промокод на выходные или на 48 часов
Лимит по сумме заказа Минимальная или максимальная сумма корзины Скидка только от 3000 ₽ в корзине

В WooCommerce первые два лимита - штатная функция купонов: поля «Лимит использования купона» и «Лимит использования на одного пользователя» в настройках ограничений, без доработок.

В Tilda есть встроенное ограничение количества использований промокода в настройках корзины - оно закрывает общий лимит по коду. Но это глобальный счётчик: он не умеет считать использования на конкретного покупателя и не привязывается к телефону или email, поэтому код на «один раз для новых клиентов» через него не собрать. Для такого сценария я делал ограничение промокодов в Tilda с привязкой лимита к контакту покупателя поверх штатной корзины.

Защита промокода от подбора и накрутки

Короткий числовой код вроде «1234» или последовательные коды «SALE01», «SALE02» перебираются скриптом за минуты - форма проверки купона обычно не защищена от частых запросов, и если бэкенд просто сверяет строку с таблицей без ограничений, злоумышленник переберёт весь диапазон циклом.

Что закладываю на уровне сервера:

  • длина и алфавит кода - минимум 8 символов из букв и цифр, без предсказуемых последовательностей и без человекочитаемых номеров заказов внутри кода;
  • ограничение частоты запросов к обработчику применения купона - не больше нескольких попыток в минуту с одного IP или сессии;
  • капча или временная блокировка после нескольких неудачных попыток подряд, а не после каждой отдельной попытки - иначе капча мешает обычным покупателям, которые просто ошиблись в коде;
  • логирование неудачных попыток с IP и user-agent, чтобы отличить одного человека, который путает раскладку, от скрипта, перебирающего тысячи вариантов;
  • персональные коды выдаю не строкой в письме, а одноразовым токеном, который сгорает при первом успешном применении независимо от статуса оплаты заказа.

Как проверяю и храню промокоды на практике

Логика проверки и списания промокода - обычная задача для PHP-обработчика и MySQL на том же хостинге, где уже развёрнут магазин: отдельный сервер под это поднимать не нужно. Таблица промокодов с уникальным индексом по коду и счётчиком использований, атомарное обновление в момент применения:

UPDATE promocodes
SET used_count = used_count + 1
WHERE code = 'SALE2026XZ'
  AND used_count < usage_limit
  AND (expires_at IS NULL OR expires_at > NOW());

Если запрос обновил ноль строк - лимит уже исчерпан или срок истёк, и скидка не применяется. Это защищает от гонки, когда два покупателя одновременно оформляют заказ с последним доступным промокодом: без атомарного UPDATE оба обработчика могут прочитать один и тот же остаток лимита и применить скидку дважды.

Финально списывать использование стоит после подтверждения оплаты, а не в момент оформления заказа - иначе брошенные корзины с промокодом в T‑Bank или другом эквайринге съедают лимит акции впустую. Резервирую код на заказ на короткое время и снимаю резерв, если оплата не пришла.

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

Частые ошибки при запуске промокодов

За практику на разных магазинах чаще всего встречаются одни и те же промахи:

  • забыли выставить срок действия - код продолжает работать месяцами после окончания акции, и о нём узнают из чужого блога со скидками;
  • не проверили пересечение со скидками по акции - промокод суммируется с распродажей, и товар уходит по цене ниже себестоимости;
  • не учли часовой пояс при задании даты окончания - код отключается на несколько часов раньше или позже, чем планировали;
  • не протестировали применение купона в мобильной версии корзины - поле ввода промокода спрятано за дополнительным кликом, и конверсия акции падает не из-за условий, а из-за интерфейса;
  • код и остаток лимита видны в ответе фронтенда или в исходном JS - достаточно открыть консоль браузера, чтобы вытащить действующий промокод раньше официального анонса.

Частые вопросы

Сколько стоит внедрить промокоды в интернет-магазин под ключ?

Интернет-магазин с корзиной, промокодами, лимитами и защитой от подбора я делаю от 80 000 ₽. Если промокоды нужно добавить в уже готовый магазин на Tilda как отдельную доработку - это кастомная интеграция от 40 000 ₽, конкретная цена зависит от того, сколько типов лимитов и правил нужно заложить.

Можно ли ограничить промокод одним использованием на человека в Tilda?

Штатное ограничение количества использований в Tilda считает только общий лимит по коду для всех покупателей сразу, без привязки к конкретному человеку. Чтобы код сработал у каждого покупателя не больше одного раза, нужна отдельная привязка лимита к email или телефону поверх стандартной корзины.

Как защитить промокод от перебора без капчи на каждый заказ?

Капчу имеет смысл показывать не сразу, а после нескольких подряд неудачных попыток ввода с одного IP или сессии - тогда обычный покупатель, который один раз ошибся в коде, её не увидит, а скрипт, перебирающий варианты по кругу, упрётся в ограничение. Вместе с ограничением частоты запросов и логированием попыток этого обычно достаточно без капчи на каждую попытку.

Что делать, если промокод уже слили в паблик со скидками?

Быстрее всего отключить код и выпустить новый с более длинным и непредсказуемым значением, а не пытаться заблокировать конкретные IP - код разлетается через скриншоты и репосты, и по IP отследить всех, кто им воспользовался, не получится. На будущее закладываю лимит использований заранее, чтобы даже слитый код не смог принести акции убыток больше расчётного.

Есть задача?

Обсудим в мессенджере

Расскажите, что нужно сделать — отвечу в течение 4 часов в рабочее время. Первая консультация бесплатно.

Продолжая пользование настоящим сайтом Вы выражаете своё согласие на обработку Ваших персональных данных (файлов куки) с использованием Yandex.Metrika.
Понятно