diff --git a/src/core/frontend/applets/general_frontend.cpp b/src/core/frontend/applets/general_frontend.cpp
index b974f22895..c30b36de77 100644
--- a/src/core/frontend/applets/general_frontend.cpp
+++ b/src/core/frontend/applets/general_frontend.cpp
@@ -7,9 +7,38 @@
 
 namespace Core::Frontend {
 
+ParentalControlsApplet::~ParentalControlsApplet() = default;
+
+DefaultParentalControlsApplet::~DefaultParentalControlsApplet() = default;
+
+void DefaultParentalControlsApplet::VerifyPIN(std::function<void(bool)> finished,
+                                              bool suspend_future_verification_temporarily) {
+    LOG_INFO(Service_AM,
+             "Application requested frontend to verify PIN (normal), "
+             "suspend_future_verification_temporarily={}, verifying as correct.",
+             suspend_future_verification_temporarily);
+    finished(true);
+}
+
+void DefaultParentalControlsApplet::VerifyPINForSettings(std::function<void(bool)> finished) {
+    LOG_INFO(Service_AM,
+             "Application requested frontend to verify PIN (settings), verifying as correct.");
+    finished(true);
+}
+
+void DefaultParentalControlsApplet::RegisterPIN(std::function<void()> finished) {
+    LOG_INFO(Service_AM, "Application requested frontend to register new PIN");
+    finished();
+}
+
+void DefaultParentalControlsApplet::ChangePIN(std::function<void()> finished) {
+    LOG_INFO(Service_AM, "Application requested frontend to change PIN to new value");
+    finished();
+}
+
 PhotoViewerApplet::~PhotoViewerApplet() = default;
 
-DefaultPhotoViewerApplet::~DefaultPhotoViewerApplet() {}
+DefaultPhotoViewerApplet::~DefaultPhotoViewerApplet() = default;
 
 void DefaultPhotoViewerApplet::ShowPhotosForApplication(u64 title_id,
                                                         std::function<void()> finished) const {
@@ -24,4 +53,72 @@ void DefaultPhotoViewerApplet::ShowAllPhotos(std::function<void()> finished) con
     finished();
 }
 
+ECommerceApplet::~ECommerceApplet() = default;
+
+DefaultECommerceApplet::~DefaultECommerceApplet() = default;
+
+void DefaultECommerceApplet::ShowApplicationInformation(
+    std::function<void()> finished, u64 title_id, std::optional<u128> user_id,
+    std::optional<bool> full_display, std::optional<std::string> extra_parameter) {
+    const auto value = user_id.value_or(u128{});
+    LOG_INFO(Service_AM,
+             "Application requested frontend show application information for EShop, "
+             "title_id={:016X}, user_id={:016X}{:016X}, full_display={}, extra_parameter={}",
+             title_id, value[1], value[0],
+             full_display.has_value() ? fmt::format("{}", *full_display) : "null",
+             extra_parameter.value_or("null"));
+    finished();
+}
+
+void DefaultECommerceApplet::ShowAddOnContentList(std::function<void()> finished, u64 title_id,
+                                                  std::optional<u128> user_id,
+                                                  std::optional<bool> full_display) {
+    const auto value = user_id.value_or(u128{});
+    LOG_INFO(Service_AM,
+             "Application requested frontend show add on content list for EShop, "
+             "title_id={:016X}, user_id={:016X}{:016X}, full_display={}",
+             title_id, value[1], value[0],
+             full_display.has_value() ? fmt::format("{}", *full_display) : "null");
+    finished();
+}
+
+void DefaultECommerceApplet::ShowSubscriptionList(std::function<void()> finished, u64 title_id,
+                                                  std::optional<u128> user_id) {
+    const auto value = user_id.value_or(u128{});
+    LOG_INFO(Service_AM,
+             "Application requested frontend show subscription list for EShop, title_id={:016X}, "
+             "user_id={:016X}{:016X}",
+             title_id, value[1], value[0]);
+    finished();
+}
+
+void DefaultECommerceApplet::ShowConsumableItemList(std::function<void()> finished, u64 title_id,
+                                                    std::optional<u128> user_id) {
+    const auto value = user_id.value_or(u128{});
+    LOG_INFO(
+        Service_AM,
+        "Application requested frontend show consumable item list for EShop, title_id={:016X}, "
+        "user_id={:016X}{:016X}",
+        title_id, value[1], value[0]);
+    finished();
+}
+
+void DefaultECommerceApplet::ShowShopHome(std::function<void()> finished, u128 user_id,
+                                          bool full_display) {
+    LOG_INFO(Service_AM,
+             "Application requested frontend show home menu for EShop, user_id={:016X}{:016X}, "
+             "full_display={}",
+             user_id[1], user_id[0], full_display);
+    finished();
+}
+
+void DefaultECommerceApplet::ShowSettings(std::function<void()> finished, u128 user_id,
+                                          bool full_display) {
+    LOG_INFO(Service_AM,
+             "Application requested frontend show settings menu for EShop, user_id={:016X}{:016X}, "
+             "full_display={}",
+             user_id[1], user_id[0], full_display);
+    finished();
+}
+
 } // namespace Core::Frontend
diff --git a/src/core/frontend/applets/general_frontend.h b/src/core/frontend/applets/general_frontend.h
index d4506c9990..4b63f828eb 100644
--- a/src/core/frontend/applets/general_frontend.h
+++ b/src/core/frontend/applets/general_frontend.h
@@ -5,10 +5,43 @@
 #pragma once
 
 #include <functional>
+#include <optional>
 #include "common/common_types.h"
 
 namespace Core::Frontend {
 
+class ParentalControlsApplet {
+public:
+    virtual ~ParentalControlsApplet();
+
+    // Prompts the user to enter a PIN and calls the callback with whether or not it matches the
+    // correct PIN. If the bool is passed, and the PIN was recently entered correctly, the frontend
+    // should not prompt and simply return true.
+    virtual void VerifyPIN(std::function<void(bool)> finished,
+                           bool suspend_future_verification_temporarily) = 0;
+
+    // Prompts the user to enter a PIN and calls the callback for correctness. Frontends can
+    // optionally alert the user that this is to change parental controls settings.
+    virtual void VerifyPINForSettings(std::function<void(bool)> finished) = 0;
+
+    // Prompts the user to create a new PIN for pctl and stores it with the service.
+    virtual void RegisterPIN(std::function<void()> finished) = 0;
+
+    // Prompts the user to verify the current PIN and then store a new one into pctl.
+    virtual void ChangePIN(std::function<void()> finished) = 0;
+};
+
+class DefaultParentalControlsApplet final : public ParentalControlsApplet {
+public:
+    ~DefaultParentalControlsApplet() override;
+
+    void VerifyPIN(std::function<void(bool)> finished,
+                   bool suspend_future_verification_temporarily) override;
+    void VerifyPINForSettings(std::function<void(bool)> finished) override;
+    void RegisterPIN(std::function<void()> finished) override;
+    void ChangePIN(std::function<void()> finished) override;
+};
+
 class PhotoViewerApplet {
 public:
     virtual ~PhotoViewerApplet();
@@ -25,4 +58,55 @@ public:
     void ShowAllPhotos(std::function<void()> finished) const override;
 };
 
+class ECommerceApplet {
+public:
+    virtual ~ECommerceApplet();
+
+    // Shows a page with application icons, description, name, and price.
+    virtual void ShowApplicationInformation(std::function<void()> finished, u64 title_id,
+                                            std::optional<u128> user_id = {},
+                                            std::optional<bool> full_display = {},
+                                            std::optional<std::string> extra_parameter = {}) = 0;
+
+    // Shows a page with all of the add on content available for a game, with name, description, and
+    // price.
+    virtual void ShowAddOnContentList(std::function<void()> finished, u64 title_id,
+                                      std::optional<u128> user_id = {},
+                                      std::optional<bool> full_display = {}) = 0;
+
+    // Shows a page with all of the subscriptions (recurring payments) for a game, with name,
+    // description, price, and renewal period.
+    virtual void ShowSubscriptionList(std::function<void()> finished, u64 title_id,
+                                      std::optional<u128> user_id = {}) = 0;
+
+    // Shows a page with a list of any additional game related purchasable items (DLC,
+    // subscriptions, etc) for a particular game, with name, description, type, and price.
+    virtual void ShowConsumableItemList(std::function<void()> finished, u64 title_id,
+                                        std::optional<u128> user_id = {}) = 0;
+
+    // Shows the home page of the shop.
+    virtual void ShowShopHome(std::function<void()> finished, u128 user_id, bool full_display) = 0;
+
+    // Shows the user settings page of the shop.
+    virtual void ShowSettings(std::function<void()> finished, u128 user_id, bool full_display) = 0;
+};
+
+class DefaultECommerceApplet : public ECommerceApplet {
+public:
+    ~DefaultECommerceApplet() override;
+
+    void ShowApplicationInformation(std::function<void()> finished, u64 title_id,
+                                    std::optional<u128> user_id, std::optional<bool> full_display,
+                                    std::optional<std::string> extra_parameter) override;
+    void ShowAddOnContentList(std::function<void()> finished, u64 title_id,
+                              std::optional<u128> user_id,
+                              std::optional<bool> full_display) override;
+    void ShowSubscriptionList(std::function<void()> finished, u64 title_id,
+                              std::optional<u128> user_id) override;
+    void ShowConsumableItemList(std::function<void()> finished, u64 title_id,
+                                std::optional<u128> user_id) override;
+    void ShowShopHome(std::function<void()> finished, u128 user_id, bool full_display) override;
+    void ShowSettings(std::function<void()> finished, u128 user_id, bool full_display) override;
+};
+
 } // namespace Core::Frontend
