> ## Documentation Index
> Fetch the complete documentation index at: https://dokumentation.websale.de/llms.txt
> Use this file to discover all available pages before exploring further.

# GeoIP and User Detection

> Detect which device and which country a visitor is coming from, and offer them the right shop.

A visitor holding a smartphone should land in the mobile shop, and a visitor from Austria in the Austrian subshop. Both cases answer the same question: which of the existing shops suits this visitor, and how do they get there without having to search for it themselves?

## The Mobile WebApp

Mobile access to a WEBSALE shop is not an app that has to be installed, but a separate subshop. This results in three properties:

* You are free in design and range of functions, just as with any other subshop.
* The shop runs on every device, regardless of the operating system, and without installation.
* The product range can match that of the main shop or differ from it, as with any subshop.

A classic app would have to be developed separately for each operating system and redistributed with every extension. Here, calling up an address is all it takes.

Whether a mobile subshop will be set up for you is something to clarify with your WEBSALE contact person.

## What is detected

| Detection | Basis | Result |
| - | - | - |
| Device | The browser's UserAgent, optionally also the screen resolution | Offer to switch to the mobile shop |
| Country | The visitor's IP address via GeoIP | Offer to switch to the shop for that country |

Both can be used individually or together. Device detection is automatically available with a mobile subshop and does not require separate activation.

> [!WARNING]
>
> Under the Geoblocking Regulation, automatic redirection based solely on the country of origin is not permitted. Discuss with your legal advisor whether and under which conditions a country-dependent redirect may be set up in your case. A legitimate reason may be, for example, an advertising or sales ban for certain products, or fixed book prices.

> [!NOTE]
>
> Part of the technology described here works with cookies so that the visitor's decision does not have to be requested again on every visit. Cookies that are strictly necessary for operation are permitted without consent; nevertheless, coordinate their use with your data protection officer.

> [!NOTE]
>
> All examples on this page use jQuery. Make sure it is included on the affected pages.

## Including the libraries

Both types of detection require the same two files. They belong in the `<head>` section of all pages on which detection should take place.

```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
<head>
   ...
   <script type="text/javascript" src="/$WS/ws_sysdata/js/ws-system-1.8.3.js"></script>
   <script type="text/javascript" src="/$WS/ws_sysdata/js/ws-user_detection-1.5.0.min.js"></script>
   ...
</head>
```

Materials: WEBSALE JavaScript library

Reference: WS-FirstCall

## Detecting the device

### The basic framework

The following script also belongs in the `<head>` section. It defines what is checked and where the visitor should be redirected.

```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
<script type="text/javascript">
$(document).ready(function(){

   ws_mobile_detection_type = "useragents";
   ws_mobile_domain         = "ihr-mobile-shop.de";
   ws_mobile_subshopid      = "IHRE-SUBSHOP-ID";
   ws_mobile_question       = "Es gibt eine für mobile Geräte optimierte Version des Shops. Möchten Sie diese nutzen?";
   ws_mobile_cookie         = "2 days";

   ws_mobile_detection();

});
</script>
```

| Variable | Type | Required | Meaning |
| - | - | - | - |
| `ws_mobile_domain` | String | yes | Domain to redirect to |
| `ws_mobile_subshopid` | String | yes | Subshop to redirect to |
| `ws_mobile_question` | String | yes | Text of the prompt asking whether to switch |
| `ws_mobile_detection_type` | String | no | `useragents` checks only the UserAgent (default), `resolution` decides based on the screen resolution |
| `ws_mobile_cookie` | String | no | Validity of the cookie, for example `2 days`, `6 hours` or `30 minutes` |
| `ws_mobile_agent_list` | Object | no | List of UserAgents with the respective action |
| `ws_mobile_resolution_list` | Object | no | List of resolutions with the respective action |
| `ws_mobile_replace_list` | Array | no | Strings that are replaced in the address before redirecting |

> [!NOTE]
>
> The prompt from `ws_mobile_question` only appears on devices that can also display the standard shop. Where this is not the case, the switch happens without a prompt.

### Which device triggers what

Each UserAgent and each resolution is assigned one of three actions:

| Action | Behavior |
| - | - |
| `ws_mobile_auto` | Redirect without prompt |
| `ws_mobile_ask` | Redirect after prompt |
| `ws_mobile_no` | No prompt and no redirect |

