diff --git a/android/AndroidManifest.xml b/android/AndroidManifest.xml
index d18ded385a..1463b1d67d 100644
--- a/android/AndroidManifest.xml
+++ b/android/AndroidManifest.xml
@@ -38,12 +38,6 @@
   //-->
   <uses-permission android:name="android.permission.WAKE_LOCK"/>
   <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
-  <!--
-    Android 13 (API level 33) and higher supports a runtime permission for sending non-exempt (including Foreground
-    Services (FGS)) notifications from an app.
-  //-->
-  <uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
-
 
   <queries>
     <intent>
diff --git a/android/build.gradle b/android/build.gradle
index 53374c7638..9aab4e47f5 100644
--- a/android/build.gradle
+++ b/android/build.gradle
@@ -26,19 +26,19 @@ buildscript {
   ext.googleFirebaseServicesEnabled = project.hasProperty('firebase') ?: googleFirebaseServicesDefault
 
   dependencies {
-    classpath 'com.android.tools.build:gradle:7.4.1'
+    classpath 'com.android.tools.build:gradle:7.3.1'
 
     if (googleMobileServicesEnabled) {
       println("Building with Google Mobile Services")
-      classpath 'com.google.gms:google-services:4.3.15'
+      classpath 'com.google.gms:google-services:4.3.10'
     } else {
       println("Building without Google Services")
     }
 
     if (googleFirebaseServicesEnabled) {
       println("Building with Google Firebase Services")
-      classpath 'com.google.firebase:firebase-crashlytics-gradle:2.9.4'
-      classpath 'com.google.firebase:firebase-appdistribution-gradle:3.2.0'
+      classpath 'com.google.firebase:firebase-crashlytics-gradle:2.8.1'
+      classpath 'com.google.firebase:firebase-appdistribution-gradle:2.2.0'
     } else {
       println("Building without Google Firebase Services")
     }
@@ -75,34 +75,36 @@ dependencies {
   // Google Firebase Services
   if (googleFirebaseServicesEnabled) {
     // Import the BoM for the Firebase platform
-    implementation platform('com.google.firebase:firebase-bom:31.2.1')
+    implementation platform('com.google.firebase:firebase-bom:30.5.0')
     // Add the dependencies for the Crashlytics and Analytics libraries
     // When using the BoM, you don't specify versions in Firebase library dependencies
     implementation 'com.google.firebase:firebase-crashlytics'
     implementation 'com.google.firebase:firebase-crashlytics-ndk'
   }
 
-  // This line is added as a workaround for duplicate classes error caused by some outdated dependency:
-  // > A failure occurred while executing com.android.build.gradle.internal.tasks.CheckDuplicatesRunnable
-  // We don't use Kotlin, but some dependencies are actively using it.
-  implementation(platform('org.jetbrains.kotlin:kotlin-bom:1.8.0'))
-  implementation 'androidx.annotation:annotation:1.6.0-dev01'
-  implementation 'androidx.appcompat:appcompat:1.6.1'
+  implementation 'androidx.annotation:annotation:1.5.0'
+  implementation 'androidx.appcompat:appcompat:1.7.0-alpha01'
   implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
-  implementation 'androidx.fragment:fragment:1.5.5'
+  implementation 'androidx.fragment:fragment:1.5.4'
+  // Lifecycle is added as a workaround for duplicate classes error caused by some outdated dependency:
+  // > A failure occurred while executing com.android.build.gradle.internal.tasks.CheckDuplicatesRunnable
+  //   > Duplicate class androidx.lifecycle.ViewModelLazy found in modules jetified-lifecycle-viewmodel-ktx-2.3.1-runtime (androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.1) and lifecycle-viewmodel-2.5.1-runtime (androidx.lifecycle:lifecycle-viewmodel:2.5.1)
+  //     Duplicate class androidx.lifecycle.ViewTreeViewModelKt found in modules jetified-lifecycle-viewmodel-ktx-2.3.1-runtime (androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.1) and lifecycle-viewmodel-2.5.1-runtime (androidx.lifecycle:lifecycle-viewmodel:2.5.1)
+  implementation 'androidx.lifecycle:lifecycle-viewmodel:2.5.1'
+  implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.1'
   implementation 'androidx.preference:preference:1.2.0'
   implementation 'androidx.recyclerview:recyclerview:1.2.1'
-  implementation 'androidx.work:work-runtime:2.8.0'
-  implementation 'com.google.android.material:material:1.8.0'
-  implementation 'com.google.code.gson:gson:2.10.1'
+  implementation 'androidx.work:work-runtime:2.7.1'
+  implementation 'com.google.android.material:material:1.8.0-alpha02'
+  implementation 'com.google.code.gson:gson:2.10'
   implementation 'com.timehop.stickyheadersrecyclerview:library:0.4.3@aar'
   implementation 'com.github.devnullorthrow:MPAndroidChart:3.2.0-alpha'
   implementation 'net.jcip:jcip-annotations:1.0'
 
   // Test Dependencies
   testImplementation 'junit:junit:4.13.2'
-  testImplementation 'org.mockito:mockito-core:5.1.1'
-  testImplementation 'org.mockito:mockito-inline:5.1.1'
+  testImplementation 'org.mockito:mockito-core:4.8.1'
+  testImplementation 'org.mockito:mockito-inline:4.8.1'
 }
 
 def run(cmd) {
@@ -145,7 +147,7 @@ android {
   compileSdkVersion propCompileSdkVersion.toInteger()
   buildToolsVersion propBuildToolsVersion
 
-  ndkVersion '25.2.9519653'
+  ndkVersion '25.1.8937393'
 
   defaultConfig {
     // Default package name is taken from the manifest and should be app.organicmaps
@@ -452,6 +454,7 @@ task prepareGoogleReleaseListing {
     final sourceFiles = fileTree(dir: sourceDir,
         include: "**/*.txt", exclude: "**/*-${targetFlavor}.txt")
     sourceFiles.each { File sourceFile ->
+      final path = sourceFile.getPath()
       final locale = sourceFile.parentFile.getName()
       final targetLocaleDir = new File(targetDir, locale)
       if (!targetLocaleDir.isDirectory())
diff --git a/android/gradle.properties b/android/gradle.properties
index 5f249e8b1e..c9cf2e5f8f 100644
--- a/android/gradle.properties
+++ b/android/gradle.properties
@@ -1,7 +1,7 @@
 propMinSdkVersion=21
 propTargetSdkVersion=33
 propCompileSdkVersion=33
-propBuildToolsVersion=33.0.2
+propBuildToolsVersion=33.0.0
 
 org.gradle.caching=true
 org.gradle.jvmargs=-Xmx1024m -Xms256m
diff --git a/android/gradle/wrapper/gradle-wrapper.jar b/android/gradle/wrapper/gradle-wrapper.jar
index 943f0cbfa7..249e5832f0 100644
Binary files a/android/gradle/wrapper/gradle-wrapper.jar and b/android/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties
index f398c33c4b..ae04661ee7 100644
--- a/android/gradle/wrapper/gradle-wrapper.properties
+++ b/android/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,5 @@
 distributionBase=GRADLE_USER_HOME
 distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-bin.zip
-networkTimeout=10000
+distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-bin.zip
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
diff --git a/android/gradlew b/android/gradlew
index 65dcd68d65..a69d9cb6c2 100755
--- a/android/gradlew
+++ b/android/gradlew
@@ -55,7 +55,7 @@
 #       Darwin, MinGW, and NonStop.
 #
 #   (3) This script is generated from the Groovy template
-#       https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+#       https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
 #       within the Gradle project.
 #
 #       You can find Gradle at https://github.com/gradle/gradle/.
@@ -80,11 +80,11 @@ do
     esac
 done
 
-# This is normally unused
-# shellcheck disable=SC2034
-APP_BASE_NAME=${0##*/}
 APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
 
+APP_NAME="Gradle"
+APP_BASE_NAME=${0##*/}
+
 # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
 DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
 
@@ -143,16 +143,12 @@ fi
 if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
     case $MAX_FD in #(
       max*)
-        # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
-        # shellcheck disable=SC3045 
         MAX_FD=$( ulimit -H -n ) ||
             warn "Could not query maximum file descriptor limit"
     esac
     case $MAX_FD in  #(
       '' | soft) :;; #(
       *)
-        # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
-        # shellcheck disable=SC3045 
         ulimit -n "$MAX_FD" ||
             warn "Could not set maximum file descriptor limit to $MAX_FD"
     esac
diff --git a/android/gradlew.bat b/android/gradlew.bat
index 93e3f59f13..f127cfd49d 100644
--- a/android/gradlew.bat
+++ b/android/gradlew.bat
@@ -26,7 +26,6 @@ if "%OS%"=="Windows_NT" setlocal
 
 set DIRNAME=%~dp0
 if "%DIRNAME%"=="" set DIRNAME=.
-@rem This is normally unused
 set APP_BASE_NAME=%~n0
 set APP_HOME=%DIRNAME%
 
diff --git a/android/jni/app/organicmaps/Framework.cpp b/android/jni/app/organicmaps/Framework.cpp
index ad17613965..209e0b1608 100644
--- a/android/jni/app/organicmaps/Framework.cpp
+++ b/android/jni/app/organicmaps/Framework.cpp
@@ -1650,6 +1650,16 @@ Java_app_organicmaps_Framework_nativeDeleteBookmarkFromMapObject(JNIEnv * env, j
   return usermark_helper::CreateMapObject(env, g_framework->GetPlacePageInfo());
 }
 
+JNIEXPORT jstring JNICALL
+Java_app_organicmaps_Framework_nativeGetPoiContactUrl(JNIEnv *env, jclass, jint id)
+{
+  auto const metaID = static_cast<osm::MapObject::MetadataID>(id);
+  string_view const value = g_framework->GetPlacePageInfo().GetMetadata(metaID);
+  if (osm::isSocialContactTag(metaID))
+    return jni::ToJavaString(env, osm::socialContactToURL(metaID, value));
+  return jni::ToJavaString(env, value);
+}
+
 JNIEXPORT void JNICALL
 Java_app_organicmaps_Framework_nativeTurnOnChoosePositionMode(JNIEnv *, jclass, jboolean isBusiness, jboolean applyPosition)
 {
diff --git a/android/jni/app/organicmaps/editor/Editor.cpp b/android/jni/app/organicmaps/editor/Editor.cpp
index cbe58bb013..c4b295822f 100644
--- a/android/jni/app/organicmaps/editor/Editor.cpp
+++ b/android/jni/app/organicmaps/editor/Editor.cpp
@@ -100,6 +100,14 @@ Java_app_organicmaps_editor_Editor_nativeGetMetadata(JNIEnv * env, jclass, jint
 {
   auto const metaID = static_cast<osm::MapObject::MetadataID>(id);
   ASSERT_LESS(metaID, osm::MapObject::MetadataID::FMD_COUNT, ());
+  if (osm::isSocialContactTag(metaID))
+  {
+    auto const value = g_editableMapObject.GetMetadata(metaID);
+    if (value.find('/') == std::string::npos) // `value` contains pagename.
+      return jni::ToJavaString(env, value);
+    // `value` contains URL.
+    return jni::ToJavaString(env, osm::socialContactToURL(metaID, value));
+  }
   return jni::ToJavaString(env, g_editableMapObject.GetMetadata(metaID));
 }
 
diff --git a/android/src/app/organicmaps/Framework.java b/android/src/app/organicmaps/Framework.java
index 05fbae2eae..9b39a3704c 100644
--- a/android/src/app/organicmaps/Framework.java
+++ b/android/src/app/organicmaps/Framework.java
@@ -335,13 +335,12 @@ public class Framework
 
   public static native boolean nativeIsIsolinesLayerEnabled();
 
-  public static native void nativeSetGuidesLayerEnabled(boolean enabled);
-
-  public static native boolean nativeIsGuidesLayerEnabled();
-
   @NonNull
   public static native MapObject nativeDeleteBookmarkFromMapObject();
 
+  @NonNull
+  public static native String nativeGetPoiContactUrl(int metadataType);
+
   public static native void nativeZoomToPoint(double lat, double lon, int zoom, boolean animate);
 
   /**
diff --git a/android/src/app/organicmaps/editor/Editor.java b/android/src/app/organicmaps/editor/Editor.java
index 19a303d9c6..66cb1e7691 100644
--- a/android/src/app/organicmaps/editor/Editor.java
+++ b/android/src/app/organicmaps/editor/Editor.java
@@ -72,7 +72,6 @@ public final class Editor
   public static native String nativeGetMetadata(int id);
   public static native boolean nativeIsMetadataValid(int id, String value);
   public static native void nativeSetMetadata(int id, String value);
-
   public static native String nativeGetOpeningHours();
   public static native void nativeSetOpeningHours(String openingHours);
   public static String nativeGetPhone()
diff --git a/android/src/app/organicmaps/widget/placepage/PlacePageLinksFragment.java b/android/src/app/organicmaps/widget/placepage/PlacePageLinksFragment.java
index bc70897337..d43f7dc08b 100644
--- a/android/src/app/organicmaps/widget/placepage/PlacePageLinksFragment.java
+++ b/android/src/app/organicmaps/widget/placepage/PlacePageLinksFragment.java
@@ -12,6 +12,7 @@ import androidx.annotation.Nullable;
 import androidx.fragment.app.Fragment;
 import androidx.lifecycle.Observer;
 import androidx.lifecycle.ViewModelProvider;
+import app.organicmaps.Framework;
 import app.organicmaps.R;
 import app.organicmaps.bookmarks.data.MapObject;
 import app.organicmaps.bookmarks.data.Metadata;
@@ -145,7 +146,7 @@ public class PlacePageLinksFragment extends Fragment implements Observer<MapObje
   private void openUrl(Metadata.MetadataType type)
   {
     final String url = getLink(type);
-    if (type != Metadata.MetadataType.FMD_CONTACT_LINE || !isSocialUsername(type))
+    if (!TextUtils.isEmpty(url))
       Utils.openUrl(requireContext(), url);
   }
 
@@ -153,35 +154,21 @@ public class PlacePageLinksFragment extends Fragment implements Observer<MapObje
   {
     final String metadata = mMapObject.getMetadata(type);
     if (TextUtils.isEmpty(metadata))
-    {
       return "";
-    }
-    String path = "";
-    String domain = "";
+
     switch (type)
     {
       case FMD_WEBSITE:
-        path = getWebsiteUrl(mMapObject);
-        break;
+        return getWebsiteUrl(mMapObject);
       case FMD_CONTACT_FACEBOOK:
-        domain = "https://m.facebook.com/";
-        break;
       case FMD_CONTACT_INSTAGRAM:
-        domain = "https://instagram.com/";
-        break;
       case FMD_CONTACT_TWITTER:
-        domain = "https://mobile.twitter.com/";
-        break;
       case FMD_CONTACT_VK:
-        domain = "https://vk.com/";
-        break;
       case FMD_CONTACT_LINE:
-        path = getLineUrl();
-        break;
+        return Framework.nativeGetPoiContactUrl(type.toInt());
+      default:
+        return metadata;
     }
-    if (TextUtils.isEmpty(path))
-      path = metadata;
-    return domain + path;
   }
 
   private boolean copyUrl(View view, Metadata.MetadataType type)
@@ -202,24 +189,10 @@ public class PlacePageLinksFragment extends Fragment implements Observer<MapObje
     return true;
   }
 
-  private void refreshSocialPageLink(View view, TextView tvSocialPage, String socialPage, String webDomain)
+  private void refreshSocialPageLink(@NonNull MapObject mapObject, View view, TextView tvSocialPage, Metadata.MetadataType metaType)
   {
-    if (TextUtils.isEmpty(socialPage))
-      view.setVisibility(GONE);
-    else if (socialPage.indexOf('/') >= 0)
-      refreshMetadataOrHide("https://" + webDomain + "/" + socialPage, view, tvSocialPage);
-    else
-      refreshMetadataOrHide("@" + socialPage, view, tvSocialPage);
-  }
-
-  private void refreshSocialPageLink(View view, TextView tvSocialPage, String socialPage)
-  {
-    if (TextUtils.isEmpty(socialPage))
-      view.setVisibility(GONE);
-    else if (socialPage.indexOf('/') >= 0)
-      refreshMetadataOrHide("https://" + socialPage, view, tvSocialPage);
-    else
-      refreshMetadataOrHide("@" + socialPage, view, tvSocialPage);
+    final String socialPage = mapObject.getMetadata(metaType);
+    refreshMetadataOrHide(socialPage, view, tvSocialPage);
   }
 
   private static String getWebsiteUrl(MapObject mapObject)
@@ -229,15 +202,6 @@ public class PlacePageLinksFragment extends Fragment implements Observer<MapObje
     return TextUtils.isEmpty(website) ? url : website;
   }
 
-  private String getLineUrl()
-  {
-    final String metadata = mMapObject.getMetadata(Metadata.MetadataType.FMD_CONTACT_LINE);
-    if (isSocialUsername(Metadata.MetadataType.FMD_CONTACT_LINE))
-      return "https://line.me/R/ti/p/@" + metadata;
-    else
-      return "https://" + metadata;
-  }
-
   private void refreshLinks()
   {
     refreshMetadataOrHide(getWebsiteUrl(mMapObject), mWebsite, mTvWebsite);
@@ -246,18 +210,11 @@ public class PlacePageLinksFragment extends Fragment implements Observer<MapObje
     refreshMetadataOrHide(wikimedia_commons_text, mWikimedia, mTvWikimedia);
     refreshMetadataOrHide(mMapObject.getMetadata(Metadata.MetadataType.FMD_EMAIL), mEmail, mTvEmail);
 
-    final String facebookPageLink = mMapObject.getMetadata(Metadata.MetadataType.FMD_CONTACT_FACEBOOK);
-    refreshSocialPageLink(mFacebookPage, mTvFacebookPage, facebookPageLink, "facebook.com");
-    final String instagramPageLink = mMapObject.getMetadata(Metadata.MetadataType.FMD_CONTACT_INSTAGRAM);
-    refreshSocialPageLink(mInstagramPage, mTvInstagramPage, instagramPageLink, "instagram.com");
-    final String twitterPageLink = mMapObject.getMetadata(Metadata.MetadataType.FMD_CONTACT_TWITTER);
-    refreshSocialPageLink(mTwitterPage, mTvTwitterPage, twitterPageLink, "twitter.com");
-    final String vkPageLink = mMapObject.getMetadata(Metadata.MetadataType.FMD_CONTACT_VK);
-    refreshSocialPageLink(mVkPage, mTvVkPage, vkPageLink, "vk.com");
-    final String linePageLink = mMapObject.getMetadata(Metadata.MetadataType.FMD_CONTACT_LINE);
-    // Tag `contact:line` could contain urls from domains: line.me, liff.line.me, page.line.me, etc.
-    // And `socialPage` should not be prepended with domain, but only with "https://" protocol.
-    refreshSocialPageLink(mLinePage, mTvLinePage, linePageLink);
+    refreshSocialPageLink(mMapObject, mFacebookPage, mTvFacebookPage, Metadata.MetadataType.FMD_CONTACT_FACEBOOK);
+    refreshSocialPageLink(mMapObject, mInstagramPage, mTvInstagramPage, Metadata.MetadataType.FMD_CONTACT_INSTAGRAM);
+    refreshSocialPageLink(mMapObject, mTwitterPage, mTvTwitterPage, Metadata.MetadataType.FMD_CONTACT_TWITTER);
+    refreshSocialPageLink(mMapObject, mVkPage, mTvVkPage, Metadata.MetadataType.FMD_CONTACT_VK);
+    refreshSocialPageLink(mMapObject, mLinePage, mTvLinePage, Metadata.MetadataType.FMD_CONTACT_LINE);
   }
 
   @Override
diff --git a/base/base_tests/string_utils_test.cpp b/base/base_tests/string_utils_test.cpp
index 438afb66b4..05991a6281 100644
--- a/base/base_tests/string_utils_test.cpp
+++ b/base/base_tests/string_utils_test.cpp
@@ -923,6 +923,18 @@ UNIT_TEST(EndsWith)
     TEST(!EndsWith(s, MakeUniString("aюя")), ());
     TEST(!EndsWith(s, MakeUniString("1zюя")), ());
   }
+  {
+    std::string const s("abcd");
+    TEST(EndsWith(s, std::string_view{""}), ());
+    TEST(EndsWith(s, std::string_view{"d"}), ());
+    TEST(EndsWith(s, std::string_view{"bcd"}), ());
+    TEST(EndsWith(s, std::string_view{"abcd"}), ());
+    TEST(!EndsWith(s, std::string_view{"dd"}), ());
+    TEST(!EndsWith(s, std::string_view{"c\""}), ());
+    TEST(!EndsWith(s, std::string_view{"cde"}), ());
+    TEST(!EndsWith(s, std::string_view{"abcde"}), ());
+    TEST(!EndsWith(s, std::string_view{"0abcd"}), ());
+  }
 }
 
 UNIT_TEST(EatPrefix_EatSuffix)
diff --git a/base/string_utils.cpp b/base/string_utils.cpp
index 0d0a2025b3..db7fd9f975 100644
--- a/base/string_utils.cpp
+++ b/base/string_utils.cpp
@@ -329,9 +329,14 @@ bool EndsWith(UniString const & s1, UniString const & s2)
 }
 
 bool EndsWith(std::string const & s1, char const * s2)
+{
+  return EndsWith(s1, std::string_view(s2));
+}
+
+bool EndsWith(std::string const & s1, std::string_view s2)
 {
   size_t const n = s1.size();
-  size_t const m = strlen(s2);
+  size_t const m = s2.size();
   if (n < m)
     return false;
   return (s1.compare(n - m, m, s2) == 0);
diff --git a/base/string_utils.hpp b/base/string_utils.hpp
index 5d892104a0..1ae52e015b 100644
--- a/base/string_utils.hpp
+++ b/base/string_utils.hpp
@@ -597,6 +597,7 @@ bool StartsWith(std::string const & s1, std::string const & s2);
 
 bool EndsWith(UniString const & s1, UniString const & s2);
 bool EndsWith(std::string const & s1, char const * s2);
+bool EndsWith(std::string const & s1, std::string_view s2);
 bool EndsWith(std::string const & s, std::string::value_type c);
 bool EndsWith(std::string const & s1, std::string const & s2);
 
diff --git a/data/editor.config b/data/editor.config
index a6e2d2d7c6..9b3d774316 100644
--- a/data/editor.config
+++ b/data/editor.config
@@ -152,6 +152,7 @@
         <field_ref name="contact_instagram" />
         <field_ref name="contact_twitter" />
         <field_ref name="contact_vk" />
+        <field_ref name="contact_line" />
       </field_group>
       <field_group name="poi_internet">
         <field_ref name="name" />
@@ -167,6 +168,7 @@
         <field_ref name="contact_instagram" />
         <field_ref name="contact_twitter" />
         <field_ref name="contact_vk" />
+        <field_ref name="contact_line" />
       </field_group>
     </fields>
     <!-- Types should be sorted by their priority. -->
diff --git a/data/strings/types_strings.txt b/data/strings/types_strings.txt
index a60e234715..067f54e27b 100644
--- a/data/strings/types_strings.txt
+++ b/data/strings/types_strings.txt
@@ -5080,7 +5080,7 @@
     pt = Fronteira de subúrbio
     pt-BR = Fronteira de subúrbio
     ru = Граница пригорода
-    tr = Mahalle Sınırı
+    tr = Banliyö Sınırı
     uk = Приміська межа
     zh-Hans = 市郊行政区域界线
 
@@ -17467,7 +17467,7 @@
     sv = Förort
     sw = Pambizo
     th = ชานเมือง
-    tr = Mahalle
+    tr = Banliyö
     uk = Район
     vi = Đảo
     zh-Hans = 市郊
diff --git a/docs/INSTALL.md b/docs/INSTALL.md
index b395156317..a53d9bb0c6 100644
--- a/docs/INSTALL.md
+++ b/docs/INSTALL.md
@@ -43,19 +43,12 @@ Configure the repository for an opensource build:
 bash ./configure.sh
 ```
 
-For _Windows 10_:  You should be able to build the project by following either of these setups:
-
-**Setup 1: Using WSL**
-1. Install [WSL](https://learn.microsoft.com/en-us/windows/wsl/install) on your machine.
-2. Install g++ by running the following command in WSL: `sudo apt install g++`
-3. Run `./configure.sh` in WSL.
-
-**Setup 2: Using Visual Studio Developer Command Prompt**
-1. Install the [Visual Studio Developer Command Prompt](https://docs.microsoft.com/en-us/visualstudio/ide/reference/command-prompt-powershell?view=vs-2022) (make sure to choose the latest MSVC x64/x86 build tool and Windows 10/11 SDK as individual components while installing Visual Studio).
-2. Run the following command and follow instructions:
+For _Windows 10_: Use WSL to run `./configure.sh`, or, alternatively, run the following command from the
+[Visual Studio Developer Command Prompt](https://docs.microsoft.com/en-us/visualstudio/ide/reference/command-prompt-powershell?view=vs-2022)
+and follow instructions:
 
 ```bash
-"C:\Program Files\Git\bin\bash.exe" configure.sh # execute the script by using Developer Command Prompt
+bash ./configure.sh # execute the script by using Ubuntu WSL VM
 ```
 
 ### Special cases options
diff --git a/editor/editor_tests/editor_config_test.cpp b/editor/editor_tests/editor_config_test.cpp
index d2932e5d81..e609043f06 100644
--- a/editor/editor_tests/editor_config_test.cpp
+++ b/editor/editor_tests/editor_config_test.cpp
@@ -21,6 +21,7 @@ UNIT_TEST(EditorConfig_TypeDescription)
     EType::FMD_CONTACT_INSTAGRAM,
     EType::FMD_CONTACT_TWITTER,
     EType::FMD_CONTACT_VK,
+    EType::FMD_CONTACT_LINE,
   };
 
   pugi::xml_document doc;
diff --git a/editor/editor_tests/xml_feature_test.cpp b/editor/editor_tests/xml_feature_test.cpp
index 5764d7d208..dac94b0812 100644
--- a/editor/editor_tests/xml_feature_test.cpp
+++ b/editor/editor_tests/xml_feature_test.cpp
@@ -480,3 +480,89 @@ UNIT_TEST(XMLFeature_Diet)
   ft.SetCuisine("");
   TEST_EQUAL(ft.GetCuisine(), "", ());
 }
+
+UNIT_TEST(XMLFeature_SocialContactsProcessing)
+{
+  {
+    std::string const nightclubStr = R"(<?xml version="1.0"?>
+    <node lat="50.4082862" lon="30.5130017" timestamp="2022-02-24T05:07:00Z">
+    <tag k="amenity" v="nightclub" />
+    <tag k="name" v="Stereo Plaza" />
+    <tag k="contact:facebook" v="http://www.facebook.com/pages/Stereo-Plaza/118100041593935" />
+    <tag k="contact:instagram" v="https://www.instagram.com/p/CSy87IhMhfm/" />
+    <tag k="contact:line" v="liff.line.me/1645278921-kWRPP32q/?accountId=673watcr" />
+    </node>
+    )";
+
+    editor::XMLFeature xmlFeature(nightclubStr);
+
+    osm::EditableMapObject emo;
+    editor::FromXML(xmlFeature, emo);
+
+    // Read and write "contact:facebook" to apply normalization.
+    std::string contactFacebook(emo.GetMetadata(feature::Metadata::FMD_CONTACT_FACEBOOK));
+    emo.SetMetadata(osm::MapObject::MetadataID::FMD_CONTACT_FACEBOOK, contactFacebook);
+
+    // Read and write "contact:instagram" to apply normalization.
+    std::string contactInstagram(emo.GetMetadata(feature::Metadata::FMD_CONTACT_INSTAGRAM));
+    emo.SetMetadata(osm::MapObject::MetadataID::FMD_CONTACT_INSTAGRAM, contactInstagram);
+
+    // Read and write "contact:line" to apply normalization.
+    std::string contactLine(emo.GetMetadata(feature::Metadata::FMD_CONTACT_LINE));
+    emo.SetMetadata(osm::MapObject::MetadataID::FMD_CONTACT_LINE, contactLine);
+
+    auto convertedFt = editor::ToXML(emo, true);
+
+    TEST(convertedFt.HasTag("contact:facebook"), ());
+    TEST_EQUAL(convertedFt.GetTagValue("contact:facebook"), "https://facebook.com/pages/Stereo-Plaza/118100041593935", ());
+
+    TEST(convertedFt.HasTag("contact:instagram"), ());
+    TEST_EQUAL(convertedFt.GetTagValue("contact:instagram"), "https://instagram.com/p/CSy87IhMhfm", ());
+
+    TEST(convertedFt.HasTag("contact:line"), ());
+    TEST_EQUAL(convertedFt.GetTagValue("contact:line"), "https://liff.line.me/1645278921-kWRPP32q/?accountId=673watcr", ());
+  }
+}
+
+UNIT_TEST(XMLFeature_SocialContactsProcessing_clean)
+{
+  {
+    std::string const nightclubStr = R"(<?xml version="1.0"?>
+    <node lat="40.82862" lon="20.30017" timestamp="2022-02-24T05:07:00Z">
+    <tag k="amenity" v="bar" />
+    <tag k="name" v="Irish Pub" />
+    <tag k="contact:facebook" v="https://www.facebook.com/PierreCardinPeru.oficial/" />
+    <tag k="contact:instagram" v="https://www.instagram.com/fraback.genusswelt/" />
+    <tag k="contact:line" v="https://line.me/R/ti/p/%40015qevdv" />
+    </node>
+    )";
+
+    editor::XMLFeature xmlFeature(nightclubStr);
+
+    osm::EditableMapObject emo;
+    editor::FromXML(xmlFeature, emo);
+
+    // Read and write "contact:facebook" to apply normalization.
+    std::string contactFacebook(emo.GetMetadata(feature::Metadata::FMD_CONTACT_FACEBOOK));
+    emo.SetMetadata(osm::MapObject::MetadataID::FMD_CONTACT_FACEBOOK, contactFacebook);
+
+    // Read and write "contact:instagram" to apply normalization.
+    std::string contactInstagram(emo.GetMetadata(feature::Metadata::FMD_CONTACT_INSTAGRAM));
+    emo.SetMetadata(osm::MapObject::MetadataID::FMD_CONTACT_INSTAGRAM, contactInstagram);
+
+    // Read and write "contact:line" to apply normalization.
+    std::string contactLine(emo.GetMetadata(feature::Metadata::FMD_CONTACT_LINE));
+    emo.SetMetadata(osm::MapObject::MetadataID::FMD_CONTACT_LINE, contactLine);
+
+    auto convertedFt = editor::ToXML(emo, true);
+
+    TEST(convertedFt.HasTag("contact:facebook"), ());
+    TEST_EQUAL(convertedFt.GetTagValue("contact:facebook"), "PierreCardinPeru.oficial", ());
+
+    TEST(convertedFt.HasTag("contact:instagram"), ());
+    TEST_EQUAL(convertedFt.GetTagValue("contact:instagram"), "fraback.genusswelt", ());
+
+    TEST(convertedFt.HasTag("contact:line"), ());
+    TEST_EQUAL(convertedFt.GetTagValue("contact:line"), "015qevdv", ());
+  }
+}
diff --git a/editor/xml_feature.cpp b/editor/xml_feature.cpp
index 5ac1b1ba85..51021c8376 100644
--- a/editor/xml_feature.cpp
+++ b/editor/xml_feature.cpp
@@ -3,6 +3,7 @@
 #include "indexer/classificator.hpp"
 #include "indexer/editable_map_object.hpp"
 #include "indexer/ftypes_matcher.hpp"
+#include "indexer/validate_and_format_contacts.hpp"
 
 #include "coding/string_utf8_multilang.hpp"
 
@@ -606,7 +607,10 @@ XMLFeature ToXML(osm::EditableMapObject const & object, bool serializeType)
 
   object.ForEachMetadataItem([&toFeature](string_view tag, string_view value)
   {
-    toFeature.SetTagValue(tag, value);
+    if (osm::isSocialContactTag(tag) && value.find('/') != std::string::npos)
+      toFeature.SetTagValue(tag, osm::socialContactToURL(tag, value));
+    else
+      toFeature.SetTagValue(tag, value);
   });
 
   return toFeature;
diff --git a/indexer/indexer_tests/validate_and_format_contacts_test.cpp b/indexer/indexer_tests/validate_and_format_contacts_test.cpp
index ea8212f9bf..536876effb 100644
--- a/indexer/indexer_tests/validate_and_format_contacts_test.cpp
+++ b/indexer/indexer_tests/validate_and_format_contacts_test.cpp
@@ -9,11 +9,15 @@ UNIT_TEST(EditableMapObject_ValidateAndFormat_facebook)
   TEST_EQUAL(osm::ValidateAndFormat_facebook(""), "", ());
   TEST_EQUAL(osm::ValidateAndFormat_facebook("facebook.com/OpenStreetMap"), "OpenStreetMap", ());
   TEST_EQUAL(osm::ValidateAndFormat_facebook("www.facebook.com/OpenStreetMap"), "OpenStreetMap", ());
+  TEST_EQUAL(osm::ValidateAndFormat_facebook("www.facebook.fr/OpenStreetMap"), "OpenStreetMap", ());
   TEST_EQUAL(osm::ValidateAndFormat_facebook("http://facebook.com/OpenStreetMap"), "OpenStreetMap", ());
   TEST_EQUAL(osm::ValidateAndFormat_facebook("https://facebook.com/OpenStreetMap"), "OpenStreetMap", ());
   TEST_EQUAL(osm::ValidateAndFormat_facebook("http://www.facebook.com/OpenStreetMap"), "OpenStreetMap", ());
   TEST_EQUAL(osm::ValidateAndFormat_facebook("https://www.facebook.com/OpenStreetMap"), "OpenStreetMap", ());
+  TEST_EQUAL(osm::ValidateAndFormat_facebook("https://de-de.facebook.de/Open_Street_Map"), "Open_Street_Map", ());
   TEST_EQUAL(osm::ValidateAndFormat_facebook("https://en-us.facebook.com/OpenStreetMap"), "OpenStreetMap", ());
+  TEST_EQUAL(osm::ValidateAndFormat_facebook("https://de-de.facebook.com/profile.php?id=100085707580841"), "100085707580841", ());
+  TEST_EQUAL(osm::ValidateAndFormat_facebook("http://facebook.com/profile.php?share=app&id=100086487430889#m"), "100086487430889", ());
   TEST_EQUAL(osm::ValidateAndFormat_facebook("some.good.page"), "some.good.page", ());
   TEST_EQUAL(osm::ValidateAndFormat_facebook("@tree-house-interiors"), "tree-house-interiors", ());
 
@@ -61,14 +65,16 @@ UNIT_TEST(EditableMapObject_ValidateAndFormat_twitter)
 UNIT_TEST(EditableMapObject_ValidateAndFormat_vk)
 {
   TEST_EQUAL(osm::ValidateAndFormat_vk("vk.com/id404"), "id404", ());
-  TEST_EQUAL(osm::ValidateAndFormat_vk("vkontakte.ru/id404"), "id404", ());
+  TEST_EQUAL(osm::ValidateAndFormat_vk("vkontakte.ru/id4321"), "id4321", ());
+  TEST_EQUAL(osm::ValidateAndFormat_vk("www.vkontakte.ru/id43210"), "id43210", ());
   TEST_EQUAL(osm::ValidateAndFormat_vk("www.vk.com/id404"), "id404", ());
-  TEST_EQUAL(osm::ValidateAndFormat_vk("http://vk.com/id404"), "id404", ());
-  TEST_EQUAL(osm::ValidateAndFormat_vk("https://vk.com/id404"), "id404", ());
-  TEST_EQUAL(osm::ValidateAndFormat_vk("https://vkontakte.ru/id404"), "id404", ());
-  TEST_EQUAL(osm::ValidateAndFormat_vk("http://www.vk.com/id404"), "id404", ());
-  TEST_EQUAL(osm::ValidateAndFormat_vk("https://www.vk.com/id404"), "id404", ());
-  TEST_EQUAL(osm::ValidateAndFormat_vk("https://www.vk.com/id405/"), "id405", ());
+  TEST_EQUAL(osm::ValidateAndFormat_vk("http://vk.com/ozon"), "ozon", ());
+  TEST_EQUAL(osm::ValidateAndFormat_vk("https://vk.com/sklad169"), "sklad169", ());
+  TEST_EQUAL(osm::ValidateAndFormat_vk("https://vkontakte.ru/id4321"), "id4321", ());
+  TEST_EQUAL(osm::ValidateAndFormat_vk("https://www.vkontakte.ru/id4321"), "id4321", ());
+  TEST_EQUAL(osm::ValidateAndFormat_vk("http://www.vk.com/ugona.net.expert"), "ugona.net.expert", ());
+  TEST_EQUAL(osm::ValidateAndFormat_vk("https://www.vk.com/7cvetov18"), "7cvetov18", ());
+  TEST_EQUAL(osm::ValidateAndFormat_vk("https://www.vk.com/7cvetov18/"), "7cvetov18", ());
   TEST_EQUAL(osm::ValidateAndFormat_vk("@22ab.cdef"), "22ab.cdef", ());
 
   TEST_EQUAL(osm::ValidateAndFormat_vk("instagram.com/hello_world"), "", ());
@@ -81,6 +87,7 @@ UNIT_TEST(EditableMapObject_ValidateAndFormat_contactLine)
   TEST_EQUAL(osm::ValidateAndFormat_contactLine("https://line.me/ti/p/@dgxs9r6wad"), "dgxs9r6wad", ());
   TEST_EQUAL(osm::ValidateAndFormat_contactLine("https://line.me/ti/p/%40vne5uwke17"), "vne5uwke17", ());
   TEST_EQUAL(osm::ValidateAndFormat_contactLine("http://line.me/R/ti/p/bfsg1a8x9u"), "bfsg1a8x9u", ());
+  TEST_EQUAL(osm::ValidateAndFormat_contactLine("line.me/R/ti/p/bfsg1a8x9u"), "bfsg1a8x9u", ());
   TEST_EQUAL(osm::ValidateAndFormat_contactLine("https://line.me/R/ti/p/gdltt7s380"), "gdltt7s380", ());
   TEST_EQUAL(osm::ValidateAndFormat_contactLine("https://line.me/R/ti/p/@sdb2pb3lsg"), "sdb2pb3lsg", ());
   TEST_EQUAL(osm::ValidateAndFormat_contactLine("https://line.me/R/ti/p/%40b30h5mdj11"), "b30h5mdj11", ());
@@ -91,6 +98,9 @@ UNIT_TEST(EditableMapObject_ValidateAndFormat_contactLine)
   TEST_EQUAL(osm::ValidateAndFormat_contactLine("https://line.me/R/home/public/profile?id=r90ck7n1rq"), "r90ck7n1rq", ());
   TEST_EQUAL(osm::ValidateAndFormat_contactLine("https://page.line.me/fom5198h"), "fom5198h", ());
   TEST_EQUAL(osm::ValidateAndFormat_contactLine("https://page.line.me/qn58n8g?web=mobile"), "qn58n8g", ());
+  TEST_EQUAL(osm::ValidateAndFormat_contactLine("https://page.line.me/?accountId=673watcr"), "673watcr", ());
+  TEST_EQUAL(osm::ValidateAndFormat_contactLine("page.line.me/?accountId=673watcr"), "673watcr", ());
+  TEST_EQUAL(osm::ValidateAndFormat_contactLine("https://liff.line.me/1645278921-kWRPP32q/?accountId=673watcr"), "liff.line.me/1645278921-kWRPP32q/?accountId=673watcr", ());
   TEST_EQUAL(osm::ValidateAndFormat_contactLine("https://abc.line.me/en/some/page?id=xaladqv"), "abc.line.me/en/some/page?id=xaladqv", ());
   TEST_EQUAL(osm::ValidateAndFormat_contactLine("@abcd"), "abcd", ());
   TEST_EQUAL(osm::ValidateAndFormat_contactLine("@-hyphen-test-"), "-hyphen-test-", ());
@@ -103,11 +113,14 @@ UNIT_TEST(EditableMapObject_ValidateFacebookPage)
   TEST(osm::ValidateFacebookPage(""), ());
   TEST(osm::ValidateFacebookPage("facebook.com/OpenStreetMap"), ());
   TEST(osm::ValidateFacebookPage("www.facebook.com/OpenStreetMap"), ());
+  TEST(osm::ValidateFacebookPage("www.facebook.fr/OpenStreetMap"), ());
   TEST(osm::ValidateFacebookPage("http://facebook.com/OpenStreetMap"), ());
   TEST(osm::ValidateFacebookPage("https://facebook.com/OpenStreetMap"), ());
   TEST(osm::ValidateFacebookPage("http://www.facebook.com/OpenStreetMap"), ());
   TEST(osm::ValidateFacebookPage("https://www.facebook.com/OpenStreetMap"), ());
+  TEST(osm::ValidateFacebookPage("https://de-de.facebook.de/OpenStreetMap"), ());
   TEST(osm::ValidateFacebookPage("https://en-us.facebook.com/OpenStreetMap"), ());
+  TEST(osm::ValidateFacebookPage("https://www.facebook.com/profile.php?id=100085707580841"), ());
   TEST(osm::ValidateFacebookPage("OpenStreetMap"), ());
   TEST(osm::ValidateFacebookPage("some.good.page"), ());
   TEST(osm::ValidateFacebookPage("Quaama-Volunteer-Bushfire-Brigade-526790054021506"), ());
@@ -248,3 +261,18 @@ UNIT_TEST(EditableMapObject_ValidateLinePage)
   TEST(!osm::ValidateLinePage("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"), ());
   TEST(!osm::ValidateLinePage("https://line.com/ti/p/invalid-domain"), ());
 }
+
+UNIT_TEST(EditableMapObject_socialContactToURL)
+{
+  TEST_EQUAL(osm::socialContactToURL(osm::MapObject::MetadataID::FMD_CONTACT_INSTAGRAM, "some_page_name"), "https://instagram.com/some_page_name", ());
+  TEST_EQUAL(osm::socialContactToURL(osm::MapObject::MetadataID::FMD_CONTACT_INSTAGRAM, "p/BvkgKZNDbqN"), "https://instagram.com/p/BvkgKZNDbqN", ());
+  TEST_EQUAL(osm::socialContactToURL(osm::MapObject::MetadataID::FMD_CONTACT_FACEBOOK, "100086487430889"), "https://facebook.com/100086487430889", ());
+  TEST_EQUAL(osm::socialContactToURL(osm::MapObject::MetadataID::FMD_CONTACT_FACEBOOK, "nova.poshta.official"), "https://facebook.com/nova.poshta.official", ());
+  TEST_EQUAL(osm::socialContactToURL(osm::MapObject::MetadataID::FMD_CONTACT_FACEBOOK, "pg/ESQ-336537783591903/about"), "https://facebook.com/pg/ESQ-336537783591903/about", ());
+  TEST_EQUAL(osm::socialContactToURL(osm::MapObject::MetadataID::FMD_CONTACT_TWITTER, "carmelopizza"), "https://twitter.com/carmelopizza", ());
+  TEST_EQUAL(osm::socialContactToURL(osm::MapObject::MetadataID::FMD_CONTACT_TWITTER, "demhamburguesa/status/688001869269078016"), "https://twitter.com/demhamburguesa/status/688001869269078016", ());
+  TEST_EQUAL(osm::socialContactToURL(osm::MapObject::MetadataID::FMD_CONTACT_VK, "beerhousebar"), "https://vk.com/beerhousebar", ());
+  TEST_EQUAL(osm::socialContactToURL(osm::MapObject::MetadataID::FMD_CONTACT_VK, "wall-41524_29351"), "https://vk.com/wall-41524_29351", ());
+  TEST_EQUAL(osm::socialContactToURL(osm::MapObject::MetadataID::FMD_CONTACT_LINE, "a26235875"), "https://line.me/R/ti/p/@a26235875", ());
+  TEST_EQUAL(osm::socialContactToURL(osm::MapObject::MetadataID::FMD_CONTACT_LINE, "liff.line.me/1645278921-kWRPP32q/?accountId=673watcr"), "https://liff.line.me/1645278921-kWRPP32q/?accountId=673watcr", ());
+}
\ No newline at end of file
diff --git a/indexer/validate_and_format_contacts.cpp b/indexer/validate_and_format_contacts.cpp
index 00c4ee462d..f544a452bb 100644
--- a/indexer/validate_and_format_contacts.cpp
+++ b/indexer/validate_and_format_contacts.cpp
@@ -17,22 +17,50 @@ static auto const s_badVkRegex = regex(R"(^\d\d\d.+$)");
 static auto const s_goodVkRegex = regex(R"(^[A-Za-z0-9_.]{5,32}$)");
 static auto const s_lineRegex = regex(R"(^[a-z0-9-_.]{4,20}$)");
 
-char const * const kWebsiteProtocols[] = {"http://", "https://"};
-size_t const kWebsiteProtocolDefaultIndex = 0;
+constexpr string_view kFacebook{"contact:facebook"};
+constexpr string_view kInstagram{"contact:instagram"};
+constexpr string_view kTwitter{"contact:twitter"};
+constexpr string_view kVk{"contact:vk"};
+constexpr string_view kLine{"contact:line"};
+
+constexpr string_view kProfilePhp{"profile.php"};
+
+// Domains constants.
+constexpr string_view kFbDot{"fb."};
+constexpr string_view kFacebookDot{"facebook."};
+constexpr string_view kInstagramCom{"instagram.com"};
+constexpr string_view kDotInstagramCom{".instagram.com"};
+constexpr string_view kTwitterCom{"twitter.com"};
+constexpr string_view kDotTwitterCom{".twitter.com"};
+constexpr string_view kVkCom{"vk.com"};
+constexpr string_view kVkontakteRu{"vkontakte.ru"};
+constexpr string_view kDotVkCom{".vk.com"};
+constexpr string_view kDotVkontakteRu{".vkontakte.ru"};
+constexpr string_view kLineMe{"line.me"};
+constexpr string_view kPageLineMe{"page.line.me"};
+constexpr string_view kDotLineMe{".line.me"};
+
+// URLs constants
+constexpr string_view kUrlFacebook{"https://facebook.com/"};
+constexpr string_view kUrlInstagram{"https://instagram.com/"};
+constexpr string_view kUrlTwitter{"https://twitter.com/"};
+constexpr string_view kUrlVk{"https://vk.com/"};
+constexpr string_view kUrlLine{"https://line.me/R/ti/p/@"};
+constexpr string_view kHttp{"http://"};
+constexpr string_view kHttps{"https://"};
 
 size_t GetProtocolNameLength(string const & website)
 {
-  for (auto const & protocol : kWebsiteProtocols)
-  {
-    if (strings::StartsWith(website, protocol))
-      return strlen(protocol);
-  }
+  if (strings::StartsWith(website, kHttp))
+    return kHttp.size();
+  if (strings::StartsWith(website, kHttps))
+    return kHttps.size();
   return 0;
 }
 
 bool IsProtocolSpecified(string const & website)
 {
-  return GetProtocolNameLength(website) > 0;
+  return strings::StartsWith(website, kHttp) || strings::StartsWith(website, kHttps);
 }
 
 // TODO: Current implementation looks only for restricted symbols from ASCII block ignoring
@@ -60,7 +88,7 @@ bool containsInvalidFBSymbol(string const & facebookPage, size_t startIndex = 0)
 std::string ValidateAndFormat_website(std::string const & v)
 {
   if (!v.empty() && !IsProtocolSpecified(v))
-    return kWebsiteProtocols[kWebsiteProtocolDefaultIndex] + v;
+    return string{kHttp}.append(v);
   return v;
 }
 
@@ -90,12 +118,18 @@ string ValidateAndFormat_facebook(string const & facebookPage)
   url::Url const url = url::Url::FromString(facebookPage);
   string const domain = strings::MakeLowerCase(url.GetHost());
   // Check Facebook domain name.
-  if (strings::EndsWith(domain, "facebook.com") || strings::EndsWith(domain, "fb.com")
-      || strings::EndsWith(domain, "fb.me") || strings::EndsWith(domain, "facebook.de")
-      || strings::EndsWith(domain, "facebook.fr"))
+  if (strings::StartsWith(domain, kFacebookDot) || strings::StartsWith(domain, kFbDot) ||
+      domain.find(".facebook.") != string::npos || domain.find(".fb.") != string::npos)
   {
     auto webPath = url.GetPath();
-    // Strip last '/' symbol
+    // In case of https://www.facebook.com/profile.php?id=100085707580841 extract only ID.
+    if (strings::StartsWith(webPath, kProfilePhp))
+    {
+      std::string const * id = url.GetParamValue("id");
+      return (id ? *id : std::string());
+    }
+
+    // Strip last '/' symbol.
     webPath.erase(webPath.find_last_not_of('/') + 1);
     return webPath;
   }
@@ -120,8 +154,8 @@ string ValidateAndFormat_instagram(string const & instagramPage)
 
   url::Url const url = url::Url::FromString(instagramPage);
   string const domain = strings::MakeLowerCase(url.GetHost());
-  // Check Instagram domain name.
-  if (domain == "instagram.com" || strings::EndsWith(domain, ".instagram.com"))
+  // Check Instagram domain name: "instagram.com" or "*.instagram.com".
+  if (domain == kInstagramCom || strings::EndsWith(domain, kDotInstagramCom))
   {
     auto webPath = url.GetPath();
     // Strip last '/' symbol.
@@ -149,12 +183,12 @@ string ValidateAndFormat_twitter(string const & twitterPage)
 
   url::Url const url = url::Url::FromString(twitterPage);
   string const domain = strings::MakeLowerCase(url.GetHost());
-  // Check Twitter domain name.
-  if (domain == "twitter.com" || strings::EndsWith(domain, ".twitter.com"))
+  // Check Twitter domain name: "twitter.com" or "*.twitter.com".
+  if (domain == kTwitterCom || strings::EndsWith(domain, kDotTwitterCom))
   {
     auto webPath = url.GetPath();
 
-    // Strip last '/' symbol and first '@' symbol
+    // Strip last '/' symbol and first '@' symbol.
     webPath.erase(webPath.find_last_not_of('/') + 1);
     webPath.erase(0, webPath.find_first_not_of('@'));
 
@@ -190,9 +224,9 @@ string ValidateAndFormat_vk(string const & vkPage)
 
   url::Url const url = url::Url::FromString(vkPage);
   string const domain = strings::MakeLowerCase(url.GetHost());
-  // Check VK domain name.
-  if (domain == "vk.com" || strings::EndsWith(domain, ".vk.com") ||
-      domain == "vkontakte.ru" || strings::EndsWith(domain, ".vkontakte.ru"))
+  // Check VK domain name: "vk.com" or "vkontakte.ru" or "*.vk.com" or "*.vkontakte.ru".
+  if (domain == kVkCom || strings::EndsWith(domain, kDotVkCom) ||
+      domain == kVkontakteRu || strings::EndsWith(domain, kDotVkontakteRu))
   {
     auto webPath = url.GetPath();
     // Strip last '/' symbol.
@@ -239,13 +273,18 @@ string ValidateAndFormat_contactLine(string const & linePage)
   url::Url const url = url::Url::FromString(linePage);
   string const domain = strings::MakeLowerCase(url.GetHost());
   // Check Line domain name.
-  if (domain == "page.line.me")
+  if (domain == kPageLineMe)
   {
+    // Parse https://page.line.me/?accountId={LINE ID}
+    std::string const * id = url.GetParamValue("accountId");
+    if (id != nullptr)
+      return *id;
+
     // Parse https://page.line.me/{LINE ID}
     string lineId = url.GetPath();
     return stripAtSymbol(lineId);
   }
-  else if (domain == "line.me" || strings::EndsWith(domain, ".line.me"))
+  else if (domain == kLineMe || strings::EndsWith(domain, kDotLineMe))
   {
     auto webPath = url.GetPath();
     if (strings::StartsWith(webPath, "R/ti/p/"))
@@ -265,14 +304,15 @@ string ValidateAndFormat_contactLine(string const & linePage)
       // Parse https://line.me/R/home/public/main?id={LINE ID without @}
       // and https://line.me/R/home/public/profile?id={LINE ID without @}
       std::string const * id = url.GetParamValue("id");
-      return (id? *id : std::string());
+      return (id ? *id : std::string());
     }
     else
     {
-      if (strings::StartsWith(linePage, "http://"))
+      if (strings::StartsWith(linePage, kHttp))
         return linePage.substr(7);
-      if (strings::StartsWith(linePage, "https://"))
+      if (strings::StartsWith(linePage, kHttps))
         return linePage.substr(8);
+      return linePage;
     }
   }
 
@@ -289,7 +329,7 @@ bool ValidateWebsite(string const & site)
   if (startPos >= site.size())
     return false;
 
-  // Site should contain at least one dot but not at the begining/end.
+  // Site should contain at least one dot but not at the beginning/end.
   if ('.' == site[startPos] || '.' == site.back())
     return false;
 
@@ -320,7 +360,8 @@ bool ValidateFacebookPage(string const & page)
     return false;
 
   string const domain = strings::MakeLowerCase(url::Url::FromString(page).GetHost());
-  return (strings::StartsWith(domain, "facebook.") || strings::StartsWith(domain, "fb.") ||
+  // Validate domain name: "facebook.*" or "fb.*" or "*.facebook.*" or "*.fb.*".
+  return (strings::StartsWith(domain, kFacebookDot) || strings::StartsWith(domain, kFbDot) ||
           domain.find(".facebook.") != string::npos || domain.find(".fb.") != string::npos);
 }
 
@@ -337,7 +378,7 @@ bool ValidateInstagramPage(string const & page)
     return false;
 
   string const domain = strings::MakeLowerCase(url::Url::FromString(page).GetHost());
-  return domain == "instagram.com" || strings::EndsWith(domain, ".instagram.com");
+  return domain == kInstagramCom || strings::EndsWith(domain, kDotInstagramCom);
 }
 
 bool ValidateTwitterPage(string const & page)
@@ -349,7 +390,7 @@ bool ValidateTwitterPage(string const & page)
     return regex_match(page, s_twitterRegex); // Rules are defined here: https://stackoverflow.com/q/11361044
 
   string const domain = strings::MakeLowerCase(url::Url::FromString(page).GetHost());
-  return domain == "twitter.com" || strings::EndsWith(domain, ".twitter.com");
+  return domain == kTwitterCom || strings::EndsWith(domain, kDotTwitterCom);
 }
 
 bool ValidateVkPage(string const & page)
@@ -382,8 +423,8 @@ bool ValidateVkPage(string const & page)
     return false;
 
   string const domain = strings::MakeLowerCase(url::Url::FromString(page).GetHost());
-  return domain == "vk.com" || strings::EndsWith(domain, ".vk.com")
-         || domain == "vkontakte.ru" || strings::EndsWith(domain, ".vkontakte.ru");
+  return domain == kVkCom || strings::EndsWith(domain, kDotVkCom)
+         || domain == kVkontakteRu || strings::EndsWith(domain, kDotVkontakteRu);
 }
 
 bool ValidateLinePage(string const & page)
@@ -406,7 +447,70 @@ bool ValidateLinePage(string const & page)
 
   string const domain = strings::MakeLowerCase(url::Url::FromString(page).GetHost());
   // Check Line domain name.
-  return (domain == "line.me" || strings::EndsWith(domain, ".line.me"));
+  return (domain == kLineMe || strings::EndsWith(domain, kDotLineMe));
+}
+
+bool isSocialContactTag(string_view tag)
+{
+  return tag == kInstagram || tag == kFacebook || tag == kTwitter || tag == kVk || tag == kLine;
+}
+
+bool isSocialContactTag(MapObject::MetadataID const metaID)
+{
+  return metaID == MapObject::MetadataID::FMD_CONTACT_INSTAGRAM ||
+         metaID == MapObject::MetadataID::FMD_CONTACT_FACEBOOK ||
+         metaID == MapObject::MetadataID::FMD_CONTACT_TWITTER ||
+         metaID == MapObject::MetadataID::FMD_CONTACT_VK ||
+         metaID == MapObject::MetadataID::FMD_CONTACT_LINE;
+}
+
+// Functions ValidateAndFormat_{facebook,instagram,twitter,vk}(...) by default strip domain name
+// from OSM data and user input. This function prepends domain name to generate full URL.
+string socialContactToURL(string_view tag, string_view value)
+{
+  ASSERT(!value.empty(), ());
+
+  if (tag == kInstagram)
+    return string{kUrlInstagram}.append(value);
+  if (tag == kFacebook)
+    return string{kUrlFacebook}.append(value);
+  if (tag == kTwitter)
+    return string{kUrlTwitter}.append(value);
+  if (tag == kVk)
+    return string{kUrlVk}.append(value);
+  if (tag == kLine)
+  {
+    if (value.find('/') == string::npos) // 'value' is a username.
+      return string{kUrlLine}.append(value);
+    else // 'value' is an URL.
+      return string{kHttps}.append(value);
+  }
+
+  return string{value};
+}
+
+string socialContactToURL(MapObject::MetadataID metaID, string_view value)
+{
+  ASSERT(!value.empty(), ());
+
+  switch (metaID)
+  {
+    case MapObject::MetadataID::FMD_CONTACT_INSTAGRAM:
+      return string{kUrlInstagram}.append(value);
+    case MapObject::MetadataID::FMD_CONTACT_FACEBOOK:
+      return string{kUrlFacebook}.append(value);
+    case MapObject::MetadataID::FMD_CONTACT_TWITTER:
+      return string{kUrlTwitter}.append(value);
+    case MapObject::MetadataID::FMD_CONTACT_VK:
+      return string{kUrlVk}.append(value);
+    case MapObject::MetadataID::FMD_CONTACT_LINE:
+      if (value.find('/') == string::npos) // 'value' is a username.
+        return string{kUrlLine}.append(value);
+      else // 'value' is an URL.
+        return string{kHttps}.append(value);
+    default:
+      return string{value};
+  }
 }
 
 } // namespace osm
diff --git a/indexer/validate_and_format_contacts.hpp b/indexer/validate_and_format_contacts.hpp
index 2d2612b15b..7e430c1656 100644
--- a/indexer/validate_and_format_contacts.hpp
+++ b/indexer/validate_and_format_contacts.hpp
@@ -2,6 +2,8 @@
 
 #include <string>
 
+#include "map_object.hpp"
+
 namespace osm
 {
 std::string ValidateAndFormat_website(std::string const & v);
@@ -17,4 +19,9 @@ bool ValidateInstagramPage(std::string const & v);
 bool ValidateTwitterPage(std::string const & v);
 bool ValidateVkPage(std::string const & v);
 bool ValidateLinePage(std::string const & v);
-}
+
+bool isSocialContactTag(std::string_view tag);
+bool isSocialContactTag(osm::MapObject::MetadataID const metaID);
+std::string socialContactToURL(std::string_view tag, std::string_view value);
+std::string socialContactToURL(osm::MapObject::MetadataID metaID, std::string_view value);
+}  // namespace osm
diff --git a/iphone/CoreApi/CoreApi/PlacePageData/Common/PlacePageInfoData.h b/iphone/CoreApi/CoreApi/PlacePageData/Common/PlacePageInfoData.h
index 9533f55927..a5da3f0f29 100644
--- a/iphone/CoreApi/CoreApi/PlacePageData/Common/PlacePageInfoData.h
+++ b/iphone/CoreApi/CoreApi/PlacePageData/Common/PlacePageInfoData.h
@@ -17,6 +17,7 @@ NS_ASSUME_NONNULL_BEGIN
 @property(nonatomic, readonly, nullable) NSString *instagram;
 @property(nonatomic, readonly, nullable) NSString *twitter;
 @property(nonatomic, readonly, nullable) NSString *vk;
+@property(nonatomic, readonly, nullable) NSString *line;
 @property(nonatomic, readonly, nullable) NSString *email;
 @property(nonatomic, readonly, nullable) NSURL *emailUrl;
 @property(nonatomic, readonly, nullable) NSString *cuisine;
diff --git a/iphone/CoreApi/CoreApi/PlacePageData/Common/PlacePageInfoData.mm b/iphone/CoreApi/CoreApi/PlacePageData/Common/PlacePageInfoData.mm
index 8e265d8ac1..22690d7f60 100644
--- a/iphone/CoreApi/CoreApi/PlacePageData/Common/PlacePageInfoData.mm
+++ b/iphone/CoreApi/CoreApi/PlacePageData/Common/PlacePageInfoData.mm
@@ -4,6 +4,8 @@
 
 #import <CoreApi/StringUtils.h>
 
+#include "indexer/validate_and_format_contacts.hpp"
+
 #include "map/place_page_info.hpp"
 
 using namespace place_page;
@@ -56,6 +58,7 @@ using namespace osm;
         case MetadataID::FMD_CONTACT_INSTAGRAM: _instagram = ToNSString(value); break;
         case MetadataID::FMD_CONTACT_TWITTER: _twitter = ToNSString(value); break;
         case MetadataID::FMD_CONTACT_VK: _vk = ToNSString(value); break;
+        case MetadataID::FMD_CONTACT_LINE: _line = ToNSString(value); break;
         case MetadataID::FMD_OPERATOR: _ppOperator = ToNSString(value); break;
         case MetadataID::FMD_INTERNET:
           _wifiAvailable = (rawData.GetInternet() == osm::Internet::No)
diff --git a/iphone/Maps/Images.xcassets/Place Page/ic_placepage_line.imageset/Contents.json b/iphone/Maps/Images.xcassets/Place Page/ic_placepage_line.imageset/Contents.json
new file mode 100644
index 0000000000..62e2d1321d
--- /dev/null
+++ b/iphone/Maps/Images.xcassets/Place Page/ic_placepage_line.imageset/Contents.json	
@@ -0,0 +1,26 @@
+{
+  "images" : [
+    {
+      "filename" : "ic_placepage_line.png",
+      "idiom" : "universal",
+      "scale" : "1x"
+    },
+    {
+      "filename" : "ic_placepage_line@2x.png",
+      "idiom" : "universal",
+      "scale" : "2x"
+    },
+    {
+      "filename" : "ic_placepage_line@3x.png",
+      "idiom" : "universal",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  },
+  "properties" : {
+    "template-rendering-intent" : "template"
+  }
+}
diff --git a/iphone/Maps/Images.xcassets/Place Page/ic_placepage_line.imageset/ic_placepage_line.png b/iphone/Maps/Images.xcassets/Place Page/ic_placepage_line.imageset/ic_placepage_line.png
new file mode 100644
index 0000000000..f7d4ffcd78
Binary files /dev/null and b/iphone/Maps/Images.xcassets/Place Page/ic_placepage_line.imageset/ic_placepage_line.png differ
diff --git a/iphone/Maps/Images.xcassets/Place Page/ic_placepage_line.imageset/ic_placepage_line@2x.png b/iphone/Maps/Images.xcassets/Place Page/ic_placepage_line.imageset/ic_placepage_line@2x.png
new file mode 100644
index 0000000000..310d02bde9
Binary files /dev/null and b/iphone/Maps/Images.xcassets/Place Page/ic_placepage_line.imageset/ic_placepage_line@2x.png differ
diff --git a/iphone/Maps/Images.xcassets/Place Page/ic_placepage_line.imageset/ic_placepage_line@3x.png b/iphone/Maps/Images.xcassets/Place Page/ic_placepage_line.imageset/ic_placepage_line@3x.png
new file mode 100644
index 0000000000..d2cb054132
Binary files /dev/null and b/iphone/Maps/Images.xcassets/Place Page/ic_placepage_line.imageset/ic_placepage_line@3x.png differ
diff --git a/iphone/Maps/UI/Editor/MWMEditorViewController.mm b/iphone/Maps/UI/Editor/MWMEditorViewController.mm
index 60307afb8a..55a20bd0f0 100644
--- a/iphone/Maps/UI/Editor/MWMEditorViewController.mm
+++ b/iphone/Maps/UI/Editor/MWMEditorViewController.mm
@@ -26,6 +26,7 @@
 #import <CoreApi/StringUtils.h>
 
 #include "platform/localization.hpp"
+#include "indexer/validate_and_format_contacts.hpp"
 
 namespace
 {
@@ -416,10 +417,15 @@ void registerCellsForTableView(std::vector<MWMEditorCellID> const & cells, UITab
                       icon:(NSString * _Nonnull)icon
                placeholder:(NSString * _Nonnull)name
 {
+  MetadataID metaId = static_cast<MetadataID>(cellID);
+  NSString* value = ToNSString(m_mapObject.GetMetadata(metaId));
+  if (osm::isSocialContactTag(metaId) && [value containsString:@"/"])
+    value = ToNSString(osm::socialContactToURL(metaId, [value UTF8String]));
+
   MWMEditorTextTableViewCell * tCell = static_cast<MWMEditorTextTableViewCell *>(cell);
   [tCell configWithDelegate:self
                        icon:[UIImage imageNamed:icon]
-                       text:ToNSString(m_mapObject.GetMetadata(static_cast<MetadataID>(cellID)))
+                       text:value
                 placeholder:name
                keyboardType:UIKeyboardTypeDefault
              capitalization:UITextAutocapitalizationTypeSentences];
@@ -662,6 +668,14 @@ void registerCellsForTableView(std::vector<MWMEditorCellID> const & cells, UITab
                  placeholder:L(@"vk")];
     break;
   }
+  case MetadataID::FMD_CONTACT_LINE:
+  {
+    [self configTextViewCell:cell
+                      cellID:cellID
+                        icon:@"ic_placepage_line"
+                 placeholder:L(@"line")];
+    break;
+  }
   case MWMEditorCellTypeNote:
   {
     MWMNoteCell * tCell = static_cast<MWMNoteCell *>(cell);
diff --git a/iphone/Maps/UI/PlacePage/Components/PlacePageInfoViewController.swift b/iphone/Maps/UI/PlacePage/Components/PlacePageInfoViewController.swift
index 8f2428e6d7..a94cddb255 100644
--- a/iphone/Maps/UI/PlacePage/Components/PlacePageInfoViewController.swift
+++ b/iphone/Maps/UI/PlacePage/Components/PlacePageInfoViewController.swift
@@ -58,6 +58,7 @@ protocol PlacePageInfoViewControllerDelegate: AnyObject {
   func didPressInstagram()
   func didPressTwitter()
   func didPressVk()
+  func didPressLine()
   func didPressEmail()
 }
 
@@ -84,6 +85,7 @@ class PlacePageInfoViewController: UIViewController {
   private var instagramView: InfoItemViewController?
   private var twitterView: InfoItemViewController?
   private var vkView: InfoItemViewController?
+  private var lineView: InfoItemViewController?
   private var cuisineView: InfoItemViewController?
   private var operatorView: InfoItemViewController?
   private var wifiView: InfoItemViewController?
@@ -166,28 +168,34 @@ class PlacePageInfoViewController: UIViewController {
     }
     
     if let facebook = placePageInfoData.facebook {
-      facebookView = createInfoItem("@" + facebook, icon: UIImage(named: "ic_placepage_facebook"), style: .link) { [weak self] in
+      facebookView = createInfoItem(facebook, icon: UIImage(named: "ic_placepage_facebook"), style: .link) { [weak self] in
         self?.delegate?.didPressFacebook()
       }
     }
     
     if let instagram = placePageInfoData.instagram {
-      instagramView = createInfoItem("@" + instagram, icon: UIImage(named: "ic_placepage_instagram"), style: .link) { [weak self] in
+      instagramView = createInfoItem(instagram, icon: UIImage(named: "ic_placepage_instagram"), style: .link) { [weak self] in
         self?.delegate?.didPressInstagram()
       }
     }
     
     if let twitter = placePageInfoData.twitter {
-      twitterView = createInfoItem("@" + twitter, icon: UIImage(named: "ic_placepage_twitter"), style: .link) { [weak self] in
+      twitterView = createInfoItem(twitter, icon: UIImage(named: "ic_placepage_twitter"), style: .link) { [weak self] in
         self?.delegate?.didPressTwitter()
       }
     }
     
     if let vk = placePageInfoData.vk {
-      vkView = createInfoItem("@" + vk, icon: UIImage(named: "ic_placepage_vk"), style: .link) { [weak self] in
+      vkView = createInfoItem(vk, icon: UIImage(named: "ic_placepage_vk"), style: .link) { [weak self] in
         self?.delegate?.didPressVk()
       }
     }
+    
+    if let line = placePageInfoData.line {
+      lineView = createInfoItem(line, icon: UIImage(named: "ic_placepage_line"), style: .link) { [weak self] in
+        self?.delegate?.didPressLine()
+      }
+    }
 
     if let address = placePageInfoData.address {
       addressView = createInfoItem(address, icon: UIImage(named: "ic_placepage_adress"))
diff --git a/iphone/Maps/UI/PlacePage/PlacePageInteractor.swift b/iphone/Maps/UI/PlacePage/PlacePageInteractor.swift
index 5eec841fcb..95cd6a50fd 100644
--- a/iphone/Maps/UI/PlacePage/PlacePageInteractor.swift
+++ b/iphone/Maps/UI/PlacePage/PlacePageInteractor.swift
@@ -57,6 +57,10 @@ extension PlacePageInteractor: PlacePageInfoViewControllerDelegate {
     MWMPlacePageManagerHelper.openVk(placePageData)
   }
   
+  func didPressLine() {
+    MWMPlacePageManagerHelper.openLine(placePageData)
+  }
+  
   func didPressEmail() {
     MWMPlacePageManagerHelper.openEmail(placePageData)
   }
diff --git a/iphone/Maps/UI/PlacePage/PlacePageManager/MWMPlacePageManager.mm b/iphone/Maps/UI/PlacePage/PlacePageManager/MWMPlacePageManager.mm
index d4d7b34603..a3f09197a7 100644
--- a/iphone/Maps/UI/PlacePage/PlacePageManager/MWMPlacePageManager.mm
+++ b/iphone/Maps/UI/PlacePage/PlacePageManager/MWMPlacePageManager.mm
@@ -10,9 +10,12 @@
 #import "location_util.h"
 
 #import <CoreApi/CoreApi.h>
+#import <CoreApi/StringUtils.h>
 
 #include "platform/downloader_defines.hpp"
 
+#include "indexer/validate_and_format_contacts.hpp"
+
 using namespace storage;
 
 @interface MWMPlacePageManager ()
@@ -238,19 +241,28 @@ using namespace storage;
 }
 
 - (void)openFacebook:(PlacePageData *)data {
-  [self.ownerViewController openUrl:[NSString stringWithFormat:@"https://m.facebook.com/%@", data.infoData.facebook]];
+  std::string const fullUrl = osm::socialContactToURL(osm::MapObject::MetadataID::FMD_CONTACT_FACEBOOK, [data.infoData.facebook UTF8String]);
+  [self.ownerViewController openUrl:ToNSString(fullUrl)];
 }
 
 - (void)openInstagram:(PlacePageData *)data {
-  [self.ownerViewController openUrl:[NSString stringWithFormat:@"https://instagram.com/%@", data.infoData.instagram]];
+  std::string const fullUrl = osm::socialContactToURL(osm::MapObject::MetadataID::FMD_CONTACT_INSTAGRAM, [data.infoData.instagram UTF8String]);
+  [self.ownerViewController openUrl:ToNSString(fullUrl)];
 }
 
 - (void)openTwitter:(PlacePageData *)data {
-  [self.ownerViewController openUrl:[NSString stringWithFormat:@"https://mobile.twitter.com/%@", data.infoData.twitter]];
+  std::string const fullUrl = osm::socialContactToURL(osm::MapObject::MetadataID::FMD_CONTACT_TWITTER, [data.infoData.twitter UTF8String]);
+  [self.ownerViewController openUrl:ToNSString(fullUrl)];
 }
 
 - (void)openVk:(PlacePageData *)data {
-  [self.ownerViewController openUrl:[NSString stringWithFormat:@"https://vk.com/%@", data.infoData.vk]];
+  std::string const fullUrl = osm::socialContactToURL(osm::MapObject::MetadataID::FMD_CONTACT_VK, [data.infoData.vk UTF8String]);
+  [self.ownerViewController openUrl:ToNSString(fullUrl)];
+}
+
+- (void)openLine:(PlacePageData *)data {
+  std::string const fullUrl = osm::socialContactToURL(osm::MapObject::MetadataID::FMD_CONTACT_LINE, [data.infoData.line UTF8String]);
+  [self.ownerViewController openUrl:ToNSString(fullUrl)];
 }
 
 - (void)openEmail:(PlacePageData *)data {
diff --git a/iphone/Maps/UI/PlacePage/PlacePageManager/MWMPlacePageManagerHelper.h b/iphone/Maps/UI/PlacePage/PlacePageManager/MWMPlacePageManagerHelper.h
index 669eea8ca2..13fffc6b67 100644
--- a/iphone/Maps/UI/PlacePage/PlacePageManager/MWMPlacePageManagerHelper.h
+++ b/iphone/Maps/UI/PlacePage/PlacePageManager/MWMPlacePageManagerHelper.h
@@ -15,6 +15,7 @@
 + (void)openInstagram:(PlacePageData *)data;
 + (void)openTwitter:(PlacePageData *)data;
 + (void)openVk:(PlacePageData *)data;
++ (void)openLine:(PlacePageData *)data;
 + (void)call:(PlacePageData *)data;
 + (void)showAllFacilities:(PlacePageData *)data;
 + (void)showPlaceDescription:(NSString *)htmlString;
diff --git a/iphone/Maps/UI/PlacePage/PlacePageManager/MWMPlacePageManagerHelper.mm b/iphone/Maps/UI/PlacePage/PlacePageManager/MWMPlacePageManagerHelper.mm
index 099d1272eb..6fe4622cda 100644
--- a/iphone/Maps/UI/PlacePage/PlacePageManager/MWMPlacePageManagerHelper.mm
+++ b/iphone/Maps/UI/PlacePage/PlacePageManager/MWMPlacePageManagerHelper.mm
@@ -22,6 +22,7 @@
 - (void)openInstagram:(PlacePageData *)data;
 - (void)openTwitter:(PlacePageData *)data;
 - (void)openVk:(PlacePageData *)data;
+- (void)openLine:(PlacePageData *)data;
 - (void)call:(PlacePageData *)data;
 - (void)showAllFacilities:(PlacePageData *)data;
 - (void)showPlaceDescription:(NSString *)htmlString;
@@ -98,6 +99,10 @@
   [[MWMMapViewControlsManager manager].placePageManager openVk:data];
 }
 
++ (void)openLine:(PlacePageData *)data {
+  [[MWMMapViewControlsManager manager].placePageManager openLine:data];
+}
+
 + (void)call:(PlacePageData *)data {
   [[MWMMapViewControlsManager manager].placePageManager call:data];
 }