diff --git a/bin/dbus/cx.ring.Ring.PluginManagerInterface.xml b/bin/dbus/cx.ring.Ring.PluginManagerInterface.xml
index 2e6e32be131dd9bdfb8e0c0cb3ebb10377dabb84..ce9861241a81ba4534d5379a529cf9c7729bd483 100644
--- a/bin/dbus/cx.ring.Ring.PluginManagerInterface.xml
+++ b/bin/dbus/cx.ring.Ring.PluginManagerInterface.xml
@@ -31,9 +31,11 @@
 
         <method name="getPluginPreferences" tp:name-for-bindings="getPluginPreferences">
             <annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="VectorMapStringString"/>
-            <tp:added version="9.2.0"/>
+            <tp:added version="11.1.0"/>
             <arg type="s" name="path" direction="in">
             </arg>
+            <arg type="s" name="accountId" direction="in">
+            </arg>
             <annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="VectorMapStringString"/>
             <arg type="aa{ss}" name="PluginPreferences" direction="out" tp:type="String_String_Map">
             </arg>
@@ -43,6 +45,8 @@
             <tp:added version="9.2.0"/>
             <arg type="s" name="path" direction="in">
             </arg>
+            <arg type="s" name="accountId" direction="in">
+            </arg>
             <arg type="s" name="key" direction="in">
             </arg>
             <arg type="s" name="value" direction="in">
@@ -56,6 +60,8 @@
             <tp:added version="9.2.0"/>
             <arg type="s" name="path" direction="in">
             </arg>
+            <arg type="s" name="accountId" direction="in">
+            </arg>
             <annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="MapStringString"/>
             <arg type="a{ss}" name="preferencesValues" direction="out" tp:type="String_String_Map">
             </arg>
@@ -65,6 +71,8 @@
             <tp:added version="9.2.0"/>
             <arg type="s" name="path" direction="in">
             </arg>
+            <arg type="s" name="accountId" direction="in">
+            </arg>
             <arg type="b" name="reset" direction="out">
             </arg>
         </method>
diff --git a/bin/dbus/dbuspluginmanagerinterface.cpp b/bin/dbus/dbuspluginmanagerinterface.cpp
index 46371c8c5c18330b3ed3159e464e49125f96ae86..3fd3b021141a2041ea674986887d16357f23e4c4 100644
--- a/bin/dbus/dbuspluginmanagerinterface.cpp
+++ b/bin/dbus/dbuspluginmanagerinterface.cpp
@@ -44,29 +44,33 @@ DBusPluginManagerInterface::getPluginDetails(const std::string& path)
 }
 
 std::vector<std::map<std::string, std::string>>
-DBusPluginManagerInterface::getPluginPreferences(const std::string& path)
+DBusPluginManagerInterface::getPluginPreferences(const std::string& path,
+                                                 const std::string& accountId)
 {
-    return DRing::getPluginPreferences(path);
+    return DRing::getPluginPreferences(path, accountId);
 }
 
 bool
 DBusPluginManagerInterface::setPluginPreference(const std::string& path,
+                                                const std::string& accountId,
                                                 const std::string& key,
                                                 const std::string& value)
 {
-    return DRing::setPluginPreference(path, key, value);
+    return DRing::setPluginPreference(path, accountId, key, value);
 }
 
 std::map<std::string, std::string>
-DBusPluginManagerInterface::getPluginPreferencesValues(const std::string& path)
+DBusPluginManagerInterface::getPluginPreferencesValues(const std::string& path,
+                                                       const std::string& accountId)
 {
-    return DRing::getPluginPreferencesValues(path);
+    return DRing::getPluginPreferencesValues(path, accountId);
 }
 
 bool
-DBusPluginManagerInterface::resetPluginPreferencesValues(const std::string& path)
+DBusPluginManagerInterface::resetPluginPreferencesValues(const std::string& path,
+                                                         const std::string& accountId)
 {
-    return DRing::resetPluginPreferencesValues(path);
+    return DRing::resetPluginPreferencesValues(path, accountId);
 }
 
 auto
diff --git a/bin/dbus/dbuspluginmanagerinterface.h b/bin/dbus/dbuspluginmanagerinterface.h
index 9b3855ad1acf50646d6c7c8d4511d73112ef0d24..4fc3ce6fe4101b96fc661b443667b7981c8a110f 100644
--- a/bin/dbus/dbuspluginmanagerinterface.h
+++ b/bin/dbus/dbuspluginmanagerinterface.h
@@ -55,12 +55,15 @@ public:
     bool loadPlugin(const std::string& path);
     bool unloadPlugin(const std::string& path);
     std::map<std::string, std::string> getPluginDetails(const std::string& path);
-    std::vector<std::map<std::string, std::string>> getPluginPreferences(const std::string& path);
+    std::vector<std::map<std::string, std::string>> getPluginPreferences(
+        const std::string& path, const std::string& accountId);
     bool setPluginPreference(const std::string& path,
+                             const std::string& accountId,
                              const std::string& key,
                              const std::string& value);
-    std::map<std::string, std::string> getPluginPreferencesValues(const std::string& path);
-    bool resetPluginPreferencesValues(const std::string& path);
+    std::map<std::string, std::string> getPluginPreferencesValues(const std::string& path,
+                                                                  const std::string& accountId);
+    bool resetPluginPreferencesValues(const std::string& path, const std::string& accountId);
     std::vector<std::string> getInstalledPlugins();
     std::vector<std::string> getLoadedPlugins();
     int installPlugin(const std::string& jplPath, const bool& force);
diff --git a/bin/jni/plugin_manager_interface.i b/bin/jni/plugin_manager_interface.i
index 0f5e226da2a162b9afb35f55d09945743480f712..dfcc01ca3263e10c41eac40ad8984d595dc8c59a 100644
--- a/bin/jni/plugin_manager_interface.i
+++ b/bin/jni/plugin_manager_interface.i
@@ -27,10 +27,10 @@ namespace DRing {
 bool loadPlugin(const std::string& path);
 bool unloadPlugin(const std::string& path);
 std::map<std::string,std::string> getPluginDetails(const std::string& path);
-std::vector<std::map<std::string,std::string>> getPluginPreferences(const std::string& path);
-bool setPluginPreference(const std::string& path, const std::string& key, const std::string& value);
-std::map<std::string,std::string> getPluginPreferencesValues(const std::string& path);
-bool resetPluginPreferencesValues(const std::string& path);
+std::vector<std::map<std::string,std::string>> getPluginPreferences(const std::string& path, const std::string& accountId);
+bool setPluginPreference(const std::string& path, const std::string& accountId, const std::string& key, const std::string& value);
+std::map<std::string,std::string> getPluginPreferencesValues(const std::string& path, const std::string& accountId);
+bool resetPluginPreferencesValues(const std::string& path, const std::string& accountId);
 std::vector<std::string> getInstalledPlugins();
 std::vector<std::string> getLoadedPlugins();
 int installPlugin(const std::string& jplPath, bool force);
diff --git a/src/client/plugin_manager_interface.cpp b/src/client/plugin_manager_interface.cpp
index fc41f7a21f300f075b8a426dcb7885ad924f5ad1..0a0115a846af48e968fbc5bb29812110fdd3087e 100644
--- a/src/client/plugin_manager_interface.cpp
+++ b/src/client/plugin_manager_interface.cpp
@@ -52,26 +52,35 @@ getPluginDetails(const std::string& path)
 }
 
 std::vector<std::map<std::string, std::string>>