diff --git a/src/core/frontend/applets/web_browser.cpp b/src/core/frontend/applets/web_browser.cpp
index 3a3d3d0bf5..528295ffcd 100644
--- a/src/core/frontend/applets/web_browser.cpp
+++ b/src/core/frontend/applets/web_browser.cpp
@@ -11,9 +11,9 @@ WebBrowserApplet::~WebBrowserApplet() = default;
 
 DefaultWebBrowserApplet::~DefaultWebBrowserApplet() = default;
 
-void DefaultWebBrowserApplet::OpenPage(std::string_view filename,
-                                       std::function<void()> unpack_romfs_callback,
-                                       std::function<void()> finished_callback) {
+void DefaultWebBrowserApplet::OpenPageLocal(std::string_view filename,
+                                            std::function<void()> unpack_romfs_callback,
+                                            std::function<void()> finished_callback) {
     LOG_INFO(Service_AM,
              "(STUBBED) called - No suitable web browser implementation found to open website page "
              "at '{}'!",
diff --git a/src/core/frontend/applets/web_browser.h b/src/core/frontend/applets/web_browser.h
index f952856af1..110e33bc49 100644
--- a/src/core/frontend/applets/web_browser.h
+++ b/src/core/frontend/applets/web_browser.h
@@ -13,16 +13,16 @@ class WebBrowserApplet {
 public:
     virtual ~WebBrowserApplet();
 
-    virtual void OpenPage(std::string_view url, std::function<void()> unpack_romfs_callback,
-                          std::function<void()> finished_callback) = 0;
+    virtual void OpenPageLocal(std::string_view url, std::function<void()> unpack_romfs_callback,
+                               std::function<void()> finished_callback) = 0;
 };
 
 class DefaultWebBrowserApplet final : public WebBrowserApplet {
 public:
     ~DefaultWebBrowserApplet() override;
 
-    void OpenPage(std::string_view url, std::function<void()> unpack_romfs_callback,
-                  std::function<void()> finished_callback) override;
+    void OpenPageLocal(std::string_view url, std::function<void()> unpack_romfs_callback,
+                       std::function<void()> finished_callback) override;
 };
 
 } // namespace Core::Frontend
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp
index 4a7bf4acb3..33cebb48b8 100644
--- a/src/core/hle/service/am/am.cpp
+++ b/src/core/hle/service/am/am.cpp
@@ -887,7 +887,9 @@ void IStorageAccessor::Read(Kernel::HLERequestContext& ctx) {
     rb.Push(RESULT_SUCCESS);
 }
 
-ILibraryAppletCreator::ILibraryAppletCreator() : ServiceFramework("ILibraryAppletCreator") {
+ILibraryAppletCreator::ILibraryAppletCreator(u64 current_process_title_id)
+    : ServiceFramework("ILibraryAppletCreator"),
+      current_process_title_id(current_process_title_id) {
     static const FunctionInfo functions[] = {
         {0, &ILibraryAppletCreator::CreateLibraryApplet, "CreateLibraryApplet"},
         {1, nullptr, "TerminateAllLibraryApplets"},
@@ -910,7 +912,7 @@ void ILibraryAppletCreator::CreateLibraryApplet(Kernel::HLERequestContext& ctx)
               static_cast<u32>(applet_id), applet_mode);
 
     const auto& applet_manager{Core::System::GetInstance().GetAppletManager()};
-    const auto applet = applet_manager.GetApplet(applet_id);
+    const auto applet = applet_manager.GetApplet(applet_id, current_process_title_id);
 
     if (applet == nullptr) {
         LOG_ERROR(Service_AM, "Applet doesn't exist! applet_id={}", static_cast<u32>(applet_id));
@@ -1234,13 +1236,13 @@ void IApplicationFunctions::GetSaveDataSize(Kernel::HLERequestContext& ctx) {
 }
 
 void InstallInterfaces(SM::ServiceManager& service_manager,
-                       std::shared_ptr<NVFlinger::NVFlinger> nvflinger) {
+                       std::shared_ptr<NVFlinger::NVFlinger> nvflinger, Core::System& system) {
     auto message_queue = std::make_shared<AppletMessageQueue>();
     message_queue->PushMessage(AppletMessageQueue::AppletMessage::FocusStateChanged); // Needed on
                                                                                       // game boot
 
-    std::make_shared<AppletAE>(nvflinger, message_queue)->InstallAsService(service_manager);
-    std::make_shared<AppletOE>(nvflinger, message_queue)->InstallAsService(service_manager);
+    std::make_shared<AppletAE>(nvflinger, message_queue, system)->InstallAsService(service_manager);
+    std::make_shared<AppletOE>(nvflinger, message_queue, system)->InstallAsService(service_manager);
     std::make_shared<IdleSys>()->InstallAsService(service_manager);
     std::make_shared<OMM>()->InstallAsService(service_manager);
     std::make_shared<SPSM>()->InstallAsService(service_manager);
diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h
index 1fa069e560..4ea609d23b 100644
--- a/src/core/hle/service/am/am.h
+++ b/src/core/hle/service/am/am.h
@@ -201,13 +201,15 @@ private:
 
 class ILibraryAppletCreator final : public ServiceFramework<ILibraryAppletCreator> {
 public:
-    ILibraryAppletCreator();
+    ILibraryAppletCreator(u64 current_process_title_id);
     ~ILibraryAppletCreator() override;
 
 private:
     void CreateLibraryApplet(Kernel::HLERequestContext& ctx);
     void CreateStorage(Kernel::HLERequestContext& ctx);
     void CreateTransferMemoryStorage(Kernel::HLERequestContext& ctx);
+
+    u64 current_process_title_id;
 };
 
 class IApplicationFunctions final : public ServiceFramework<IApplicationFunctions> {
@@ -264,7 +266,7 @@ public:
 
 /// Registers all AM services with the specified service manager.
 void InstallInterfaces(SM::ServiceManager& service_manager,
-                       std::shared_ptr<NVFlinger::NVFlinger> nvflinger);
+                       std::shared_ptr<NVFlinger::NVFlinger> nvflinger, Core::System& system);
 
 } // namespace AM
 } // namespace Service
diff --git a/src/core/hle/service/am/applet_ae.cpp b/src/core/hle/service/am/applet_ae.cpp
index 488add8e75..fe5beb8f9a 100644
--- a/src/core/hle/service/am/applet_ae.cpp
+++ b/src/core/hle/service/am/applet_ae.cpp
@@ -4,6 +4,7 @@
 
 #include "common/logging/log.h"
 #include "core/hle/ipc_helpers.h"
+#include "core/hle/kernel/process.h"
 #include "core/hle/service/am/am.h"
 #include "core/hle/service/am/applet_ae.h"
 #include "core/hle/service/nvflinger/nvflinger.h"
@@ -13,9 +14,10 @@ namespace Service::AM {
 class ILibraryAppletProxy final : public ServiceFramework<ILibraryAppletProxy> {
 public:
     explicit ILibraryAppletProxy(std::shared_ptr<NVFlinger::NVFlinger> nvflinger,
-                                 std::shared_ptr<AppletMessageQueue> msg_queue)
+                                 std::shared_ptr<AppletMessageQueue> msg_queue,
+                                 Core::System& system)
         : ServiceFramework("ILibraryAppletProxy"), nvflinger(std::move(nvflinger)),
-          msg_queue(std::move(msg_queue)) {
+          msg_queue(std::move(msg_queue)), system(system) {
         // clang-format off
         static const FunctionInfo functions[] = {
             {0, &ILibraryAppletProxy::GetCommonStateGetter, "GetCommonStateGetter"},
@@ -96,7 +98,7 @@ private:
 
         IPC::ResponseBuilder rb{ctx, 2, 0, 1};
         rb.Push(RESULT_SUCCESS);
-        rb.PushIpcInterface<ILibraryAppletCreator>();
+        rb.PushIpcInterface<ILibraryAppletCreator>(system.CurrentProcess()->GetTitleID());
     }
 
     void GetApplicationFunctions(Kernel::HLERequestContext& ctx) {
@@ -109,14 +111,15 @@ private:
 
     std::shared_ptr<NVFlinger::NVFlinger> nvflinger;
     std::shared_ptr<AppletMessageQueue> msg_queue;
+    Core::System& system;
 };
 
 class ISystemAppletProxy final : public ServiceFramework<ISystemAppletProxy> {
 public:
     explicit ISystemAppletProxy(std::shared_ptr<NVFlinger::NVFlinger> nvflinger,
-                                std::shared_ptr<AppletMessageQueue> msg_queue)
+                                std::shared_ptr<AppletMessageQueue> msg_queue, Core::System& system)
         : ServiceFramework("ISystemAppletProxy"), nvflinger(std::move(nvflinger)),
-          msg_queue(std::move(msg_queue)) {
+          msg_queue(std::move(msg_queue)), system(system) {
         // clang-format off
         static const FunctionInfo functions[] = {
             {0, &ISystemAppletProxy::GetCommonStateGetter, "GetCommonStateGetter"},
@@ -191,7 +194,7 @@ private:
 
         IPC::ResponseBuilder rb{ctx, 2, 0, 1};
         rb.Push(RESULT_SUCCESS);
-        rb.PushIpcInterface<ILibraryAppletCreator>();
+        rb.PushIpcInterface<ILibraryAppletCreator>(system.CurrentProcess()->GetTitleID());
     }
 
     void GetHomeMenuFunctions(Kernel::HLERequestContext& ctx) {
@@ -219,6 +222,7 @@ private:
     }
     std::shared_ptr<NVFlinger::NVFlinger> nvflinger;
     std::shared_ptr<AppletMessageQueue> msg_queue;
+    Core::System& system;
 };
 
 void AppletAE::OpenSystemAppletProxy(Kernel::HLERequestContext& ctx) {
@@ -226,7 +230,7 @@ void AppletAE::OpenSystemAppletProxy(Kernel::HLERequestContext& ctx) {
 
     IPC::ResponseBuilder rb{ctx, 2, 0, 1};
     rb.Push(RESULT_SUCCESS);
-    rb.PushIpcInterface<ISystemAppletProxy>(nvflinger, msg_queue);
+    rb.PushIpcInterface<ISystemAppletProxy>(nvflinger, msg_queue, system);
 }
 
 void AppletAE::OpenLibraryAppletProxy(Kernel::HLERequestContext& ctx) {
@@ -234,7 +238,7 @@ void AppletAE::OpenLibraryAppletProxy(Kernel::HLERequestContext& ctx) {
 
     IPC::ResponseBuilder rb{ctx, 2, 0, 1};
     rb.Push(RESULT_SUCCESS);
-    rb.PushIpcInterface<ILibraryAppletProxy>(nvflinger, msg_queue);
+    rb.PushIpcInterface<ILibraryAppletProxy>(nvflinger, msg_queue, system);
 }
 
 void AppletAE::OpenLibraryAppletProxyOld(Kernel::HLERequestContext& ctx) {
@@ -242,13 +246,13 @@ void AppletAE::OpenLibraryAppletProxyOld(Kernel::HLERequestContext& ctx) {
 
     IPC::ResponseBuilder rb{ctx, 2, 0, 1};
     rb.Push(RESULT_SUCCESS);
-    rb.PushIpcInterface<ILibraryAppletProxy>(nvflinger, msg_queue);
+    rb.PushIpcInterface<ILibraryAppletProxy>(nvflinger, msg_queue, system);
 }
 
 AppletAE::AppletAE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger,
-                   std::shared_ptr<AppletMessageQueue> msg_queue)
+                   std::shared_ptr<AppletMessageQueue> msg_queue, Core::System& system)
     : ServiceFramework("appletAE"), nvflinger(std::move(nvflinger)),
-      msg_queue(std::move(msg_queue)) {
+      msg_queue(std::move(msg_queue)), system(system) {
     // clang-format off
     static const FunctionInfo functions[] = {
         {100, &AppletAE::OpenSystemAppletProxy, "OpenSystemAppletProxy"},
diff --git a/src/core/hle/service/am/applet_ae.h b/src/core/hle/service/am/applet_ae.h
index 902db26658..9e006cd9d8 100644
--- a/src/core/hle/service/am/applet_ae.h
+++ b/src/core/hle/service/am/applet_ae.h
@@ -18,7 +18,7 @@ namespace AM {
 class AppletAE final : public ServiceFramework<AppletAE> {
 public:
     explicit AppletAE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger,
-                      std::shared_ptr<AppletMessageQueue> msg_queue);
+                      std::shared_ptr<AppletMessageQueue> msg_queue, Core::System& system);
     ~AppletAE() override;
 
     const std::shared_ptr<AppletMessageQueue>& GetMessageQueue() const;
@@ -30,6 +30,7 @@ private:
 
     std::shared_ptr<NVFlinger::NVFlinger> nvflinger;
     std::shared_ptr<AppletMessageQueue> msg_queue;
+    Core::System& system;
 };
 
 } // namespace AM
diff --git a/src/core/hle/service/am/applet_oe.cpp b/src/core/hle/service/am/applet_oe.cpp
index d3a0a15689..6e255fe95b 100644
--- a/src/core/hle/service/am/applet_oe.cpp
+++ b/src/core/hle/service/am/applet_oe.cpp
@@ -4,6 +4,7 @@
 
 #include "common/logging/log.h"
 #include "core/hle/ipc_helpers.h"
+#include "core/hle/kernel/process.h"
 #include "core/hle/service/am/am.h"
 #include "core/hle/service/am/applet_oe.h"
 #include "core/hle/service/nvflinger/nvflinger.h"
@@ -13,9 +14,9 @@ namespace Service::AM {
 class IApplicationProxy final : public ServiceFramework<IApplicationProxy> {
 public:
     explicit IApplicationProxy(std::shared_ptr<NVFlinger::NVFlinger> nvflinger,
-                               std::shared_ptr<AppletMessageQueue> msg_queue)
+                               std::shared_ptr<AppletMessageQueue> msg_queue, Core::System& system)
         : ServiceFramework("IApplicationProxy"), nvflinger(std::move(nvflinger)),
-          msg_queue(std::move(msg_queue)) {
+          msg_queue(std::move(msg_queue)), system(system) {
         // clang-format off
         static const FunctionInfo functions[] = {
             {0, &IApplicationProxy::GetCommonStateGetter, "GetCommonStateGetter"},
@@ -87,7 +88,7 @@ private:
 
         IPC::ResponseBuilder rb{ctx, 2, 0, 1};
         rb.Push(RESULT_SUCCESS);
-        rb.PushIpcInterface<ILibraryAppletCreator>();
+        rb.PushIpcInterface<ILibraryAppletCreator>(system.CurrentProcess()->GetTitleID());
     }
 
     void GetApplicationFunctions(Kernel::HLERequestContext& ctx) {
@@ -100,6 +101,7 @@ private:
 
     std::shared_ptr<NVFlinger::NVFlinger> nvflinger;
     std::shared_ptr<AppletMessageQueue> msg_queue;
+    Core::System& system;
 };
 
 void AppletOE::OpenApplicationProxy(Kernel::HLERequestContext& ctx) {
@@ -107,13 +109,13 @@ void AppletOE::OpenApplicationProxy(Kernel::HLERequestContext& ctx) {
 
     IPC::ResponseBuilder rb{ctx, 2, 0, 1};
     rb.Push(RESULT_SUCCESS);
-    rb.PushIpcInterface<IApplicationProxy>(nvflinger, msg_queue);
+    rb.PushIpcInterface<IApplicationProxy>(nvflinger, msg_queue, system);
 }
 
 AppletOE::AppletOE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger,
-                   std::shared_ptr<AppletMessageQueue> msg_queue)
+                   std::shared_ptr<AppletMessageQueue> msg_queue, Core::System& system)
     : ServiceFramework("appletOE"), nvflinger(std::move(nvflinger)),
-      msg_queue(std::move(msg_queue)) {
+      msg_queue(std::move(msg_queue)), system(system) {
     static const FunctionInfo functions[] = {
         {0, &AppletOE::OpenApplicationProxy, "OpenApplicationProxy"},
     };
diff --git a/src/core/hle/service/am/applet_oe.h b/src/core/hle/service/am/applet_oe.h
index bbd0108eff..22c05419d7 100644
--- a/src/core/hle/service/am/applet_oe.h
+++ b/src/core/hle/service/am/applet_oe.h
@@ -18,7 +18,7 @@ namespace AM {
 class AppletOE final : public ServiceFramework<AppletOE> {
 public:
     explicit AppletOE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger,
-                      std::shared_ptr<AppletMessageQueue> msg_queue);
+                      std::shared_ptr<AppletMessageQueue> msg_queue, Core::System& system);
     ~AppletOE() override;
 
     const std::shared_ptr<AppletMessageQueue>& GetMessageQueue() const;
@@ -28,6 +28,7 @@ private:
 
     std::shared_ptr<NVFlinger::NVFlinger> nvflinger;
     std::shared_ptr<AppletMessageQueue> msg_queue;
+    Core::System& system;
 };
 
 } // namespace AM
diff --git a/src/core/hle/service/am/applets/applets.cpp b/src/core/hle/service/am/applets/applets.cpp
index e3e4ead03f..6bdba2468b 100644
--- a/src/core/hle/service/am/applets/applets.cpp
+++ b/src/core/hle/service/am/applets/applets.cpp
@@ -139,12 +139,14 @@ void Applet::Initialize() {
 
 AppletFrontendSet::AppletFrontendSet() = default;
 
-AppletFrontendSet::AppletFrontendSet(ErrorApplet error, PhotoViewer photo_viewer,
-                                     ProfileSelect profile_select,
-                                     SoftwareKeyboard software_keyboard, WebBrowser web_browser)
-    : error{std::move(error)}, photo_viewer{std::move(photo_viewer)}, profile_select{std::move(
-                                                                          profile_select)},
-      software_keyboard{std::move(software_keyboard)}, web_browser{std::move(web_browser)} {}
+AppletFrontendSet::AppletFrontendSet(ParentalControlsApplet parental_controls, ErrorApplet error,
+                                     PhotoViewer photo_viewer, ProfileSelect profile_select,
+                                     SoftwareKeyboard software_keyboard, WebBrowser web_browser,
+                                     ECommerceApplet e_commerce)
+    : parental_controls{std::move(parental_controls)}, error{std::move(error)},
+      photo_viewer{std::move(photo_viewer)}, profile_select{std::move(profile_select)},
+      software_keyboard{std::move(software_keyboard)}, web_browser{std::move(web_browser)},
+      e_commerce{std::move(e_commerce)} {}
 
 AppletFrontendSet::~AppletFrontendSet() = default;
 
@@ -157,6 +159,8 @@ AppletManager::AppletManager() = default;
 AppletManager::~AppletManager() = default;
 
 void AppletManager::SetAppletFrontendSet(AppletFrontendSet set) {
+    if (set.parental_controls != nullptr)
+        frontend.parental_controls = std::move(set.parental_controls);
     if (set.error != nullptr)
         frontend.error = std::move(set.error);
     if (set.photo_viewer != nullptr)
@@ -167,17 +171,21 @@ void AppletManager::SetAppletFrontendSet(AppletFrontendSet set) {
         frontend.software_keyboard = std::move(set.software_keyboard);
     if (set.web_browser != nullptr)
         frontend.web_browser = std::move(set.web_browser);
+    if (set.e_commerce != nullptr)
+        frontend.e_commerce = std::move(set.e_commerce);
 }
 
 void AppletManager::SetDefaultAppletFrontendSet() {
-    frontend.error = std::make_unique<Core::Frontend::DefaultErrorApplet>();
-    frontend.photo_viewer = std::make_unique<Core::Frontend::DefaultPhotoViewerApplet>();
-    frontend.profile_select = std::make_unique<Core::Frontend::DefaultProfileSelectApplet>();
-    frontend.software_keyboard = std::make_unique<Core::Frontend::DefaultSoftwareKeyboardApplet>();
-    frontend.web_browser = std::make_unique<Core::Frontend::DefaultWebBrowserApplet>();
+    ClearAll();
+    SetDefaultAppletsIfMissing();
 }
 
 void AppletManager::SetDefaultAppletsIfMissing() {
+    if (frontend.parental_controls == nullptr) {
+        frontend.parental_controls =
+            std::make_unique<Core::Frontend::DefaultParentalControlsApplet>();
+    }
+
     if (frontend.error == nullptr) {
         frontend.error = std::make_unique<Core::Frontend::DefaultErrorApplet>();
     }
@@ -198,14 +206,20 @@ void AppletManager::SetDefaultAppletsIfMissing() {
     if (frontend.web_browser == nullptr) {
         frontend.web_browser = std::make_unique<Core::Frontend::DefaultWebBrowserApplet>();
     }
+
+    if (frontend.e_commerce == nullptr) {
+        frontend.e_commerce = std::make_unique<Core::Frontend::DefaultECommerceApplet>();
+    }
 }
 
 void AppletManager::ClearAll() {
     frontend = {};
 }
 
-std::shared_ptr<Applet> AppletManager::GetApplet(AppletId id) const {
+std::shared_ptr<Applet> AppletManager::GetApplet(AppletId id, u64 current_process_title_id) const {
     switch (id) {
+    case AppletId::Auth:
+        return std::make_shared<Auth>(*frontend.parental_controls);
     case AppletId::Error:
         return std::make_shared<Error>(*frontend.error);
     case AppletId::ProfileSelect:
@@ -214,8 +228,11 @@ std::shared_ptr<Applet> AppletManager::GetApplet(AppletId id) const {
         return std::make_shared<SoftwareKeyboard>(*frontend.software_keyboard);
     case AppletId::PhotoViewer:
         return std::make_shared<PhotoViewer>(*frontend.photo_viewer);
+    case AppletId::LibAppletShop:
+        return std::make_shared<WebBrowser>(*frontend.web_browser, current_process_title_id,
+                                            frontend.e_commerce.get());
     case AppletId::LibAppletOff:
-        return std::make_shared<WebBrowser>(*frontend.web_browser);
+        return std::make_shared<WebBrowser>(*frontend.web_browser, current_process_title_id);
     default:
         UNIMPLEMENTED_MSG(
             "No backend implementation exists for applet_id={:02X}! Falling back to stub applet.",
diff --git a/src/core/hle/service/am/applets/applets.h b/src/core/hle/service/am/applets/applets.h
index 05ae739ca4..adc973dad0 100644
--- a/src/core/hle/service/am/applets/applets.h
+++ b/src/core/hle/service/am/applets/applets.h
@@ -13,7 +13,9 @@
 union ResultCode;
 
 namespace Core::Frontend {
+class ECommerceApplet;
 class ErrorApplet;
+class ParentalControlsApplet;
 class PhotoViewerApplet;
 class ProfileSelectApplet;
 class SoftwareKeyboardApplet;
@@ -145,15 +147,19 @@ protected:
 };
 
 struct AppletFrontendSet {
+    using ParentalControlsApplet = std::unique_ptr<Core::Frontend::ParentalControlsApplet>;
     using ErrorApplet = std::unique_ptr<Core::Frontend::ErrorApplet>;
     using PhotoViewer = std::unique_ptr<Core::Frontend::PhotoViewerApplet>;
     using ProfileSelect = std::unique_ptr<Core::Frontend::ProfileSelectApplet>;
     using SoftwareKeyboard = std::unique_ptr<Core::Frontend::SoftwareKeyboardApplet>;
     using WebBrowser = std::unique_ptr<Core::Frontend::WebBrowserApplet>;
+    using ECommerceApplet = std::unique_ptr<Core::Frontend::ECommerceApplet>;
 
     AppletFrontendSet();
-    AppletFrontendSet(ErrorApplet error, PhotoViewer photo_viewer, ProfileSelect profile_select,
-                      SoftwareKeyboard software_keyboard, WebBrowser web_browser);
+    AppletFrontendSet(ParentalControlsApplet parental_controls, ErrorApplet error,
+                      PhotoViewer photo_viewer, ProfileSelect profile_select,
+                      SoftwareKeyboard software_keyboard, WebBrowser web_browser,
+                      ECommerceApplet e_commerce);
     ~AppletFrontendSet();
 
     AppletFrontendSet(const AppletFrontendSet&) = delete;
@@ -162,11 +168,13 @@ struct AppletFrontendSet {
     AppletFrontendSet(AppletFrontendSet&&) noexcept;
     AppletFrontendSet& operator=(AppletFrontendSet&&) noexcept;
 
+    ParentalControlsApplet parental_controls;
     ErrorApplet error;
     PhotoViewer photo_viewer;
     ProfileSelect profile_select;
     SoftwareKeyboard software_keyboard;
     WebBrowser web_browser;
+    ECommerceApplet e_commerce;
 };
 
 class AppletManager {
@@ -179,7 +187,7 @@ public:
     void SetDefaultAppletsIfMissing();
     void ClearAll();
 
-    std::shared_ptr<Applet> GetApplet(AppletId id) const;
+    std::shared_ptr<Applet> GetApplet(AppletId id, u64 current_process_title_id) const;
 
 private:
     AppletFrontendSet frontend;
diff --git a/src/core/hle/service/am/applets/general_backend.cpp b/src/core/hle/service/am/applets/general_backend.cpp
index 54c155dd8e..e0def8dffd 100644
--- a/src/core/hle/service/am/applets/general_backend.cpp
+++ b/src/core/hle/service/am/applets/general_backend.cpp
@@ -17,6 +17,8 @@
 
 namespace Service::AM::Applets {
 
+constexpr ResultCode ERROR_INVALID_PIN{ErrorModule::PCTL, 221};
+
 static void LogCurrentStorage(AppletDataBroker& broker, std::string_view prefix) {
     std::unique_ptr<IStorage> storage = broker.PopNormalDataToApplet();
     for (; storage != nullptr; storage = broker.PopNormalDataToApplet()) {
@@ -35,6 +37,120 @@ static void LogCurrentStorage(AppletDataBroker& broker, std::string_view prefix)
     }
 }
 
+Auth::Auth(Core::Frontend::ParentalControlsApplet& frontend) : frontend(frontend) {}
+
+Auth::~Auth() = default;
+
+void Auth::Initialize() {
+    Applet::Initialize();
+    complete = false;
+
+    const auto storage = broker.PopNormalDataToApplet();
+    ASSERT(storage != nullptr);
+    const auto data = storage->GetData();
+    ASSERT(data.size() >= 0xC);
+
+    struct Arg {
+        INSERT_PADDING_BYTES(4);
+        AuthAppletType type;
+        u8 arg0;
+        u8 arg1;
+        u8 arg2;
+        INSERT_PADDING_BYTES(1);
+    };
+    static_assert(sizeof(Arg) == 0xC, "Arg (AuthApplet) has incorrect size.");
+
+    Arg arg{};
+    std::memcpy(&arg, data.data(), sizeof(Arg));
+
+    type = arg.type;
+    arg0 = arg.arg0;
+    arg1 = arg.arg1;
+    arg2 = arg.arg2;
+}
+
+bool Auth::TransactionComplete() const {
+    return complete;
+}
+
+ResultCode Auth::GetStatus() const {
+    return successful ? RESULT_SUCCESS : ERROR_INVALID_PIN;
+}
+
+void Auth::ExecuteInteractive() {
+    UNREACHABLE_MSG("Unexpected interactive applet data.");
+}
+
+void Auth::Execute() {
+    if (complete) {
+        return;
+    }
+
+    const auto unimplemented_log = [this] {
+        UNIMPLEMENTED_MSG("Unimplemented Auth applet type for type={:08X}, arg0={:02X}, "
+                          "arg1={:02X}, arg2={:02X}",
+                          static_cast<u32>(type), arg0, arg1, arg2);
+    };
+
+    switch (type) {
+    case AuthAppletType::ShowParentalAuthentication: {
+        const auto callback = [this](bool successful) { AuthFinished(successful); };
+
+        if (arg0 == 1 && arg1 == 0 && arg2 == 1) {
+            // ShowAuthenticatorForConfiguration
+            frontend.VerifyPINForSettings(callback);
+        } else if (arg1 == 0 && arg2 == 0) {
+            // ShowParentalAuthentication(bool)
+            frontend.VerifyPIN(callback, static_cast<bool>(arg0));
+        } else {
+            unimplemented_log();
+        }
+        break;
+    }
+    case AuthAppletType::RegisterParentalPasscode: {
+        const auto callback = [this] { AuthFinished(true); };
+
+        if (arg0 == 0 && arg1 == 0 && arg2 == 0) {
+            // RegisterParentalPasscode
+            frontend.RegisterPIN(callback);
+        } else {
+            unimplemented_log();
+        }
+        break;
+    }
+    case AuthAppletType::ChangeParentalPasscode: {
+        const auto callback = [this] { AuthFinished(true); };
+
+        if (arg0 == 0 && arg1 == 0 && arg2 == 0) {
+            // ChangeParentalPasscode
+            frontend.ChangePIN(callback);
+        } else {
+            unimplemented_log();
+        }
+        break;
+    }
+    default:
+        unimplemented_log();
+    }
+}
+
+void Auth::AuthFinished(bool successful) {
+    this->successful = successful;
+
+    struct Return {
+        ResultCode result_code;
+    };
+    static_assert(sizeof(Return) == 0x4, "Return (AuthApplet) has incorrect size.");
+
+    Return return_{GetStatus()};
+
+    std::vector<u8> out(sizeof(Return));
+    std::memcpy(out.data(), &return_, sizeof(Return));
+
+    broker.PushNormalDataFromApplet(IStorage{out});
+    broker.SignalStateChanged();
+}
+
 PhotoViewer::PhotoViewer(const Core::Frontend::PhotoViewerApplet& frontend) : frontend(frontend) {}
 
 PhotoViewer::~PhotoViewer() = default;
diff --git a/src/core/hle/service/am/applets/general_backend.h b/src/core/hle/service/am/applets/general_backend.h
index fb68a2543e..0da252044b 100644
--- a/src/core/hle/service/am/applets/general_backend.h
+++ b/src/core/hle/service/am/applets/general_backend.h
@@ -8,6 +8,36 @@
 
 namespace Service::AM::Applets {
 
+enum class AuthAppletType : u32 {
+    ShowParentalAuthentication,
+    RegisterParentalPasscode,
+    ChangeParentalPasscode,
+};
+
+class Auth final : public Applet {
+public:
+    explicit Auth(Core::Frontend::ParentalControlsApplet& frontend);
+    ~Auth() override;
+
+    void Initialize() override;
+    bool TransactionComplete() const override;
+    ResultCode GetStatus() const override;
+    void ExecuteInteractive() override;
+    void Execute() override;
+
+    void AuthFinished(bool successful = true);
+
+private:
+    Core::Frontend::ParentalControlsApplet& frontend;
+    bool complete = false;
+    bool successful = false;
+
+    AuthAppletType type = AuthAppletType::ShowParentalAuthentication;
+    u8 arg0 = 0;
+    u8 arg1 = 0;
+    u8 arg2 = 0;
+};
+
 enum class PhotoViewerAppletMode : u8 {
     CurrentApp = 0,
     AllApps = 1,
diff --git a/src/core/hle/service/am/applets/web_browser.cpp b/src/core/hle/service/am/applets/web_browser.cpp
index 7878f51361..2762e0653b 100644
--- a/src/core/hle/service/am/applets/web_browser.cpp
+++ b/src/core/hle/service/am/applets/web_browser.cpp
@@ -19,7 +19,9 @@
 #include "core/file_sys/nca_metadata.h"
 #include "core/file_sys/registered_cache.h"
 #include "core/file_sys/romfs.h"
+#include "core/file_sys/system_archive/system_archive.h"
 #include "core/file_sys/vfs_types.h"
+#include "core/frontend/applets/general_frontend.h"
 #include "core/frontend/applets/web_browser.h"
 #include "core/hle/kernel/process.h"
 #include "core/hle/service/am/applets/web_browser.h"
@@ -28,74 +30,187 @@
 
 namespace Service::AM::Applets {
 
-// TODO(DarkLordZach): There are other arguments in the WebBuffer structure that are currently not
-// parsed, for example footer mode and left stick mode. Some of these are not particularly relevant,
-// but some may be worth an implementation.
-constexpr u16 WEB_ARGUMENT_URL_TYPE = 0x6;
-
-struct WebBufferHeader {
-    u16 count;
-    INSERT_PADDING_BYTES(6);
+enum class WebArgTLVType : u16 {
+    InitialURL = 0x1,
+    ShopArgumentsURL = 0x2, ///< TODO(DarkLordZach): This is not the official name.
+    CallbackURL = 0x3,
+    CallbackableURL = 0x4,
+    ApplicationID = 0x5,
+    DocumentPath = 0x6,
+    DocumentKind = 0x7,
+    SystemDataID = 0x8,
+    ShareStartPage = 0x9,
+    Whitelist = 0xA,
+    News = 0xB,
+    UserID = 0xE,
+    AlbumEntry0 = 0xF,
+    ScreenShotEnabled = 0x10,
+    EcClientCertEnabled = 0x11,
+    Unk12 = 0x12,
+    PlayReportEnabled = 0x13,
+    Unk14 = 0x14,
+    Unk15 = 0x15,
+    BootDisplayKind = 0x17,
+    BackgroundKind = 0x18,
+    FooterEnabled = 0x19,
+    PointerEnabled = 0x1A,
+    LeftStickMode = 0x1B,
+    KeyRepeatFrame1 = 0x1C,
+    KeyRepeatFrame2 = 0x1D,
+    BootAsMediaPlayerInv = 0x1E,
+    DisplayUrlKind = 0x1F,
+    BootAsMediaPlayer = 0x21,
+    ShopJumpEnabled = 0x22,
+    MediaAutoPlayEnabled = 0x23,
+    LobbyParameter = 0x24,
+    ApplicationAlbumEntry = 0x26,
+    JsExtensionEnabled = 0x27,
+    AdditionalCommentText = 0x28,
+    TouchEnabledOnContents = 0x29,
+    UserAgentAdditionalString = 0x2A,
+    AdditionalMediaData0 = 0x2B,
+    MediaPlayerAutoCloseEnabled = 0x2C,
+    PageCacheEnabled = 0x2D,
+    WebAudioEnabled = 0x2E,
+    Unk2F = 0x2F,
+    YouTubeVideoWhitelist = 0x31,
+    FooterFixedKind = 0x32,
+    PageFadeEnabled = 0x33,
+    MediaCreatorApplicationRatingAge = 0x34,
+    BootLoadingIconEnabled = 0x35,
+    PageScrollIndicationEnabled = 0x36,
+    MediaPlayerSpeedControlEnabled = 0x37,
+    AlbumEntry1 = 0x38,
+    AlbumEntry2 = 0x39,
+    AlbumEntry3 = 0x3A,
+    AdditionalMediaData1 = 0x3B,
+    AdditionalMediaData2 = 0x3C,
+    AdditionalMediaData3 = 0x3D,
+    BootFooterButton = 0x3E,
+    OverrideWebAudioVolume = 0x3F,
+    OverrideMediaAudioVolume = 0x40,
+    BootMode = 0x41,
+    WebSessionEnabled = 0x42,
 };
-static_assert(sizeof(WebBufferHeader) == 0x8, "WebBufferHeader has incorrect size.");
 
-struct WebArgumentHeader {
-    u16 type;
+enum class ShimKind : u32 {
+    Shop = 1,
+    Login = 2,
+    Offline = 3,
+    Share = 4,
+    Web = 5,
+    Wifi = 6,
+    Lobby = 7,
+};
+
+enum class ShopWebTarget {
+    ApplicationInfo,
+    AddOnContentList,
+    SubscriptionList,
+    ConsumableItemList,
+    Home,
+    Settings,
+};
+
+namespace {
+
+constexpr std::size_t SHIM_KIND_COUNT = 0x8;
+
+struct WebArgHeader {
+    u16 count;
+    INSERT_PADDING_BYTES(2);
+    ShimKind kind;
+};
+static_assert(sizeof(WebArgHeader) == 0x8, "WebArgHeader has incorrect size.");
+
+struct WebArgTLV {
+    WebArgTLVType type;
     u16 size;
     u32 offset;
 };
-static_assert(sizeof(WebArgumentHeader) == 0x8, "WebArgumentHeader has incorrect size.");
+static_assert(sizeof(WebArgTLV) == 0x8, "WebArgTLV has incorrect size.");
 
-struct WebArgumentResult {
+struct WebCommonReturnValue {
     u32 result_code;
+    INSERT_PADDING_BYTES(0x4);
     std::array<char, 0x1000> last_url;
     u64 last_url_size;
 };
-static_assert(sizeof(WebArgumentResult) == 0x1010, "WebArgumentResult has incorrect size.");
+static_assert(sizeof(WebCommonReturnValue) == 0x1010, "WebCommonReturnValue has incorrect size.");
 
-static std::vector<u8> GetArgumentDataForTagType(const std::vector<u8>& data, u16 type) {
-    WebBufferHeader header;
-    ASSERT(sizeof(WebBufferHeader) <= data.size());
-    std::memcpy(&header, data.data(), sizeof(WebBufferHeader));
+struct WebWifiPageArg {
+    INSERT_PADDING_BYTES(4);
+    std::array<char, 0x100> connection_test_url;
+    std::array<char, 0x400> initial_url;
+    std::array<u8, 0x10> nifm_network_uuid;
+    u32 nifm_requirement;
+};
+static_assert(sizeof(WebWifiPageArg) == 0x518, "WebWifiPageArg has incorrect size.");
 
-    u64 offset = sizeof(WebBufferHeader);
-    for (u16 i = 0; i < header.count; ++i) {
-        WebArgumentHeader arg;
-        ASSERT(offset + sizeof(WebArgumentHeader) <= data.size());
-        std::memcpy(&arg, data.data() + offset, sizeof(WebArgumentHeader));
-        offset += sizeof(WebArgumentHeader);
+struct WebWifiReturnValue {
+    INSERT_PADDING_BYTES(4);
+    u32 result;
+};
+static_assert(sizeof(WebWifiReturnValue) == 0x8, "WebWifiReturnValue has incorrect size.");
 
-        if (arg.type == type) {
-            std::vector<u8> out(arg.size);
-            offset += arg.offset;
-            ASSERT(offset + arg.size <= data.size());
-            std::memcpy(out.data(), data.data() + offset, out.size());
+enum class OfflineWebSource : u32 {
+    OfflineHtmlPage = 0x1,
+    ApplicationLegalInformation = 0x2,
+    SystemDataPage = 0x3,
+};
+
+std::map<WebArgTLVType, std::vector<u8>> GetWebArguments(const std::vector<u8>& arg) {
+    if (arg.size() < sizeof(WebArgHeader))
+        return {};
+
+    WebArgHeader header{};
+    std::memcpy(&header, arg.data(), sizeof(WebArgHeader));
+
+    std::map<WebArgTLVType, std::vector<u8>> out;
+    u64 offset = sizeof(WebArgHeader);
+    for (std::size_t i = 0; i < header.count; ++i) {
+        if (arg.size() < (offset + sizeof(WebArgTLV)))
             return out;
-        }
 
-        offset += arg.offset + arg.size;
+        WebArgTLV tlv{};
+        std::memcpy(&tlv, arg.data() + offset, sizeof(WebArgTLV));
+        offset += sizeof(WebArgTLV);
+
+        offset += tlv.offset;
+        if (arg.size() < (offset + tlv.size))
+            return out;
+
+        std::vector<u8> data(tlv.size);
+        std::memcpy(data.data(), arg.data() + offset, tlv.size);
+        offset += tlv.size;
+
+        out.insert_or_assign(tlv.type, data);
     }
 
-    return {};
+    return out;
 }
 
-static FileSys::VirtualFile GetManualRomFS() {
-    auto& loader{Core::System::GetInstance().GetAppLoader()};
-
-    FileSys::VirtualFile out;
-    if (loader.ReadManualRomFS(out) == Loader::ResultStatus::Success)
-        return out;
-
+FileSys::VirtualFile GetApplicationRomFS(u64 title_id, FileSys::ContentRecordType type) {
     const auto& installed{Core::System::GetInstance().GetContentProvider()};
-    const auto res = installed.GetEntry(Core::System::GetInstance().CurrentProcess()->GetTitleID(),
-                                        FileSys::ContentRecordType::Manual);
+    const auto res = installed.GetEntry(title_id, type);
 
-    if (res != nullptr)
+    if (res != nullptr) {
         return res->GetRomFS();
+    }
+
+    if (type == FileSys::ContentRecordType::Data) {
+        return FileSys::SystemArchive::SynthesizeSystemArchive(title_id);
+    }
+
     return nullptr;
 }
 
-WebBrowser::WebBrowser(Core::Frontend::WebBrowserApplet& frontend) : frontend(frontend) {}
+} // Anonymous namespace
+
+WebBrowser::WebBrowser(Core::Frontend::WebBrowserApplet& frontend, u64 current_process_title_id,
+                       Core::Frontend::ECommerceApplet* frontend_e_commerce)
+    : frontend(frontend), frontend_e_commerce(frontend_e_commerce),
+      current_process_title_id(current_process_title_id) {}
 
 WebBrowser::~WebBrowser() = default;
 
@@ -111,24 +226,12 @@ void WebBrowser::Initialize() {
     ASSERT(web_arg_storage != nullptr);
     const auto& web_arg = web_arg_storage->GetData();
 
-    const auto url_data = GetArgumentDataForTagType(web_arg, WEB_ARGUMENT_URL_TYPE);
-    filename = Common::StringFromFixedZeroTerminatedBuffer(
-        reinterpret_cast<const char*>(url_data.data()), url_data.size());
+    ASSERT(web_arg.size() >= 0x8);
+    std::memcpy(&kind, web_arg.data() + 0x4, sizeof(ShimKind));
 
-    temporary_dir = FileUtil::SanitizePath(FileUtil::GetUserPath(FileUtil::UserPath::CacheDir) +
-                                               "web_applet_manual",
-                                           FileUtil::DirectorySeparator::PlatformDefault);
-    FileUtil::DeleteDirRecursively(temporary_dir);
+    args = GetWebArguments(web_arg);
 
-    manual_romfs = GetManualRomFS();
-    if (manual_romfs == nullptr) {
-        status = ResultCode(-1);
-        LOG_ERROR(Service_AM, "Failed to find manual for current process!");
-    }
-
-    filename =
-        FileUtil::SanitizePath(temporary_dir + DIR_SEP + "html-document" + DIR_SEP + filename,
-                               FileUtil::DirectorySeparator::PlatformDefault);
+    InitializeInternal();
 }
 
 bool WebBrowser::TransactionComplete() const {
@@ -144,24 +247,25 @@ void WebBrowser::ExecuteInteractive() {
 }
 
 void WebBrowser::Execute() {
-    if (complete)
+    if (complete) {
         return;
+    }
 
     if (status != RESULT_SUCCESS) {
         complete = true;
         return;
     }
 
-    frontend.OpenPage(filename, [this] { UnpackRomFS(); }, [this] { Finalize(); });
+    ExecuteInternal();
 }
 
 void WebBrowser::UnpackRomFS() {
     if (unpacked)
         return;
 
-    ASSERT(manual_romfs != nullptr);
+    ASSERT(offline_romfs != nullptr);
     const auto dir =
-        FileSys::ExtractRomFS(manual_romfs, FileSys::RomFSExtractionType::SingleDiscard);
+        FileSys::ExtractRomFS(offline_romfs, FileSys::RomFSExtractionType::SingleDiscard);
     const auto& vfs{Core::System::GetInstance().GetFilesystem()};
     const auto temp_dir = vfs->CreateDirectory(temporary_dir, FileSys::Mode::ReadWrite);
     FileSys::VfsRawCopyD(dir, temp_dir);
@@ -172,17 +276,275 @@ void WebBrowser::UnpackRomFS() {
 void WebBrowser::Finalize() {
     complete = true;
 
-    WebArgumentResult out{};
+    WebCommonReturnValue out{};
     out.result_code = 0;
     out.last_url_size = 0;
 
-    std::vector<u8> data(sizeof(WebArgumentResult));
-    std::memcpy(data.data(), &out, sizeof(WebArgumentResult));
+    std::vector<u8> data(sizeof(WebCommonReturnValue));
+    std::memcpy(data.data(), &out, sizeof(WebCommonReturnValue));
 
     broker.PushNormalDataFromApplet(IStorage{data});
     broker.SignalStateChanged();
 
+    if (!temporary_dir.empty() && FileUtil::IsDirectory(temporary_dir)) {
+        FileUtil::DeleteDirRecursively(temporary_dir);
+    }
+}
+
+void WebBrowser::InitializeInternal() {
+    using WebAppletInitializer = void (WebBrowser::*)();
+
+    constexpr std::array<WebAppletInitializer, SHIM_KIND_COUNT> functions{
+        nullptr, &WebBrowser::InitializeShop,
+        nullptr, &WebBrowser::InitializeOffline,
+        nullptr, nullptr,
+        nullptr, nullptr,
+    };
+
+    const auto index = static_cast<u32>(kind);
+
+    if (index > functions.size() || functions[index] == nullptr) {
+        LOG_ERROR(Service_AM, "Invalid shim_kind={:08X}", index);
+        return;
+    }
+
+    const auto function = functions[index];
+    (this->*function)();
+}
+
+void WebBrowser::ExecuteInternal() {
+    using WebAppletExecutor = void (WebBrowser::*)();
+
+    constexpr std::array<WebAppletExecutor, SHIM_KIND_COUNT> functions{
+        nullptr, &WebBrowser::ExecuteShop,
+        nullptr, &WebBrowser::ExecuteOffline,
+        nullptr, nullptr,
+        nullptr, nullptr,
+    };
+
+    const auto index = static_cast<u32>(kind);
+
+    if (index > functions.size() || functions[index] == nullptr) {
+        LOG_ERROR(Service_AM, "Invalid shim_kind={:08X}", index);
+        return;
+    }
+
+    const auto function = functions[index];
+    (this->*function)();
+}
+
+void WebBrowser::InitializeShop() {
+    if (frontend_e_commerce == nullptr) {
+        LOG_ERROR(Service_AM, "Missing ECommerce Applet frontend!");
+        status = ResultCode(-1);
+        return;
+    }
+
+    const auto user_id_data = args.find(WebArgTLVType::UserID);
+
+    user_id = std::nullopt;
+    if (user_id_data != args.end()) {
+        user_id = u128{};
+        std::memcpy(user_id->data(), user_id_data->second.data(), sizeof(u128));
+    }
+
+    const auto url = args.find(WebArgTLVType::ShopArgumentsURL);
+
+    if (url == args.end()) {
+        LOG_ERROR(Service_AM, "Missing EShop Arguments URL for initialization!");
+        status = ResultCode(-1);
+        return;
+    }
+
+    std::vector<std::string> split_query;
+    Common::SplitString(Common::StringFromFixedZeroTerminatedBuffer(
+                            reinterpret_cast<const char*>(url->second.data()), url->second.size()),
+                        '?', split_query);
+
+    // 2 -> Main URL '?' Query Parameters
+    // Less is missing info, More is malformed
+    if (split_query.size() != 2) {
+        LOG_ERROR(Service_AM, "EShop Arguments has more than one question mark, malformed");
+        status = ResultCode(-1);
+        return;
+    }
+
+    std::vector<std::string> queries;
+    Common::SplitString(split_query[1], '&', queries);
+
+    const auto split_single_query =
+        [](const std::string& in) -> std::pair<std::string, std::string> {
+        const auto index = in.find('=');
+        if (index == std::string::npos || index == in.size() - 1) {
+            return {in, ""};
+        }
+
+        return {in.substr(0, index), in.substr(index + 1)};
+    };
+
+    std::transform(queries.begin(), queries.end(),
+                   std::inserter(shop_query, std::next(shop_query.begin())), split_single_query);
+
+    const auto scene = shop_query.find("scene");
+
+    if (scene == shop_query.end()) {
+        LOG_ERROR(Service_AM, "No scene parameter was passed via shop query!");
+        status = ResultCode(-1);
+        return;
+    }
+
+    const std::map<std::string, ShopWebTarget, std::less<>> target_map{
+        {"product_detail", ShopWebTarget::ApplicationInfo},
+        {"aocs", ShopWebTarget::AddOnContentList},
+        {"subscriptions", ShopWebTarget::SubscriptionList},
+        {"consumption", ShopWebTarget::ConsumableItemList},
+        {"settings", ShopWebTarget::Settings},
+        {"top", ShopWebTarget::Home},
+    };
+
+    const auto target = target_map.find(scene->second);
+    if (target == target_map.end()) {
+        LOG_ERROR(Service_AM, "Scene for shop query is invalid! (scene={})", scene->second);
+        status = ResultCode(-1);
+        return;
+    }
+
+    shop_web_target = target->second;
+
+    const auto title_id_data = shop_query.find("dst_app_id");
+    if (title_id_data != shop_query.end()) {
+        title_id = std::stoull(title_id_data->second, nullptr, 0x10);
+    }
+
+    const auto mode_data = shop_query.find("mode");
+    if (mode_data != shop_query.end()) {
+        shop_full_display = mode_data->second == "full";
+    }
+}
+
+void WebBrowser::InitializeOffline() {
+    if (args.find(WebArgTLVType::DocumentPath) == args.end() ||
+        args.find(WebArgTLVType::DocumentKind) == args.end() ||
+        args.find(WebArgTLVType::ApplicationID) == args.end()) {
+        status = ResultCode(-1);
+        LOG_ERROR(Service_AM, "Missing necessary parameters for initialization!");
+    }
+
+    const auto url_data = args[WebArgTLVType::DocumentPath];
+    filename = Common::StringFromFixedZeroTerminatedBuffer(
+        reinterpret_cast<const char*>(url_data.data()), url_data.size());
+
+    OfflineWebSource source;
+    ASSERT(args[WebArgTLVType::DocumentKind].size() >= 4);
+    std::memcpy(&source, args[WebArgTLVType::DocumentKind].data(), sizeof(OfflineWebSource));
+
+    constexpr std::array<const char*, 3> WEB_SOURCE_NAMES{
+        "manual",
+        "legal",
+        "system",
+    };
+
+    temporary_dir =
+        FileUtil::SanitizePath(FileUtil::GetUserPath(FileUtil::UserPath::CacheDir) + "web_applet_" +
+                                   WEB_SOURCE_NAMES[static_cast<u32>(source) - 1],
+                               FileUtil::DirectorySeparator::PlatformDefault);
     FileUtil::DeleteDirRecursively(temporary_dir);
+
+    u64 title_id = 0; // 0 corresponds to current process
+    ASSERT(args[WebArgTLVType::ApplicationID].size() >= 0x8);
+    std::memcpy(&title_id, args[WebArgTLVType::ApplicationID].data(), sizeof(u64));
+    FileSys::ContentRecordType type = FileSys::ContentRecordType::Data;
+
+    switch (source) {
+    case OfflineWebSource::OfflineHtmlPage:
+        // While there is an AppID TLV field, in official SW this is always ignored.
+        title_id = 0;
+        type = FileSys::ContentRecordType::Manual;
+        break;
+    case OfflineWebSource::ApplicationLegalInformation:
+        type = FileSys::ContentRecordType::Legal;
+        break;
+    case OfflineWebSource::SystemDataPage:
+        type = FileSys::ContentRecordType::Data;
+        break;
+    }
+
+    if (title_id == 0) {
+        title_id = current_process_title_id;
+    }
+
+    offline_romfs = GetApplicationRomFS(title_id, type);
+    if (offline_romfs == nullptr) {
+        status = ResultCode(-1);
+        LOG_ERROR(Service_AM, "Failed to find offline data for request!");
+    }
+
+    std::string path_additional_directory;
+    if (source == OfflineWebSource::OfflineHtmlPage) {
+        path_additional_directory = std::string(DIR_SEP).append("html-document");
+    }
+
+    filename =
+        FileUtil::SanitizePath(temporary_dir + path_additional_directory + DIR_SEP + filename,
+                               FileUtil::DirectorySeparator::PlatformDefault);
+}
+
+void WebBrowser::ExecuteShop() {
+    const auto callback = [this]() { Finalize(); };
+
+    const auto check_optional_parameter = [this](const auto& p) {
+        if (!p.has_value()) {
+            LOG_ERROR(Service_AM, "Missing one or more necessary parameters for execution!");
+            status = ResultCode(-1);
+            return false;
+        }
+
+        return true;
+    };
+
+    switch (shop_web_target) {
+    case ShopWebTarget::ApplicationInfo:
+        if (!check_optional_parameter(title_id))
+            return;
+        frontend_e_commerce->ShowApplicationInformation(callback, *title_id, user_id,
+                                                        shop_full_display, shop_extra_parameter);
+        break;
+    case ShopWebTarget::AddOnContentList:
+        if (!check_optional_parameter(title_id))
+            return;
+        frontend_e_commerce->ShowAddOnContentList(callback, *title_id, user_id, shop_full_display);
+        break;
+    case ShopWebTarget::ConsumableItemList:
+        if (!check_optional_parameter(title_id))
+            return;
+        frontend_e_commerce->ShowConsumableItemList(callback, *title_id, user_id);
+        break;
+    case ShopWebTarget::Home:
+        if (!check_optional_parameter(user_id))
+            return;
+        if (!check_optional_parameter(shop_full_display))
+            return;
+        frontend_e_commerce->ShowShopHome(callback, *user_id, *shop_full_display);
+        break;
+    case ShopWebTarget::Settings:
+        if (!check_optional_parameter(user_id))
+            return;
+        if (!check_optional_parameter(shop_full_display))
+            return;
+        frontend_e_commerce->ShowSettings(callback, *user_id, *shop_full_display);
+        break;
+    case ShopWebTarget::SubscriptionList:
+        if (!check_optional_parameter(title_id))
+            return;
+        frontend_e_commerce->ShowSubscriptionList(callback, *title_id, user_id);
+        break;
+    default:
+        UNREACHABLE();
+    }
+}
+
+void WebBrowser::ExecuteOffline() {
+    frontend.OpenPageLocal(filename, [this] { UnpackRomFS(); }, [this] { Finalize(); });
 }
 
 } // namespace Service::AM::Applets
diff --git a/src/core/hle/service/am/applets/web_browser.h b/src/core/hle/service/am/applets/web_browser.h
index 7e0f34c7dd..870f57b645 100644
--- a/src/core/hle/service/am/applets/web_browser.h
+++ b/src/core/hle/service/am/applets/web_browser.h
@@ -4,15 +4,22 @@
 
 #pragma once
 
+#include <map>
 #include "core/file_sys/vfs_types.h"
 #include "core/hle/service/am/am.h"
 #include "core/hle/service/am/applets/applets.h"
 
 namespace Service::AM::Applets {
 
+enum class ShimKind : u32;
+enum class ShopWebTarget;
+enum class WebArgTLVType : u16;
+
 class WebBrowser final : public Applet {
 public:
-    WebBrowser(Core::Frontend::WebBrowserApplet& frontend);
+    WebBrowser(Core::Frontend::WebBrowserApplet& frontend, u64 current_process_title_id,
+               Core::Frontend::ECommerceApplet* frontend_e_commerce = nullptr);
+
     ~WebBrowser() override;
 
     void Initialize() override;
@@ -32,15 +39,41 @@ public:
     void Finalize();
 
 private:
+    void InitializeInternal();
+    void ExecuteInternal();
+
+    // Specific initializers for the types of web applets
+    void InitializeShop();
+    void InitializeOffline();
+
+    // Specific executors for the types of web applets
+    void ExecuteShop();
+    void ExecuteOffline();
+
     Core::Frontend::WebBrowserApplet& frontend;
 
+    // Extra frontends for specialized functions
+    Core::Frontend::ECommerceApplet* frontend_e_commerce;
+
     bool complete = false;
     bool unpacked = false;
     ResultCode status = RESULT_SUCCESS;
 
-    FileSys::VirtualFile manual_romfs;
+    u64 current_process_title_id;
+
+    ShimKind kind;
+    std::map<WebArgTLVType, std::vector<u8>> args;
+
+    FileSys::VirtualFile offline_romfs;
     std::string temporary_dir;
     std::string filename;
+
+    ShopWebTarget shop_web_target;
+    std::map<std::string, std::string, std::less<>> shop_query;
+    std::optional<u64> title_id = 0;
+    std::optional<u128> user_id;
+    std::optional<bool> shop_full_display;
+    std::string shop_extra_parameter;
 };
 
 } // namespace Service::AM::Applets
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp
index beae9c510d..ec9d755b73 100644
--- a/src/core/hle/service/service.cpp
+++ b/src/core/hle/service/service.cpp
@@ -204,7 +204,7 @@ void Init(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system,
     SM::ServiceManager::InstallInterfaces(sm);
 
     Account::InstallInterfaces(system);
-    AM::InstallInterfaces(*sm, nv_flinger);
+    AM::InstallInterfaces(*sm, nv_flinger, system);
     AOC::InstallInterfaces(*sm);
     APM::InstallInterfaces(*sm);
     Audio::InstallInterfaces(*sm);
diff --git a/src/yuzu/applets/web_browser.cpp b/src/yuzu/applets/web_browser.cpp
index ac80b2fa20..33f1c385d1 100644
--- a/src/yuzu/applets/web_browser.cpp
+++ b/src/yuzu/applets/web_browser.cpp
@@ -87,8 +87,8 @@ QtWebBrowser::QtWebBrowser(GMainWindow& main_window) {
 
 QtWebBrowser::~QtWebBrowser() = default;
 
-void QtWebBrowser::OpenPage(std::string_view url, std::function<void()> unpack_romfs_callback,
-                            std::function<void()> finished_callback) {
+void QtWebBrowser::OpenPageLocal(std::string_view url, std::function<void()> unpack_romfs_callback,
+                                 std::function<void()> finished_callback) {
     this->unpack_romfs_callback = std::move(unpack_romfs_callback);
     this->finished_callback = std::move(finished_callback);
 
diff --git a/src/yuzu/applets/web_browser.h b/src/yuzu/applets/web_browser.h
index 1a3d67353f..b38437e460 100644
--- a/src/yuzu/applets/web_browser.h
+++ b/src/yuzu/applets/web_browser.h
@@ -37,8 +37,8 @@ public:
     explicit QtWebBrowser(GMainWindow& main_window);
     ~QtWebBrowser() override;
 
-    void OpenPage(std::string_view url, std::function<void()> unpack_romfs_callback,
-                  std::function<void()> finished_callback) override;
+    void OpenPageLocal(std::string_view url, std::function<void()> unpack_romfs_callback,
+                       std::function<void()> finished_callback) override;
 
 signals:
     void MainWindowOpenPage(std::string_view filename, std::string_view additional_args) const;
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index 66a7080c91..47e46f574c 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -814,11 +814,13 @@ bool GMainWindow::LoadROM(const QString& filename) {
     system.SetGPUDebugContext(debug_context);
 
     system.SetAppletFrontendSet({
-        std::make_unique<QtErrorDisplay>(*this),
-        nullptr,
-        std::make_unique<QtProfileSelector>(*this),
-        std::make_unique<QtSoftwareKeyboard>(*this),
-        std::make_unique<QtWebBrowser>(*this),
+        nullptr,                                     // Parental Controls
+        std::make_unique<QtErrorDisplay>(*this),     //
+        nullptr,                                     // Photo Viewer
+        std::make_unique<QtProfileSelector>(*this),  //
+        std::make_unique<QtSoftwareKeyboard>(*this), //
+        std::make_unique<QtWebBrowser>(*this),       //
+        nullptr,                                     // E-Commerce
     });
 
     const Core::System::ResultStatus result{system.Load(*render_window, filename.toStdString())};