Setting Up Automatic City Detection for 1C-Bitrix Users
Automatic city detection is needed when a site operates across multiple regions: the correct city must appear in the header, current prices and availability must be shown, and the nearest store suggested. In Bitrix, this is solved through built-in geolocation mechanisms or external geodatabases.
Bitrix Built-In Geolocation Module
Bitrix ships with the sale (online shop) module, which includes geolocation. Settings: Shop → Settings → Geolocation.
The module uses a GeoIP database (MaxMind GeoLite2 or paid versions). The database file is connected in the site settings. Country, region, and city are determined from the user's IP address.
Getting the city programmatically:
$ip = \Bitrix\Main\Context::getCurrent()->getRequest()->getRemoteAddress();
// Bitrix built-in detector
$location = \Bitrix\Sale\Location\GeoIp\Manager::getLocationByIp($ip, LANGUAGE_ID);
// $location['CITY_NAME'] — city name
// $location['REGION_NAME'] — region name
// $location['COUNTRY_NAME'] — country name
If only country and city are needed without binding to the sale module:
\Bitrix\Main\Loader::includeModule('sale');
$geo = \Bitrix\Sale\Location\GeoIp\Manager::getInfo($ip, 'en');
Storing the Selected City in the Session
The detected (or manually selected) city is stored in the session:
// Write
$_SESSION['USER_CITY'] = [
'ID' => $cityId,
'NAME' => $cityName,
'CODE' => $cityCode,
];
// Read in the template
$currentCity = $_SESSION['USER_CITY'] ?? null;
For authenticated users — additionally save in the user profile via CUser::Update() with a custom field UF_CITY.
JavaScript Detection via the Browser
If the user has granted location access, a more precise detection is possible via the browser Geolocation API, followed by coordinate-to-city conversion (reverse geocoding):
navigator.geolocation.getCurrentPosition(async (pos) => {
const resp = await fetch('/local/ajax/detect-city.php', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
lat: pos.coords.latitude,
lng: pos.coords.longitude,
}),
});
const data = await resp.json();
if (data.city) showCityConfirmDialog(data.city);
});
For server-side reverse geocoding, use the Yandex Geocoder API or DaData:
// Yandex Geocoder
$url = "https://geocode-maps.yandex.ru/1.x/?apikey={$key}&format=json"
. "&geocode={$lng},{$lat}&kind=locality&results=1&lang=en_US";
$response = json_decode(file_get_contents($url), true);
$city = $response['response']['GeoObjectCollection']['featureMember'][0]
['GeoObject']['name'] ?? null;
City Confirmation by the User
Auto-detection is an assumption, not a fact. Always show a popup banner "Your city is Minsk?" with "Yes, correct" / "Choose another" buttons. Without confirmation, in some scenarios (especially with VPN) the city may be detected incorrectly, and the user will see irrelevant information.
Show the banner on the first visit by checking $_SESSION['CITY_CONFIRMED']. After confirmation or manual selection — set the flag and stop showing the banner.
Linking the City to Catalogue Sections and Prices
If you have a multi-regional site, the city is linked to:
- Bitrix site (multisite) — different domains for different cities
- Iblock sections — prices from properties with regional pricing
-
Price groups
b_catalog_price_type— each city has its own price group
| Stage | Time |
|---|---|
| GeoIP database setup | 1–2 h |
| City detection and storage logic | 3–4 h |
| Browser geolocation + reverse geocoding | 3–5 h |
| City confirmation UI banner | 2–3 h |
| Binding to prices / content | 4–8 h |