There are two ways to make the assignment, and the difference between them determines what happens with unknown devices:

| Way | Notation | Unknown UserAgents |
| - | - | - |
| Extend the standard list | `ws_mobile_agent_list["ipad"] = ws_mobile_no;` | are handled according to the WEBSALE standard list |
| Set your own list | `ws_mobile_agent_list = { "android": ws_mobile_auto };` | trigger nothing |

**Extend the standard list.** Each entry overrides exactly the entry of the same name in the standard list; everything else remains in place.

```js theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
ws_mobile_agent_list["ipad"]   = ws_mobile_no;
ws_mobile_agent_list["iphone"] = ws_mobile_no;
```

**Set your own list.** Here, only what you list applies.

```js theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
ws_mobile_agent_list = {
   "android" : ws_mobile_auto,
   "iphone"  : ws_mobile_ask,
   "symbian" : ws_mobile_no
};
```

> [!WARNING]
>
> With your own list, the WEBSALE standard list no longer applies. Every device you do not list sees the standard shop, even if it is a smartphone. If you only want to treat individual devices differently, use the first way.

### Deciding by screen resolution

If `ws_mobile_detection_type` is set to `resolution`, the resolution decides on the redirect. The UserAgent list then only serves to detect a mobile device in the first place; its actions are no longer evaluated.

In the following example, the visitor is prompted from 800 pixels in height or width, no switch happens at all from 1000 pixels, and everything below is redirected without a prompt.

```js theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
ws_mobile_detection_type = "resolution";
ws_mobile_resolution_list = {
   "800"     : ws_mobile_ask,
   "1000"    : ws_mobile_no,
   "default" : ws_mobile_auto
};
```

### Replacing parts of the address

When redirecting, the shop swaps the domain and subshop ID. If more of the address needs to change, for example because the mobile shop names a template differently, list the replacements.

```js theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
ws_mobile_replace_list = [
   { from: "tpl_meintemplate.htm", to: "tpl_meinanderestemplate.htm" },
   { from: "&meinparameter=wert",  to: "" }
];
```

An empty value for `to` removes the string entirely.

### Asking on every visit

Normally, the question is only asked the first time the shop is called up. It can also be asked on every subsequent visit, as long as the visitor has not explicitly switched to the desktop version.

```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
<script type="text/javascript">
$(document).ready(function(){

   ws_mobile_detection_type = "useragents";
   ws_mobile_domain         = "ihr-mobile-shop.de";
   ws_mobile_subshopid      = "IHRE-SUBSHOP-ID";
   ws_mobile_question       = "Es gibt eine für mobile Geräte optimierte Version des Shops. Möchten Sie diese nutzen?";
   ws_redirect_subshopid    = "~WS-SubShopID~";
   ws_session_id            = "~WS-SID~";
   {WS-OTP1(stay)}ws_mobile_stay = true;{/WS-OTP1(stay)}

   ws_mobile_detection();

});
</script>
```

So that the visitor can deliberately stay in the desktop version, append the parameter from the `WS-OTP1` bracket to the corresponding link:

```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
<a href="https://www.ihr-shop.de/?websale8=ihr-shop.01-AA&otp1=stay">Zur Desktop-Ansicht</a>
```

### Switching between the versions

Regardless of detection, visitors should be able to switch themselves at any time. This requires one link for each version and a script that remembers the decision.

