Давайте зайдём на сайт Министерства иностранных дел.

На странице такой серьёзной организации размещены значки некоторых организаций, признанных в России экстремистскими. Чтобы не травмировать вашу психику, я применил к ним эффект стекла (а заодно и к некоторым другим, потому что не знаю, в каком году вы открыли эту статью).
Размещение некоторых значков считается публичной демонстрацией запрещенной экстремистской символики, а значит может примениться административная ответственность по ст. 20.3 КоАП РФ. А если может, значит уже применяется.
И вот как быть серьёзной организации, которая работает не только для России? Помимо нашей страны есть и другие, в которых тоже есть интернет. И там свои варианты дозволенного.
Самый известный пример — GDPR (General Data Protection Regulation), регламент Евросоюза о защите персональных данных. Если ваш сайт посещает пользователь из ЕС, вы обязаны спросить у него разрешение на сбор cookies и объяснить, зачем они нужны. Именно поэтому при первом заходе на европейские сайты вас встречает баннер «Мы используем cookies» — это не прихоть дизайнера, а юридическое требование. Чтобы показывать этот баннер только нужным людям (и не раздражать им всех остальных), сайты и используют геотаргетинг: определяют страну посетителя по IP-адресу и уже тогда решают, что ему показать.
Та же задача встала передо мной, когда я делал промо-страницу для своего приложения ScreenLines. Приложение доступно в App Store, а там пользователи со всего мира. На странице я предлагал промокод на премиум-подписку в обмен на видео: нужно было снять, как клеишь защитное стекло на телефон, и выложить в соцсети. Но в какие именно? ВКонтакте понятен российской аудитории и бесполезен для иностранца. Instagram (принадлежит компании Meta, признанной экстремистской организацией и запрещённой в РФ) и X (Twitter) — наоборот, привычны на Западе, но в России заблокированы. Вот тут и пригодился геотаргетинг. Для посетителей из России — одно предложение, для всех остальных — другое.
Первый подход: цепочка сторонних сервисов
Есть несколько зарубежных сервисов, которые определяют страну пользователя по IP-адресу провайдера. Проблема в том, что они все с нюансами: одни блокируются расширениями для блокировки рекламы, другие работают с ограничениями на количество запросов.
- ip-api.com — попадает в чёрные списки блокировщиков рекламы, лимит 45 запросов в минуту с одного IP
- ipinfo.io — лимит 1000 запросов в сутки на бесплатном тарифе (общий на всех с одного IP)
- ipapi.co — аналогично в чёрных списках, бесплатный тариф явно запрещён для коммерческого использования
- ipgeolocation.io — требует регистрации и API-ключа
Чтобы не зависеть от одного сервиса, я выстроил цепочку: если первый не ответил — пробуем второй, если и второй не сработал — следующий. Если никто не ответил — на всякий случай показываем российский вариант. Логика разумная, но у неё есть цена: каждый запрос ждёт ответа и только после этого передаёт эстафету следующему. В итоге страница могла подвисать на несколько секунд, пока вся цепочка не отработает.
Но главная проблема обнаружилась позже. В России на мобильном интернете действуют белые списки: без ограничений открываются только одобренные ресурсы, особенно хорошо работает виртуальный хостинг — провайдеры этот вопрос решают. А вот обращение к зарубежному геосервису, например ipinfo.io, попадает под шейпинг — это когда доступ не заблокирован, но скорость намеренно урезана до минимума. Нам нужно получить буквально несколько байт с геоданными, но из-за шейпинга даже этот крошечный запрос может тянуться секунды.
Второй подход: свой сервис
Я решил сделать иначе. Если вы когда-то настраивали хостинг, то могли видеть галочку «доступ к сайту только из РФ». На мой взгляд, абсурднейший флажок — особенно сейчас, когда люди запросто «оказываются в другой стране», как только просыпаются. Но именно эта механика мне и нужна.
Идея: разместить на своём хостинге специальный адрес /geo/ru и закрыть к нему доступ для российских IP. Дальше всё просто: скрипт на странице делает один HEAD-запрос на этот адрес — он не скачивает никакого содержимого, только получает код ответа сервера. Если пришёл 403 (или любая другая ошибка) — значит, доступ закрыт, пользователь в России. Если 200 — пользователь за рубежом.
CDN — российский, запрос к нему не шейпится, ответ приходит мгновенно. Никаких цепочек, никаких зависимостей от сторонних сервисов.
Так появился ГдеЯ — инструмент с открытым исходным кодом, который доступен на GitHub. Можно использовать мой сервис или развернуть собственный.
Как этим пользоваться
Вы задаёте два варианта содержимого — один увидят пользователи из России, другой — все остальные. Текст, ссылка, кнопка, целый блок — что угодно.
Сервис генерирует фрагмент кода, который вы вставляете в нужное место страницы. Оба варианта встроены в страницу в закодированном виде — в исходном коде их не прочитать.
При загрузке страницы скрипт определяет местоположение пользователя по одному HEAD-запросу. За пределами России — показывается международный вариант. В остальных случаях (ошибка, таймаут, Россия) — российский.
Вот как выглядит сниппет для строчного элемента — например, ссылки или кнопки:
<span
data-gdeya-ru="t9G08LCjEOKFt9C1zEzjsuKIR7Taqd8S4I/m37TfqOISUUBCAgkHFg1dRF1A"
data-gdeya-intl="t9ZDFwNBQAkKBkQNCwRUDRBeExAVClsdH1tYFBAEHhNTXRxVCAlKGBNGVV9UCAgKDQ5EEgzm37TYqODjsuKGt9e0+bGC4I7m0lhKGF8=">
</span>
А вот пункт списка со ссылками на соцсети. Обратите внимание: data-gdeya-ru пустой — для российских пользователей этот элемент просто не появится:
<li
data-gdeya-ru=""
data-gdeya-intl="R0RFWUESEBIKBkQGFQBBQw8UDgcKF0MS...">
</li>
Содержимое закодировано — в исходном коде страницы его не прочитать. Это важно, если вы, например, прячете иконки заблокированных в России соцсетей: они не присутствуют в HTML явно, а раскодируются и подставляются скриптом уже в браузере.
Кстати, МИД тоже мог бы воспользоваться ГдеЯ. Показывать российским пользователям одно, иностранным — другое. Но, видимо, пока не в курсе.