-getPluginPreferences(const std::string& path)
+getPluginPreferences(const std::string& path, const std::string& accountId)
 {
-    return jami::Manager::instance().getJamiPluginManager().getPluginPreferences(path);
+    return jami::Manager::instance().getJamiPluginManager().getPluginPreferences(path, accountId);
 }
 
 bool
-setPluginPreference(const std::string& path, const std::string& key, const std::string& value)
+setPluginPreference(const std::string& path,
+                    const std::string& accountId,
+                    const std::string& key,
+                    const std::string& value)
 {
-    return jami::Manager::instance().getJamiPluginManager().setPluginPreference(path, key, value);
+    return jami::Manager::instance().getJamiPluginManager().setPluginPreference(path,
+                                                                                accountId,
+                                                                                key,
+                                                                                value);
 }
 
 std::map<std::string, std::string>
-getPluginPreferencesValues(const std::string& path)
+getPluginPreferencesValues(const std::string& path, const std::string& accountId)
 {
-    return jami::Manager::instance().getJamiPluginManager().getPluginPreferencesValuesMap(path);
+    return jami::Manager::instance().getJamiPluginManager().getPluginPreferencesValuesMap(path,
+                                                                                          accountId);
 }
 bool
-resetPluginPreferencesValues(const std::string& path)
+resetPluginPreferencesValues(const std::string& path, const std::string& accountId)
 {
-    return jami::Manager::instance().getJamiPluginManager().resetPluginPreferencesValuesMap(path);
+    return jami::Manager::instance()
+        .getJamiPluginManager()
+        .resetPluginPreferencesValuesMap(path, accountId);
 }
 
 std::vector<std::string>
diff --git a/src/conference.cpp b/src/conference.cpp
index be023394b9e9de47edeb5ddb90edcbf891d039bb..9ea5af27ecb83b6be3c1c3c794abb17f0e882670 100644
--- a/src/conference.cpp
+++ b/src/conference.cpp
@@ -310,6 +310,8 @@ Conference::setLocalHostDefaultMediaSource()
 void
 Conference::createConfAVStreams()
 {
+    std::string accountId = getAccountId();
+
     auto audioMap = [](const std::shared_ptr<jami::MediaFrame>& m) -> AVFrame* {
         return std::static_pointer_cast<AudioFrame>(m)->pointer();
     };
@@ -317,9 +319,9 @@ Conference::createConfAVStreams()
     // Preview and Received
     if ((audioMixer_ = jami::getAudioInput(getConfId()))) {
         auto audioSubject = std::make_shared<MediaStreamSubject>(audioMap);
-        StreamData previewStreamData {getConfId(), false, StreamType::audio, getConfId()};
+        StreamData previewStreamData {getConfId(), false, StreamType::audio, getConfId(), accountId};
         createConfAVStream(previewStreamData, *audioMixer_, audioSubject);
-        StreamData receivedStreamData {getConfId(), true, StreamType::audio, getConfId()};
+        StreamData receivedStreamData {getConfId(), true, StreamType::audio, getConfId(), accountId};
         createConfAVStream(receivedStreamData, *audioMixer_, audioSubject);
     }
 
@@ -328,13 +330,13 @@ Conference::createConfAVStreams()
     if (videoMixer_) {
         // Review
         auto receiveSubject = std::make_shared<MediaStreamSubject>(pluginVideoMap_);
-        StreamData receiveStreamData {getConfId(), true, StreamType::video, getConfId()};
+        StreamData receiveStreamData {getConfId(), true, StreamType::video, getConfId(), accountId};
         createConfAVStream(receiveStreamData, *videoMixer_, receiveSubject);
 
         // Preview
         if (auto& videoPreview = videoMixer_->getVideoLocal()) {
             auto previewSubject = std::make_shared<MediaStreamSubject>(pluginVideoMap_);
-            StreamData previewStreamData {getConfId(), false, StreamType::video, getConfId()};
+            StreamData previewStreamData {getConfId(), false, StreamType::video, getConfId(), accountId};
             createConfAVStream(previewStreamData, *videoPreview, previewSubject);
         }
     }
@@ -1024,7 +1026,7 @@ Conference::switchInput(const std::string& input)
         // Preview
         if (auto& videoPreview = mixer->getVideoLocal()) {
             auto previewSubject = std::make_shared<MediaStreamSubject>(pluginVideoMap_);
-            StreamData previewStreamData {getConfId(), false, StreamType::video, getConfId()};
+            StreamData previewStreamData {getConfId(), false, StreamType::video, getConfId(), getAccountId()};
             createConfAVStream(previewStreamData, *videoPreview, previewSubject, true);
         }
 #endif
diff --git a/src/jami/plugin_manager_interface.h b/src/jami/plugin_manager_interface.h
index e1f4aee9f819342cfe36349fdb476dc3208a2232..f35a05a11967368c785a09ea81b5f7c21ade523c 100644
--- a/src/jami/plugin_manager_interface.h
+++ b/src/jami/plugin_manager_interface.h
@@ -38,12 +38,15 @@ DRING_PUBLIC bool loadPlugin(const std::string& path);
 DRING_PUBLIC bool unloadPlugin(const std::string& path);
 DRING_PUBLIC std::map<std::string, std::string> getPluginDetails(const std::string& path);
 DRING_PUBLIC std::vector<std::map<std::string, std::string>> getPluginPreferences(
-    const std::string& path);
+    const std::string& path, const std::string& accountId);
 DRING_PUBLIC bool setPluginPreference(const std::string& path,
+                                      const std::string& accountId,
                                       const std::string& key,
                                       const std::string& value);
-DRING_PUBLIC std::map<std::string, std::string> getPluginPreferencesValues(const std::string& path);
-DRING_PUBLIC bool resetPluginPreferencesValues(const std::string& path);
+DRING_PUBLIC std::map<std::string, std::string> getPluginPreferencesValues(
+    const std::string& path, const std::string& accountId);
+DRING_PUBLIC bool resetPluginPreferencesValues(const std::string& path,
+                                               const std::string& accountId);
 DRING_PUBLIC std::vector<std::string> getInstalledPlugins();
 DRING_PUBLIC std::vector<std::string> getLoadedPlugins();
 DRING_PUBLIC int installPlugin(const std::string& jplPath, bool force);
diff --git a/src/manager.cpp b/src/manager.cpp
index 4ce503fa2e480b8c1c1410ea9c43283fd58984c2..70cc9e2352d19a9d8db1b8ac9e7f5a447d84dd6a 100644
--- a/src/manager.cpp
+++ b/src/manager.cpp
@@ -2789,13 +2789,6 @@ Manager::loadAccountMap(const YAML::Node& node)
 #endif
 #ifdef ENABLE_PLUGIN
         pluginPreferences.unserialize(node);
-
-        if (pluginPreferences.getPluginsEnabled()) {
-            std::vector<std::string> loadedPlugins = pluginPreferences.getLoadedPlugins();
-            for (const std::string& plugin : loadedPlugins) {
-                jami::Manager::instance().getJamiPluginManager().loadPlugin(plugin);
-            }
-        }
 #endif
     } catch (const YAML::Exception& e) {
         JAMI_ERR("%s: Preferences node unserialize error: ", e.what());
@@ -2849,6 +2842,15 @@ Manager::loadAccountMap(const YAML::Node& node)
     }
     cv.wait(l, [&remaining] { return remaining == 0; });
 