![Mobile desktop](https://mintcdn.com/websaleag-44ee7ea6/-VOorhOnZ4aGhsis/images/mobil-dektop.jpg?fit=max\&auto=format\&n=-VOorhOnZ4aGhsis\&q=85\&s=ae4bd3f84c97752e2057455067dec740)

In the mobile version:

```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
<div id="WK-MobileToWebLink">
   <a href="https://www.ihr-shop.de/">Zur Desktop-Ansicht wechseln</a>
</div>
```

In the desktop version:

```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
<div class="footer_switch_to_mobil">
   <a href="https://m.ihr-shop.de/">Zur mobilen Ansicht wechseln</a>
</div>
```

The following script belongs directly after the detection script. On click, it writes a cookie that records the visitor's decision.

```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
<script type="text/javascript">
$(document).ready(function(){

   function setCookie(cname, cvalue) {
      var expire;
      var expireDate = new Date();
      if (ws_mobile_cookie) {
         var index = ws_mobile_cookie.indexOf(" ");
         var countnumber = ws_mobile_cookie.slice(0, index);
         var duration = ws_mobile_cookie.slice(index + 1);
         var intCountNumber = parseInt(countnumber);
         switch (duration) {
            case "days":
               expire = expireDate.getTime() + (intCountNumber * 24 * 60 * 60 * 1000);
               break;
            case "hours":
               expire = expireDate.getTime() + (intCountNumber * 60 * 60 * 1000);
               break;
            case "minutes":
               expire = expireDate.getTime() + (intCountNumber * 60 * 1000);
               break;
            default:
               console.log("Wert der Variablen ws_mobile_cookie prüfen");
         }
      }
      else {
         expire = expireDate.getTime() + 86400000;
      }
      expireDate.setTime(expire);
      document.cookie = cname + "=" + cvalue + "; expires=" + expireDate.toGMTString();
   }

   var referrer = document.referrer;
   var output = referrer.slice(0, referrer.lastIndexOf("/"));

   if (output == ws_mobile_domain) {
      document.cookie = "ws_mobile_stay=MCURRENT;expires=Thu, 01 Jan 1970 00:00:01 GMT";
      setCookie("ws_stay", "CURRENT");
   }

   $('.footer_switch_to_mobil').on('click', function(){
      document.cookie = "ws_stay=CURRENT;expires=Thu, 01 Jan 1970 00:00:01 GMT";
      setCookie("ws_mobile_stay", "MCURRENT");
   });

});
</script>
```

> [!WARNING]
>
> Adapt the ID and the class in the script to your own names. The example only evaluates the class `footer_switch_to_mobil`, that is, the path from the desktop to the mobile version. It recognizes the reverse path solely by the fact that the visitor comes from the mobile domain. Test both directions before putting this into production.

## Detecting the country

With country detection, the shop determines the country of origin from the IP address and offers the visitor the matching shop in a layer above the page.

### The script

```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
<script type="text/javascript">

   var ws_country_user_country = "~WS-GeoIPCountryCode~";
   var ws_redirect_cookie_age  = 30;
   var ws_redirect_shopid      = "~WS-ShopID~";
   var ws_redirect_subshopid   = "~WS-SubShopID~";

   var ws_country_shop_list = new Array(
      {  country : "gbr",
         domain  : "www.testshop.com",
         device  : ws_redirect_all,
         subshop : "english" },
      {  country : "deu,aut,che,DEFAULT",
         domain  : "www.testshop.de",
         device  : ws_redirect_all,
         subshop : "deutsch" }
   );

   var ws_redirect_open_layer = function(){
      $("#redirect_layer").show();
   };
   var ws_redirect_close_layer = $("#redirect_layer").remove;

   $(document).ready(function(){
      ws_country_detection();
   });

</script>
```

| Variable | Type | Meaning |
| - | - | - |
| `ws_country_user_country` | String | The visitor's country code, supplied by the tag `WS-GeoIPCountryCode` |
| `ws_country_shop_country` | String | Country code of the current subshop |
| `ws_redirect_cookie_age` | Number | Validity of the cookie in days |
| `ws_redirect_shopid` | String | Current shop ID, supplied by the tag `WS-ShopID` |
| `ws_redirect_subshopid` | String | Current subshop ID, supplied by the tag `WS-SubShopID` |
| `ws_country_shop_list` | Array | The country list, see below |
| `ws_redirect_open_layer` | Function | Displays the selection layer |
| `ws_redirect_close_layer` | Function | Closes the selection layer |

> [!NOTE]
>
> If `ws_redirect_cookie_age` is set, the visitor can save their selection via a checkbox in the layer. The layer then no longer appears for the specified period, and the visitor is taken directly to their shop.

> [!NOTE]
>
> If the function in `ws_redirect_open_layer` itself returns a function, `ws_redirect_close_layer` is overwritten with it. You can therefore define the closing in the same function in which you describe the opening.

### The country list

Each entry in the list assigns a shop to one or more countries.

![Image](https://mintcdn.com/websaleag-44ee7ea6/ZpqrUDlxS94uTw6k/images/bild.jpg?fit=max\&auto=format\&n=ZpqrUDlxS94uTw6k\&q=85\&s=8dda12c0bd3dc04c7b65469bccc5b206)

| Setting | Meaning |
| - | - |
| `country` | Comma-separated list of three-letter country codes, in lowercase. `DEFAULT` applies to all countries that are not listed |
| `domain` | Domain to redirect to |
| `subshop` | Subshop to redirect to |
| `device` | Which devices the entry applies to: `ws_redirect_mobile`, `ws_redirect_std` or `ws_redirect_all` |

> [!WARNING]
>
> Country codes must be written in lowercase, whereas `DEFAULT` must always be in uppercase. Mixed spelling causes the entry not to take effect.

Another country is added as an additional entry:

```js theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
{  country : "irl",
   domain  : "www.testshop.ie",
   device  : ws_redirect_all,
   subshop : "irish" }
```

### The selection layer

You design the visible part yourself. The IDs, classes and field names in the following framework must not be removed or renamed, as the script uses them to find the elements.

```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
<div id="redirect_layer">

   <div onclick="ws_redirect_close_layer();">schließen</div>

   <div class="ws_redirect_country_text ws_country_text_GBR">
      Welcome! You are in our English online shop.
      Would you like to switch to another one?
   </div>

   <div class="ws_redirect_country_text ws_country_text_DEU ws_country_text_AUT ws_country_text_CHE ws_country_text_DEFAULT">
      Herzlich willkommen! Sie sind im deutschen Onlineshop.
      Möchten Sie Ihre Bestellung lieber über einen unserer anderen Shops abgeben?
   </div>

   <div class="geoip_choose">
      <div id="ws_country_selection">
         <input name="ws_redirect_location" value="current" checked="checked" type="radio"> Auf www.testshop.de bleiben<br>
         <input name="ws_redirect_location" value="redirect" type="radio">
         <select name="ws_redirect_target_select">
            <option value="gbr">www.testshop.com</option>
            <option value="deu">www.testshop.de</option>
         </select>
      </div>
   </div>

   <div id="ws_mobile_section">
      Shop-Version auswählen:<br>
      <input type="radio" name="ws_redirect_version" value="mobile" checked="checked"> Mobile
      <input type="radio" name="ws_redirect_version" value="standard"> Standard
   </div>

   <div id="ws_redirect_cookie_section">
      <input name="ws_redirect_cookie" value="set" type="checkbox">
      Auswahl für zukünftige Besuche speichern
   </div>

   <p>
      <input value="Zum gewählten Shop wechseln" name="ws_redirect_check" type="button">
   </p>

</div>
```

| ID or name | Purpose |
| - | - |
| `#redirect_layer` | Encloses the layer; used to show and hide it |
| `.ws_redirect_country_text` | Marks a country-dependent text. On page load, all areas marked this way are hidden |
| `.ws_country_text_<LÄNDERCODE>` | The area displayed for this country |
| `.ws_country_text_DEFAULT` | The area for all countries without their own text |
| `#ws_country_selection` | Encloses the shop selection |
| `ws_redirect_location` | Name of the "stay" and "switch" radio buttons |
| `ws_redirect_target_select` | Name of the shop selection list |
| `#ws_mobile_section` | Encloses the choice between the mobile and the regular version |
| `ws_redirect_version` | Name of these radio buttons |
| `#ws_redirect_cookie_section` | Encloses the checkbox for saving the selection |
| `ws_redirect_cookie` | Name of this checkbox |
| `ws_redirect_check` | Name of the button that triggers the switch |

> [!NOTE]
>
> Unlike the country codes in the country list, the country codes in the class names are in uppercase, for example `ws_country_text_DEU`.

### Testing

Use the GeoIP test mode to check whether the layer appears correctly, without having to change country.

Guide: Switching the shop's test modes on and off

## Evaluating device and country together

Both checks can be combined. To do this, the same country gets two entries that differ in `device` and in the domain.

```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
<script type="text/javascript">

   var ws_country_user_country = "~WS-GeoIPCountryCode~";
   var ws_country_shop_country = "deu";
   var ws_redirect_cookie_age  = 30;
   var ws_redirect_shopid      = "~WS-ShopID~";
   var ws_redirect_subshopid   = "~WS-SubShopID~";

   var ws_country_shop_list = new Array(
      {  country : "gbr,DEFAULT",
         domain  : "www.testshop.com",
         device  : ws_redirect_all,
         subshop : "english" },
      {  country : "deu,aut,che",
         domain  : "www.testshop.de",
         device  : ws_redirect_std,
         subshop : "deutsch" },
      {  country : "deu,aut,che",
         domain  : "mobile.testshop.de",
         device  : ws_redirect_mobile,
         subshop : "deutsch" }
   );

   var ws_redirect_open_layer = function(){
      $("#redirect_layer").show();
   };
   var ws_redirect_close_layer = $("#redirect_layer").remove;

   ws_redirect_detection();

</script>
```

> [!NOTE]
>
> Here, `ws_redirect_detection()` is called, not `ws_country_detection()`. Only this function evaluates country and device together.

## The standard list of UserAgents

This list applies as long as you do not set `ws_mobile_agent_list` entirely yourself.

```js theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
var ws_mobile_agent_list = {

   // Apple
   "iphone"          : ws_mobile_auto,
   "ipad"            : ws_mobile_ask,
   "ipod"            : ws_mobile_auto,

   // Google und Android
   "android.*mobile" : ws_mobile_auto,   // Smartphones
   "android"         : ws_mobile_ask,    // Tablets
   "googletv"        : ws_mobile_no,
   "xoom"            : ws_mobile_ask,

   // Symbian
   "symbian"         : ws_mobile_auto,
   "series60"        : ws_mobile_auto,
   "series70"        : ws_mobile_auto,
   "series80"        : ws_mobile_auto,
   "series90"        : ws_mobile_auto,

   // Microsoft und Windows
   "windows phone"   : ws_mobile_auto,
   "windows ce"      : ws_mobile_auto,
   "iemobile"        : ws_mobile_auto,
   "nuvifone"        : ws_mobile_auto,

   // Blackberry
   "blackberry"      : ws_mobile_auto,
   "vnd.rim"         : ws_mobile_auto,   // Emulator
   "playbook"        : ws_mobile_ask,    // Tablet

   // Palm
   "palm"            : ws_mobile_auto,
   "webos"           : ws_mobile_ask,
   "blazer"          : ws_mobile_auto,

   // Weitere Browser
   "netfront"        : ws_mobile_ask,
   "up.browser"      : ws_mobile_ask,

   // Hersteller
   "sonyericsson"    : ws_mobile_ask,
   "ericsson"        : ws_mobile_ask,
   "sony"            : ws_mobile_ask,
   "sec-sgh"         : ws_mobile_ask,
   "htc"             : ws_mobile_ask,
   "lg"              : ws_mobile_ask,
   "phonifer"        : ws_mobile_ask,
   "samsung"         : ws_mobile_ask,
   "sharp"           : ws_mobile_ask,
   "sie-"            : ws_mobile_ask,

   // Netzbetreiber
   "docomo"          : ws_mobile_ask,
   "kddi"            : ws_mobile_ask,
   "vodafone"        : ws_mobile_ask

};
```

> [!NOTE]
>
> The entries are checked against the UserAgent and may contain simple patterns, see `android.*mobile`. Some of the listed systems are no longer relevant today. This does no harm to the list; it simply no longer takes effect for these devices.

## Related topics

* Guide: Sitemaps, robots.txt and mobile subshops
* Guide: Switching the shop's test modes on and off
* Guide: JavaScript and jQuery


## Related topics

- [WEBSALE JavaScript library](https://dokumentation.websale.de/en/v8s/materialien/websale-javascript-bibliothek.md)
- [Customer, login, and customer account](https://dokumentation.websale.de/en/v8s/referenz/konfigurationen/shopkonfiguration-shop-config/kunde-anmeldung-und-kundenkonto.md)
- [Enabling and disabling shop test modes](https://dokumentation.websale.de/en/v8s/domains/testmodi-des-shops-ein-ausschalten.md)
- [Shop, page and technology](https://dokumentation.websale.de/en/v8s/referenz/tags/ws/shop-seite-und-technik.md)
- [Currencies](https://dokumentation.websale.de/en/v8s/preise/waehrungen.md)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.