+#ifdef ENABLE_PLUGIN
+    if (pluginPreferences.getPluginsEnabled()) {
+        std::vector<std::string> loadedPlugins = pluginPreferences.getLoadedPlugins();
+        for (const std::string& plugin : loadedPlugins) {
+            jami::Manager::instance().getJamiPluginManager().loadPlugin(plugin);
+        }
+    }
+#endif
+
     return errorCount;
 }
 
diff --git a/src/meson.build b/src/meson.build
index 5171da766b10c72f2e74dd1e4e0fcaa930ebe838..7a53e38dd4781ccd8e607ba4f161840ee76f28cb 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -292,6 +292,7 @@ endif
 if conf.get('ENABLE_PLUGIN')
     libjami_sources += files(
         'client/plugin_manager_interface.cpp',
+        'plugin/preferenceservicesmanager.cpp',
         'plugin/callservicesmanager.cpp',
         'plugin/chatservicesmanager.cpp',
         'plugin/jamipluginmanager.cpp',
diff --git a/src/plugin/CMakeLists.txt b/src/plugin/CMakeLists.txt
index e79748986b75bf76a188669b7992e94ea1b16cb1..968e154de73bf00fa17fa554a2eeb1a416769fc1 100644
--- a/src/plugin/CMakeLists.txt
+++ b/src/plugin/CMakeLists.txt
@@ -7,10 +7,13 @@ list (APPEND Source_Files__plugin
       "${CMAKE_CURRENT_SOURCE_DIR}/pluginmanager.cpp"
       "${CMAKE_CURRENT_SOURCE_DIR}/pluginpreferencesutils.cpp"
       "${CMAKE_CURRENT_SOURCE_DIR}/pluginsutils.cpp"
+      "${CMAKE_CURRENT_SOURCE_DIR}/preferenceservicesmanager.h"
+      "${CMAKE_CURRENT_SOURCE_DIR}/preferenceservicesmanager.cpp"
       "${CMAKE_CURRENT_SOURCE_DIR}/callservicesmanager.h"
       "${CMAKE_CURRENT_SOURCE_DIR}/callservicesmanager.cpp"
       "${CMAKE_CURRENT_SOURCE_DIR}/chatservicesmanager.h"
       "${CMAKE_CURRENT_SOURCE_DIR}/chatservicesmanager.cpp"
+      "${CMAKE_CURRENT_SOURCE_DIR}/preferencehandler.h"
       "${CMAKE_CURRENT_SOURCE_DIR}/chathandler.h"
       "${CMAKE_CURRENT_SOURCE_DIR}/jamiplugin.h"
       "${CMAKE_CURRENT_SOURCE_DIR}/jamipluginmanager.h"
diff --git a/src/plugin/Makefile.am b/src/plugin/Makefile.am
index 4ce81f7579223830e820de43358b9137bcd1d258..02b6b728fbbe5e3be82b53c80d0bb7c608a5afa1 100644
--- a/src/plugin/Makefile.am
+++ b/src/plugin/Makefile.am
@@ -3,7 +3,9 @@ if ENABLE_PLUGIN
 noinst_LTLIBRARIES += libplugin.la
 
 noinst_HEADERS += \
+	./plugin/preferenceservicesmanager.h \
 	./plugin/callservicesmanager.h \
+	./plugin/preferencehandler.h \
 	./plugin/chathandler.h \
 	./plugin/chatservicesmanager.h \
 	./plugin/jamiplugin.h \
@@ -22,7 +24,8 @@ libplugin_la_SOURCES = \
 	./plugin/pluginpreferencesutils.cpp \
 	./plugin/pluginsutils.cpp \
 	./plugin/chatservicesmanager.cpp \
-	./plugin/callservicesmanager.cpp
+	./plugin/callservicesmanager.cpp \
+	./plugin/preferenceservicesmanager.cpp
 
 libring_la_LIBADD += libplugin.la
 
diff --git a/src/plugin/callservicesmanager.cpp b/src/plugin/callservicesmanager.cpp
index 294c1e1f9b9649b6a33b30118c5c679269525bd0..79aec3bd821fe132084cb24ff2e31273982df0d5 100644
--- a/src/plugin/callservicesmanager.cpp
+++ b/src/plugin/callservicesmanager.cpp
@@ -61,7 +61,8 @@ CallServicesManager::createAVSubject(const StreamData& data, AVSubjectSPtr subje
         // toggle is true if we should automatically activate the MediaHandler.
         bool toggle = PluginPreferencesUtils::getAlwaysPreference(
             callMediaHandler->id().substr(0, found),
-            callMediaHandler->getCallMediaHandlerDetails().at("name"));
+            callMediaHandler->getCallMediaHandlerDetails().at("name"),
+            data.source);
         // toggle may be overwritten if the MediaHandler was previously activated/deactivated
         // for the given call.
         for (const auto& toggledMediaHandlerPair : mediaHandlerToggled_[data.id]) {
diff --git a/src/plugin/chatservicesmanager.cpp b/src/plugin/chatservicesmanager.cpp
index a406017e92d3d8186f651f611ec0f53d6c101452..723c2dd1cd3d1b5ee333a6c24149026fbe82c413 100644
--- a/src/plugin/chatservicesmanager.cpp
+++ b/src/plugin/chatservicesmanager.cpp
@@ -147,7 +147,8 @@ ChatServicesManager::publishMessage(pluginMessagePtr message)
         std::size_t found = chatHandler->id().find_last_of(DIR_SEPARATOR_CH);
         // toggle is true if we should automatically activate the ChatHandler.
         bool toggle = PluginPreferencesUtils::getAlwaysPreference(chatHandler->id().substr(0, found),
-                                                                  chatHandlerName);
+                                                                  chatHandlerName,
+                                                                  message->accountId);
         // toggle is overwritten if we have previously activated/deactivated the ChatHandler
         // for the given conversation.
         auto allowedIt = chatAllowDenySet.find(chatHandlerName);
diff --git a/src/plugin/jamiplugin.h b/src/plugin/jamiplugin.h
index b7510445fd1efc358bb3a5d920351cb103d01ed0..92043524bde3a67ee133df25a9384e0f1ae33f3a 100644
--- a/src/plugin/jamiplugin.h
+++ b/src/plugin/jamiplugin.h
@@ -38,8 +38,8 @@
 #define JAMI_PLUGIN_ABI_VERSION 1 // 0 doesn't exist, considered as error
 
 // JAMI_PLUGIN_API_VERSION reflects changes in Services Managers
-// (CallServicesManager and ChatServicesMangers) and in JAMI_PluginAPI.
-#define JAMI_PLUGIN_API_VERSION 1 // 0 doesn't exist, considered as error
+// (CallServicesManager, ChatServicesMansge, and PreferenceServicesManagers) and in JAMI_PluginAPI.
+#define JAMI_PLUGIN_API_VERSION 2 // 0 doesn't exist, considered as error
 
 C_INTERFACE_START;
 
diff --git a/src/plugin/jamipluginmanager.cpp b/src/plugin/jamipluginmanager.cpp
index a8cde173eff9f903d7d1041ac64f1e6861d60868..5c078b5cfa5c9c304524da85a36ddf2d0674d92d 100644
--- a/src/plugin/jamipluginmanager.cpp
+++ b/src/plugin/jamipluginmanager.cpp
@@ -79,9 +79,11 @@ JamiPluginManager::getInstalledPlugins()
     std::for_each(pluginsPaths.begin(), pluginsPaths.end(), [&pluginsPath](std::string& x) {
         x = pluginsPath + DIR_SEPARATOR_CH + x;
     });
-    auto returnIterator = std::remove_if(pluginsPaths.begin(), pluginsPaths.end(), [](const std::string& path) {
-        return !PluginUtils::checkPluginValidity(path);
-    });
+    auto returnIterator = std::remove_if(pluginsPaths.begin(),
+                                         pluginsPaths.end(),
+                                         [](const std::string& path) {
+                                             return !PluginUtils::checkPluginValidity(path);
+                                         });
     pluginsPaths.erase(returnIterator, std::end(pluginsPaths));
 
     // Gets plugins installed in non standard path
@@ -106,8 +108,8 @@ JamiPluginManager::installPlugin(const std::string& jplPath, bool force)
             if (name.empty())
                 return 0;
             const std::string& version = manifestMap["version"];
-            std::string destinationDir {fileutils::get_data_dir() + DIR_SEPARATOR_CH
-                                              + "plugins" + DIR_SEPARATOR_CH + name};
+            std::string destinationDir {fileutils::get_data_dir() + DIR_SEPARATOR_CH + "plugins"
+                                        + DIR_SEPARATOR_CH + name};
             // Find if there is an existing version of this plugin
             const auto alreadyInstalledManifestMap = PluginUtils::parseManifestFile(
                 PluginUtils::manifestPath(destinationDir));
@@ -163,6 +165,10 @@ JamiPluginManager::uninstallPlugin(const std::string& rootPath)
                     return -1;
                 }
             }
+            for (const auto& accId : jami::Manager::instance().getAccountList())
+                fileutils::removeAll(fileutils::get_data_dir() + DIR_SEPARATOR_CH + accId
+                                     + DIR_SEPARATOR_CH + "plugins" + DIR_SEPARATOR_CH
+                                     + detailsIt->second.at("name"));
             pluginDetailsMap_.erase(detailsIt);
         }
         return fileutils::removeAll(rootPath);
@@ -223,34 +229,49 @@ JamiPluginManager::getLoadedPlugins() const
 }
 
 std::vector<std::map<std::string, std::string>>
-JamiPluginManager::getPluginPreferences(const std::string& rootPath)
+JamiPluginManager::getPluginPreferences(const std::string& rootPath, const std::string& accountId)
 {
-    return PluginPreferencesUtils::getPreferences(rootPath);
+    return PluginPreferencesUtils::getPreferences(rootPath, accountId);
 }
 
 bool
 JamiPluginManager::setPluginPreference(const std::string& rootPath,
+                                       const std::string& accountId,
                                        const std::string& key,
                                        const std::string& value)
 {
+    std::string acc = accountId;
+
+    // If we try to change a preference value linked to an account
+    // but that preference is global, we must ignore accountId and
+    // change the preference for every account
+    if (!accountId.empty()) {
+        // Get global preferences
+        auto preferences = PluginPreferencesUtils::getPreferences(rootPath, "");
+        // Check if the preference we want to change is global
+        auto it = std::find_if(preferences.cbegin(),
+                               preferences.cend(),
+                               [key](const std::map<std::string, std::string>& preference) {
+                                   return preference.at("key") == key;
+                               });
+        // Ignore accountId if global preference
+        if (it != preferences.cend())
+            acc.clear();
+    }
+
     std::map<std::string, std::string> pluginUserPreferencesMap
-        = PluginPreferencesUtils::getUserPreferencesValuesMap(rootPath);
+        = PluginPreferencesUtils::getUserPreferencesValuesMap(rootPath, acc);
     std::map<std::string, std::string> pluginPreferencesMap
-        = PluginPreferencesUtils::getPreferencesValuesMap(rootPath);
+        = PluginPreferencesUtils::getPreferencesValuesMap(rootPath, acc);
 
-    std::vector<std::map<std::string, std::string>> preferences
-        = PluginPreferencesUtils::getPreferences(rootPath);
     // If any plugin handler is active we may have to reload it
     bool force {pm_.checkLoadedPlugin(rootPath)};
 
     // We check if the preference is modified without having to reload plugin
-    for (auto& preference : preferences) {
-        if (!preference["key"].compare(key)) {
-            force &= callsm_.setPreference(key, value, rootPath);
-            force &= chatsm_.setPreference(key, value, rootPath);
-            break;
-        }
-    }
+    force &= preferencesm_.setPreference(key, value, rootPath, acc);
+    force &= callsm_.setPreference(key, value, rootPath);
+    force &= chatsm_.setPreference(key, value, rootPath);
+
     if (force)
         unloadPlugin(rootPath);
 
@@ -258,8 +279,8 @@ JamiPluginManager::setPluginPreference(const std::string& rootPath,
     auto find = pluginPreferencesMap.find(key);
     if (find != pluginPreferencesMap.end()) {
         pluginUserPreferencesMap[key] = value;
-        const std::string preferencesValuesFilePath = PluginPreferencesUtils::valuesFilePath(
-            rootPath);
+        const std::string preferencesValuesFilePath
+            = PluginPreferencesUtils::valuesFilePath(rootPath, acc);
         std::lock_guard<std::mutex> guard(fileutils::getFileLock(preferencesValuesFilePath));
         std::ofstream fs(preferencesValuesFilePath, std::ios::binary);
         if (!fs.good()) {
@@ -285,19 +306,23 @@ JamiPluginManager::setPluginPreference(const std::string& rootPath,
 }
 
 std::map<std::string, std::string>
-JamiPluginManager::getPluginPreferencesValuesMap(const std::string& rootPath)
+JamiPluginManager::getPluginPreferencesValuesMap(const std::string& rootPath,
+                                                 const std::string& accountId)
 {
-    return PluginPreferencesUtils::getPreferencesValuesMap(rootPath);
+    return PluginPreferencesUtils::getPreferencesValuesMap(rootPath, accountId);
 }
 
 bool
-JamiPluginManager::resetPluginPreferencesValuesMap(const std::string& rootPath)
+JamiPluginManager::resetPluginPreferencesValuesMap(const std::string& rootPath,
+                                                   const std::string& accountId)
 {
+    bool acc {accountId.empty()};
     bool loaded {pm_.checkLoadedPlugin(rootPath)};
-    if (loaded)
+    if (loaded && acc)
         unloadPlugin(rootPath);
-    auto status = PluginPreferencesUtils::resetPreferencesValuesMap(rootPath);
-    if (loaded) {
+    auto status = PluginPreferencesUtils::resetPreferencesValuesMap(rootPath, accountId);
+    preferencesm_.resetPreferences(rootPath, accountId);
+    if (loaded && acc) {
         loadPlugin(rootPath);
     }
     return status;
@@ -320,5 +345,23 @@ JamiPluginManager::registerServices()
         dataPath->assign(PluginUtils::dataPath(plugin->getPath()));
         return 0;
     });
+
+    // getPluginAccPreferences is a service that allows plugins to load saved per account preferences.
+    auto getPluginAccPreferences = [](const DLPlugin* plugin, void* data) {
+        const auto path = PluginUtils::getRootPathFromSoPath(plugin->getPath());
+        auto preferencesPtr {(static_cast<PreferencesMap*>(data))};
+        if (!preferencesPtr)
+            return -1;
+
+        preferencesPtr->emplace("default",
+                                PluginPreferencesUtils::getPreferencesValuesMap(path, "default"));
+
+        for (const auto& accId : jami::Manager::instance().getAccountList())
+            preferencesPtr->emplace(accId,
+                                    PluginPreferencesUtils::getPreferencesValuesMap(path, accId));
+        return 0;
+    };
+
+    pm_.registerService("getPluginAccPreferences", getPluginAccPreferences);
 }
 } // namespace jami
diff --git a/src/plugin/jamipluginmanager.h b/src/plugin/jamipluginmanager.h
index b33ea39c1bd45f827e12805034e8c783e00507c1..974ae216c535659df162e7596a52a94914116e57 100644
--- a/src/plugin/jamipluginmanager.h
+++ b/src/plugin/jamipluginmanager.h
@@ -26,6 +26,7 @@
 
 #include "callservicesmanager.h"
 #include "chatservicesmanager.h"
+#include "preferenceservicesmanager.h"
 
 #include <vector>
 #include <map>
@@ -34,6 +35,8 @@
 
 namespace jami {
 
+using PreferencesMap = std::map<std::string, std::map<std::string, std::string>>;
+
 /**
  * @class  JamiPluginManager
  * @brief This class provides an interface to functions exposed to the
@@ -45,6 +48,7 @@ public:
     JamiPluginManager()
         : callsm_ {pm_}
         , chatsm_ {pm_}
+        , preferencesm_ {pm_}
     {
         registerServices();
     }
@@ -102,39 +106,48 @@ public:
     /**
      * @brief Returns contents of plugin's preferences.json file
      * @param rootPath
+     * @param accountId
      */
-    std::vector<std::map<std::string, std::string>> getPluginPreferences(const std::string& rootPath);
+    std::vector<std::map<std::string, std::string>> getPluginPreferences(
+        const std::string& rootPath, const std::string& accountId);
 
     /**
      * @brief Returns a Map with preferences keys and values.
      * @param rootPath
+     * @param accountId
      */
-    std::map<std::string, std::string> getPluginPreferencesValuesMap(const std::string& rootPath);
+    std::map<std::string, std::string> getPluginPreferencesValuesMap(const std::string& rootPath,
+                                                                     const std::string& accountId);
 
     /**
      * @brief Modifies a preference value by saving it to a preferences.msgpack.
      * Plugin is reloaded only if the preference cannot take effect immediately.
      * In other words, if we have to reload plugin so that preference may take effect.
      * @param rootPath
+     * @param accountId
      * @param key
      * @param value
      * @return True if success
      */
     bool setPluginPreference(const std::string& rootPath,
+                             const std::string& accountId,
                              const std::string& key,
                              const std::string& value);
 
     /**
      * @brief Reset plugin's preferences values to their defaultValues
      * @param rootPath
+     * @param accountId
      * @return True if success.
      */
-    bool resetPluginPreferencesValuesMap(const std::string& rootPath);
+    bool resetPluginPreferencesValuesMap(const std::string& rootPath, const std::string& accountId);
 
     CallServicesManager& getCallServicesManager() { return callsm_; }
 
     ChatServicesManager& getChatServicesManager() { return chatsm_; }
 
+    PreferenceServicesManager& getPreferenceServicesManager() { return preferencesm_; }
+
 private:
     NON_COPYABLE(JamiPluginManager);
 
@@ -152,5 +165,6 @@ private:
     // Services instances
     CallServicesManager callsm_;
     ChatServicesManager chatsm_;
+    PreferenceServicesManager preferencesm_;
 };
 } // namespace jami
diff --git a/src/plugin/pluginmanager.cpp b/src/plugin/pluginmanager.cpp
index 51b02a6a312037a89a0cd1ec10d11954b5b92abe..8c30afb93079c2c7725f20d104a5eb0a06fa044f 100644
--- a/src/plugin/pluginmanager.cpp
+++ b/src/plugin/pluginmanager.cpp
@@ -150,6 +150,7 @@ PluginManager::callPluginInitFunction(const std::string& path)
 
         if (!exitFunc) {
             JAMI_ERR() << "Plugin: init failed";
+            // emit signal with error message to let user know that jamid could not load plugin
             returnValue = false;
         } else {
             returnValue = true;
diff --git a/src/plugin/pluginpreferencesutils.cpp b/src/plugin/pluginpreferencesutils.cpp
index 07f2c4c552b6571de9e8b16d145485b621974532..16754c981b527f614906e73c20808e1844f2b4d0 100644
--- a/src/plugin/pluginpreferencesutils.cpp
+++ b/src/plugin/pluginpreferencesutils.cpp
@@ -30,15 +30,25 @@
 namespace jami {
 
 std::string
-PluginPreferencesUtils::getPreferencesConfigFilePath(const std::string& rootPath)
+PluginPreferencesUtils::getPreferencesConfigFilePath(const std::string& rootPath,
+                                                     const std::string& accountId)
 {
-    return rootPath + DIR_SEPARATOR_CH + "data" + DIR_SEPARATOR_CH + "preferences.json";
+    if (accountId.empty())
+        return rootPath + DIR_SEPARATOR_CH + "data" + DIR_SEPARATOR_CH + "preferences.json";
+    else
+        return rootPath + DIR_SEPARATOR_CH + "data" + DIR_SEPARATOR_CH + "accountpreferences.json";
 }
 
 std::string
-PluginPreferencesUtils::valuesFilePath(const std::string& rootPath)
+PluginPreferencesUtils::valuesFilePath(const std::string& rootPath, const std::string& accountId)
 {
-    return rootPath + DIR_SEPARATOR_CH + "preferences.msgpack";
+    if (accountId.empty() || accountId == "default")
+        return rootPath + DIR_SEPARATOR_CH + "preferences.msgpack";
+    auto pluginName = rootPath.substr(rootPath.find_last_of(DIR_SEPARATOR_CH) + 1);
+    auto dir = fileutils::get_data_dir() + DIR_SEPARATOR_CH + accountId + DIR_SEPARATOR_CH
+               + "plugins" + DIR_SEPARATOR_CH + pluginName;
+    fileutils::check_dir(dir.c_str());
+    return dir + DIR_SEPARATOR_CH + "preferences.msgpack";
 }
 
 std::string
@@ -89,9 +99,9 @@ PluginPreferencesUtils::parsePreferenceConfig(const Json::Value& jsonPreference)
 }
 
 std::vector<std::map<std::string, std::string>>
-PluginPreferencesUtils::getPreferences(const std::string& rootPath)
+PluginPreferencesUtils::getPreferences(const std::string& rootPath, const std::string& accountId)
 {
-    std::string preferenceFilePath = getPreferencesConfigFilePath(rootPath);
+    std::string preferenceFilePath = getPreferencesConfigFilePath(rootPath, accountId);
     std::lock_guard<std::mutex> guard(fileutils::getFileLock(preferenceFilePath));
     std::ifstream file(preferenceFilePath);
     Json::Value root;
@@ -142,9 +152,10 @@ PluginPreferencesUtils::getPreferences(const std::string& rootPath)
 }
 
 std::map<std::string, std::string>
-PluginPreferencesUtils::getUserPreferencesValuesMap(const std::string& rootPath)
+PluginPreferencesUtils::getUserPreferencesValuesMap(const std::string& rootPath,
+                                                    const std::string& accountId)
 {
-    const std::string preferencesValuesFilePath = valuesFilePath(rootPath);
+    const std::string preferencesValuesFilePath = valuesFilePath(rootPath, accountId);
     std::lock_guard<std::mutex> guard(fileutils::getFileLock(preferencesValuesFilePath));
     std::ifstream file(preferencesValuesFilePath, std::ios::binary);
     std::map<std::string, std::string> rmap;
@@ -177,12 +188,17 @@ PluginPreferencesUtils::getUserPreferencesValuesMap(const std::string& rootPath)
 }
 
 std::map<std::string, std::string>
-PluginPreferencesUtils::getPreferencesValuesMap(const std::string& rootPath)
+PluginPreferencesUtils::getPreferencesValuesMap(const std::string& rootPath,
+                                                const std::string& accountId)
 {
     std::map<std::string, std::string> rmap;
 
     // Read all preferences values
     std::vector<std::map<std::string, std::string>> preferences = getPreferences(rootPath);
+    auto accPrefs = getPreferences(rootPath, accountId);
+    for (const auto& item : accPrefs) {
+        preferences.push_back(item);
+    }
     for (auto& preference : preferences) {
         rmap[preference["key"]] = preference["defaultValue"];
     }
@@ -192,16 +208,24 @@ PluginPreferencesUtils::getPreferencesValuesMap(const std::string& rootPath)
         rmap[pair.first] = pair.second;
     }
 
+    if (!accountId.empty()) {
+        // If any of these preferences were modified, its value is changed before return
+        for (const auto& pair : getUserPreferencesValuesMap(rootPath, accountId)) {
+            rmap[pair.first] = pair.second;
+        }
+    }
+
     return rmap;
 }
 
 bool
-PluginPreferencesUtils::resetPreferencesValuesMap(const std::string& rootPath)
+PluginPreferencesUtils::resetPreferencesValuesMap(const std::string& rootPath,
+                                                  const std::string& accountId)
 {
     bool returnValue = true;
     std::map<std::string, std::string> pluginPreferencesMap {};
 
-    const std::string preferencesValuesFilePath = valuesFilePath(rootPath);
+    const std::string preferencesValuesFilePath = valuesFilePath(rootPath, accountId);
     std::lock_guard<std::mutex> guard(fileutils::getFileLock(preferencesValuesFilePath));
     std::ofstream fs(preferencesValuesFilePath, std::ios::binary);
     if (!fs.good()) {
@@ -270,7 +294,28 @@ void
 PluginPreferencesUtils::addAlwaysHandlerPreference(const std::string& handlerName,
                                                    const std::string& rootPath)
 {
-    std::string filePath = getPreferencesConfigFilePath(rootPath);
+    {
+        std::string filePath = getPreferencesConfigFilePath(rootPath);
+        Json::Value root;
+
+        std::lock_guard<std::mutex> guard(fileutils::getFileLock(filePath));
+        std::ifstream file(filePath);
+        Json::CharReaderBuilder rbuilder;
+        Json::Value preference;
+        rbuilder["collectComments"] = false;
+        std::string errs;
+        if (file) {
+            bool ok = Json::parseFromStream(rbuilder, file, &root, &errs);
+            if (ok && root.isArray()) {
+                // Return if preference already exists
+                for (const auto& child : root)
+                    if (child.get("key", "None").asString() == handlerName + "Always")
+                        return;
+            }
+        }
+    }
+
+    std::string filePath = getPreferencesConfigFilePath(rootPath, "acc");
     Json::Value root;
     {
         std::lock_guard<std::mutex> guard(fileutils::getFileLock(filePath));
@@ -279,8 +324,6 @@ PluginPreferencesUtils::addAlwaysHandlerPreference(const std::string& handlerNam
         Json::Value preference;
         rbuilder["collectComments"] = false;
         std::string errs;
-        std::set<std::string> keys;
-        std::vector<std::map<std::string, std::string>> preferences;
         if (file) {
             bool ok = Json::parseFromStream(rbuilder, file, &root, &errs);
             if (ok && root.isArray()) {
@@ -289,15 +332,15 @@ PluginPreferencesUtils::addAlwaysHandlerPreference(const std::string& handlerNam
                     if (child.get("key", "None").asString() == handlerName + "Always")
                         return;
             }
-            // Create preference structure otherwise
-            preference["key"] = handlerName + "Always";
-            preference["type"] = "Switch";
-            preference["defaultValue"] = "0";
-            preference["title"] = "Automatically turn " + handlerName + " on";
-            preference["summary"] = handlerName + " will take effect immediately";
-            root.append(preference);
-            file.close();
         }
+        // Create preference structure otherwise
+        preference["key"] = handlerName + "Always";
+        preference["type"] = "Switch";
+        preference["defaultValue"] = "0";
+        preference["title"] = "Automatically turn " + handlerName + " on";
+        preference["summary"] = handlerName + " will take effect immediately";
+        preference["scope"] = "accountId";
+        root.append(preference);
     }
     std::lock_guard<std::mutex> guard(fileutils::getFileLock(filePath));
     std::ofstream outFile(filePath);
@@ -309,10 +352,16 @@ PluginPreferencesUtils::addAlwaysHandlerPreference(const std::string& handlerNam
 }
 
 bool
-PluginPreferencesUtils::getAlwaysPreference(const std::string& rootPath, std::string& handlerName)
+PluginPreferencesUtils::getAlwaysPreference(const std::string& rootPath,
+                                            const std::string& handlerName,
+                                            const std::string& accountId)
 {
     auto preferences = getPreferences(rootPath);
-    auto preferencesValues = getPreferencesValuesMap(rootPath);
+    auto accPrefs = getPreferences(rootPath, accountId);
+    for (const auto& item : accPrefs) {
+        preferences.push_back(item);
+    }
+    auto preferencesValues = getPreferencesValuesMap(rootPath, accountId);
 
     for (const auto& preference : preferences) {
         auto key = preference.at("key");
diff --git a/src/plugin/pluginpreferencesutils.h b/src/plugin/pluginpreferencesutils.h
index e52e2caa92b030e5be3e85719f6c4a2d754e3f8c..b034d169c936dc651eacb595d7c58b951969ac9b 100644
--- a/src/plugin/pluginpreferencesutils.h
+++ b/src/plugin/pluginpreferencesutils.h
@@ -43,7 +43,8 @@ public:
      * @param rootPath
      * @return preference.json file path.
      */
-    static std::string getPreferencesConfigFilePath(const std::string& rootPath);
+    static std::string getPreferencesConfigFilePath(const std::string& rootPath,
+                                                    const std::string& accountId = "");
 
     /**
      * @brief Given a plugin installation path, returns the path to the
@@ -51,9 +52,11 @@ public:
      * The preference.msgpack file saves the actuall preferences values
      * if they were modified.
      * @param rootPath
+     * @param accountId
      * @return preference.msgpack file path.
      */
-    static std::string valuesFilePath(const std::string& rootPath);
+    static std::string valuesFilePath(const std::string& rootPath,
+                                      const std::string& accountId = "");
 
     /**
      * @brief Returns the path to allowdeny.msgpack file.
@@ -81,33 +84,38 @@ public:
     /**
      * @brief Reads a preference.json file from the plugin installed in rootPath.
      * @param rootPath
+     * @param accountId
      * @return std::vector<std::map<std::string, std::string>> with preferences.json content
      */
     static std::vector<std::map<std::string, std::string>> getPreferences(
-        const std::string& rootPath);
+        const std::string& rootPath, const std::string& accountId = "");
 
     /**
      * @brief Reads preferences values which were modified from defaultValue
      * @param rootPath
+     * @param accountId
      * @return Map with preference keys and actuall values.
      */
     static std::map<std::string, std::string> getUserPreferencesValuesMap(
-        const std::string& rootPath);
+        const std::string& rootPath, const std::string& accountId = "");
 
     /**
      * @brief Reads preferences values
      * @param rootPath
+     * @param accountId
      * @return Map with preference keys and actuall values.
      */
-    static std::map<std::string, std::string> getPreferencesValuesMap(const std::string& rootPath);
+    static std::map<std::string, std::string> getPreferencesValuesMap(
+        const std::string& rootPath, const std::string& accountId = "");
 
     /**
      * @brief Resets all preferences values to their defaultValues
      * by erasing all data saved in preferences.msgpack.
      * @param rootPath
+     * @param accountId
      * @return True if preferences were reset.
      */
-    static bool resetPreferencesValuesMap(const std::string& rootPath);
+    static bool resetPreferencesValuesMap(const std::string& rootPath, const std::string& accountId);
 
     /**
      * @brief Saves ChantHandlers status provided by list.
@@ -136,9 +144,12 @@ public:
      * "always" preference is True or False.
      * @param rootPath
      * @param handlerName
+     * @param accountId
      * @return True if the handler should be automatically toggled
      */
-    static bool getAlwaysPreference(const std::string& rootPath, std::string& handlerName);
+    static bool getAlwaysPreference(const std::string& rootPath,
+                                    const std::string& handlerName,
+                                    const std::string& accountId);
 
 private:
     PluginPreferencesUtils() {}
diff --git a/src/plugin/preferencehandler.h b/src/plugin/preferencehandler.h
new file mode 100644
index 0000000000000000000000000000000000000000..b094c105194b0f0c3cd0b7016df15e8f7d490f92
--- /dev/null
+++ b/src/plugin/preferencehandler.h
@@ -0,0 +1,82 @@
+/*
+ *  Copyright (C) 2021 Savoir-faire Linux Inc.
+ *
+ *  Author: Aline Gondim Santos <aline.gondimsantos@savoirfairelinux.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA.
+ */
+
+#pragma once
+
+#include <string>
+#include <map>
+
+namespace jami {
+
+/**
+ * @brief This abstract class is an API we need to implement from plugin side.
+ * In other words, a plugin functionality that handles preferences per account
+ * must start from the implementation of this class.
+ */
+class PreferenceHandler
+{
+public:
+    virtual ~PreferenceHandler() {}
+
+    /**
+     * @brief Returns a map with handler's name, iconPath, and pluginId.
+     */
+    virtual std::map<std::string, std::string> getHandlerDetails() = 0;
+
+    /**
+     * @brief If a preference can have different values depending on accountId, those values should
+     * be stored in the plugin through this function.
+     * @param accountId
+     * @param key
+     * @param value
+     */
+    virtual void setPreferenceAttribute(const std::string& accountId,
+                                        const std::string& key,
+                                        const std::string& value)
+        = 0;
+
+    /**
+     * @brief If a preference can be stored as per accountId, this function should return True.
+     * @param key
+     * @return True if preference can be changed through setPreferenceAttribute method.
+     */
+    virtual bool preferenceMapHasKey(const std::string& key) = 0;
+
+    /**
+     * @brief Reset stored preferences for given accountId.
+     * @param accountId
+     */
+    virtual void resetPreferenceAttributes(const std::string& accountId) = 0;
+
+    /**
+     * @brief Returns the dataPath of the plugin that created this PreferenceHandler.
+     */
+    std::string id() const { return id_; }
+
+    /**
+     * @brief Should be called by the PreferenceHandler creator to set the plugins id_ variable.
+     */
+    virtual void setId(const std::string& id) final { id_ = id; }
+
+private:
+    // Is the dataPath of the plugin that created this ChatHandler.
+    std::string id_;
+};
+} // namespace jami
diff --git a/src/plugin/preferenceservicesmanager.cpp b/src/plugin/preferenceservicesmanager.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..b5bff51bf80d17c3d44fe65740d81273cf7f0999
--- /dev/null
+++ b/src/plugin/preferenceservicesmanager.cpp
@@ -0,0 +1,130 @@
+/*
+ *  Copyright (C) 2021 Savoir-faire Linux Inc.
+ *
+ *  Author: Aline Gondim Santos <aline.gondimsantos@savoirfairelinux.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA.
+ */
+
+#include "preferenceservicesmanager.h"
+
+#include "pluginmanager.h"
+#include "pluginpreferencesutils.h"
+
+#include "manager.h"
+#include "sip/sipcall.h"
+#include "fileutils.h"
+#include "logger.h"
+
+namespace jami {
+
+PreferenceServicesManager::PreferenceServicesManager(PluginManager& pluginManager)
+{
+    registerComponentsLifeCycleManagers(pluginManager);
+}
+
+PreferenceServicesManager::~PreferenceServicesManager()
+{
+    handlers_.clear();
+}
+
+std::vector<std::string>
+PreferenceServicesManager::getHandlers() const
+{
+    std::vector<std::string> res;
+    res.reserve(handlers_.size());
+    for (const auto& preferenceHandler : handlers_) {
+        res.emplace_back(std::to_string((uintptr_t) preferenceHandler.get()));
+    }
+    return res;
+}
+
+std::map<std::string, std::string>
+PreferenceServicesManager::getHandlerDetails(const std::string& preferenceHandlerIdStr) const
+{
+    auto preferenceHandlerId = std::stoull(preferenceHandlerIdStr);
+    for (auto& preferenceHandler : handlers_) {
+        if ((uintptr_t) preferenceHandler.get() == preferenceHandlerId) {
+            return preferenceHandler->getHandlerDetails();
+        }
+    }
+    return {};
+}
+
+bool
+PreferenceServicesManager::setPreference(const std::string& key,
+                                         const std::string& value,
+                                         const std::string& rootPath,
+                                         const std::string& accountId)
+{
+    bool status {true};
+    for (auto& preferenceHandler : handlers_) {
+        if (preferenceHandler->id().find(rootPath) != std::string::npos) {
+            if (preferenceHandler->preferenceMapHasKey(key)) {
+                preferenceHandler->setPreferenceAttribute(accountId, key, value);
+                // We can return here since we expect plugins to have a single preferencehandler
+                return false;
+            }
+        }
+    }
+    return status;
+}
+
+void
+PreferenceServicesManager::resetPreferences(const std::string& rootPath,
+                                            const std::string& accountId)
+{
+    for (auto& preferenceHandler : handlers_) {
+        if (preferenceHandler->id().find(rootPath) != std::string::npos) {
+            preferenceHandler->resetPreferenceAttributes(accountId);
+        }
+    }
+}
+
+void
+PreferenceServicesManager::registerComponentsLifeCycleManagers(PluginManager& pluginManager)
+{
+    // registerHandler may be called by the PluginManager upon loading a plugin.
+    auto registerHandler = [this](void* data, std::mutex& pmMtx_) {
+        std::lock_guard<std::mutex> lk(pmMtx_);
+        PreferenceHandlerPtr ptr {(static_cast<PreferenceHandler*>(data))};
+
+        if (!ptr)
+            return -1;
+        handlers_.emplace_back(std::move(ptr));
+        return 0;
+    };
+
+    // unregisterHandler may be called by the PluginManager while unloading.
+    auto unregisterHandler = [this](void* data, std::mutex& pmMtx_) {
+        std::lock_guard<std::mutex> lk(pmMtx_);
+        auto handlerIt = std::find_if(handlers_.begin(),
+                                      handlers_.end(),
+                                      [data](PreferenceHandlerPtr& handler) {
+                                          return (handler.get() == data);
+                                      });
+
+        if (handlerIt != handlers_.end()) {
+            handlers_.erase(handlerIt);
+        }
+        return true;
+    };
+
+    // Services are registered to the PluginManager.
+    pluginManager.registerComponentManager("PreferenceHandlerManager",
+                                           registerHandler,
+                                           unregisterHandler);
+}
+} // namespace jami
diff --git a/src/plugin/preferenceservicesmanager.h b/src/plugin/preferenceservicesmanager.h
new file mode 100644
index 0000000000000000000000000000000000000000..7e03dd08638aade5b32053ecd3642ddc1bbfb24a
--- /dev/null
+++ b/src/plugin/preferenceservicesmanager.h
@@ -0,0 +1,102 @@
+/*
+ *  Copyright (C) 2021 Savoir-faire Linux Inc.
+ *
+ *  Author: Aline Gondim Santos <aline.gondimsantos@savoirfairelinux.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA.
+ */
+
+#pragma once
+
+#include "preferencehandler.h"
+
+#include "noncopyable.h"
+
+#include <list>
+#include <map>
+#include <tuple>
+#include <memory>
+#include <vector>
+
+namespace jami {
+
+class PluginManager;
+
+using PreferenceHandlerPtr = std::unique_ptr<PreferenceHandler>;
+
+/**
+ * @brief This class provides the interface between PreferenceHandlers
+ * and per account preferences. Besides, it stores pointers to all loaded PreferenceHandlers;
+ */
+class PreferenceServicesManager
+{
+public:
+    /**
+     * @brief Constructor registers PreferenceHandler API services to the PluginManager
+     * instance. These services will store PreferenceHandler pointers or clean them
+     * from the Plugin System once a plugin is loaded or unloaded.
+     * @param pluginManager
+     */
+    PreferenceServicesManager(PluginManager& pluginManager);
+
+    ~PreferenceServicesManager();
+
+    NON_COPYABLE(PreferenceServicesManager);
+
+    /**
+     * @brief List all PreferenceHandlers available.
+     * @return Vector with stored PreferenceHandlers pointers.
+     */
+    std::vector<std::string> getHandlers() const;
+
+    /**
+     * @brief Returns details Map from s implementation.
+     * @param preferenceHandlerIdStr
+     * @return Details map from the PreferenceHandler implementation
+     */
+    std::map<std::string, std::string> getHandlerDetails(
+        const std::string& preferenceHandlerIdStr) const;
+
+    /**
+     * @brief Sets a preference.
+     * @param key
+     * @param value
+     * @param rootPath
+     * @param accountId
+     * @return False if preference was changed.
+     */
+    bool setPreference(const std::string& key,
+                       const std::string& value,
+                       const std::string& rootPath,
+                       const std::string& accountId);
+
+    /**
+     * @brief Resets acc preferences to default values.
+     * @param rootPath
+     * @param accountId
+     */
+    void resetPreferences(const std::string& rootPath, const std::string& accountId);
+
+private:
+    /**
+     * @brief Exposes PreferenceHandlers' life cycle managers services to the main API.
+     * @param pluginManager
+     */
+    void registerComponentsLifeCycleManagers(PluginManager& pluginManager);
+
+    // Components that a plugin can register through registerPreferenceHandler service.
+    std::list<PreferenceHandlerPtr> handlers_;
+};
+} // namespace jami
diff --git a/src/plugin/streamdata.h b/src/plugin/streamdata.h
index b2be7045216172abe121bd32818a8eebdb2560be..40706c0fdc2ecf3ccfc6dc5153b7e3b92916bc4e 100644
--- a/src/plugin/streamdata.h
+++ b/src/plugin/streamdata.h
@@ -34,16 +34,19 @@ struct StreamData
      * @param callId
      * @param isReceived False if local audio/video streams
      * @param mediaType
-     * @param peerId
+     * @param conversationId
+     * @param accountId
      */
     StreamData(const std::string& callId,
                bool isReceived,
                const StreamType& mediaType,
-               const std::string& peerId)
+               const std::string& conversationId,
+               const std::string& accountId)
         : id {std::move(callId)}
         , direction {isReceived}
         , type {mediaType}
-        , source {std::move(peerId)}
+        , conversation {std::move(conversationId)}
+        , source {std::move(accountId)}
     {}
     // callId
     const std::string id;
@@ -51,8 +54,10 @@ struct StreamData
     const bool direction;
     // StreamType -> audio or video.
     const StreamType type;
-    // peerId
+    // accountId
     const std::string source;
+    // conversationId
+    const std::string conversation;
 };
 
 /**
diff --git a/src/sip/sipcall.cpp b/src/sip/sipcall.cpp
index a12f98f62359c8fa3de36c725f12c1784e34b48d..ba52bd4bf9bc1c8a84206831dc8db94a267101d3 100644
--- a/src/sip/sipcall.cpp
+++ b/src/sip/sipcall.cpp
@@ -283,14 +283,14 @@ SIPCall::createCallAVStreams()
     // Preview
     if (auto& localAudio = audioRtp->getAudioLocal()) {
         auto previewSubject = std::make_shared<MediaStreamSubject>(audioMap);
-        StreamData microStreamData {baseId, false, StreamType::audio, getPeerNumber()};
+        StreamData microStreamData {baseId, false, StreamType::audio, getPeerNumber(), getAccountId()};
         createCallAVStream(microStreamData, *localAudio, previewSubject);
     }
 
     // Receive
     if (auto& audioReceive = audioRtp->getAudioReceive()) {
         auto receiveSubject = std::make_shared<MediaStreamSubject>(audioMap);
-        StreamData phoneStreamData {baseId, true, StreamType::audio, getPeerNumber()};
+        StreamData phoneStreamData {baseId, true, StreamType::audio, getPeerNumber(), getAccountId()};
         createCallAVStream(phoneStreamData, (AVMediaStream&) *audioReceive, receiveSubject);
     }
 #ifdef ENABLE_VIDEO
@@ -306,14 +306,14 @@ SIPCall::createCallAVStreams()
         // Preview
         if (auto& videoPreview = videoRtp->getVideoLocal()) {
             auto previewSubject = std::make_shared<MediaStreamSubject>(map);
-            StreamData previewStreamData {getCallId(), false, StreamType::video, getPeerNumber()};
+            StreamData previewStreamData {getCallId(), false, StreamType::video, getPeerNumber(), getAccountId()};
             createCallAVStream(previewStreamData, *videoPreview, previewSubject);
         }
 
         // Receive
         if (auto& videoReceive = videoRtp->getVideoReceive()) {
             auto receiveSubject = std::make_shared<MediaStreamSubject>(map);
-            StreamData receiveStreamData {getCallId(), true, StreamType::video, getPeerNumber()};
+            StreamData receiveStreamData {getCallId(), true, StreamType::video, getPeerNumber(), getAccountId()};
             createCallAVStream(receiveStreamData, *videoReceive, receiveSubject);
         }
     }