diff --git a/src/core/hle/service/am/applets/web_browser.cpp b/src/core/hle/service/am/applets/web_browser.cpp
index 7878f513618d3a17cb23b5bb2187e69d439bf24c..6918bda02116a516f3b529cb89a2956d94fdaa2f 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,186 @@
 
 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;
+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,
+};
+
+enum class ShimKind : u32 {
+    Shop = 1,
+    Login = 2,
+    Offline = 3,
+    Share = 4,
+    Web = 5,
+    Wifi = 6,
+    Lobby = 7,
+};
+
+constexpr std::size_t SHIM_KIND_COUNT = 0x8;
 
-struct WebBufferHeader {
+struct WebArgHeader {
     u16 count;
-    INSERT_PADDING_BYTES(6);
+    INSERT_PADDING_BYTES(2);
+    ShimKind kind;
 };
-static_assert(sizeof(WebBufferHeader) == 0x8, "WebBufferHeader has incorrect size.");
+static_assert(sizeof(WebArgHeader) == 0x8, "WebArgHeader has incorrect size.");
 
-struct WebArgumentHeader {
-    u16 type;
+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 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));
-
-    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);
-
-        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());
+static_assert(sizeof(WebCommonReturnValue) == 0x1010, "WebCommonReturnValue has incorrect size.");
+
+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.");
+
+struct WebWifiReturnValue {
+    INSERT_PADDING_BYTES(4);
+    u32 result;
+};
+static_assert(sizeof(WebWifiReturnValue) == 0x8, "WebWifiReturnValue has incorrect size.");
+
+enum class OfflineWebSource : u32 {
+    OfflineHtmlPage = 0x1,
+    ApplicationLegalInformation = 0x2,
+    SystemDataPage = 0x3,
+};
+
+enum class ShopWebTarget {
+    ApplicationInfo,
+    AddOnContentList,
+    SubscriptionList,
+    ConsumableItemList,
+    Home,
+    Settings,
+};
+
+namespace {
+
+std::map<WebArgTLVType, std::vector<u8>> GetWebArguments(const std::vector<u8>& arg) {
+    WebArgHeader header{};
+    if (arg.size() < sizeof(WebArgHeader))
+        return {};
+
+    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) {
+        WebArgTLV tlv{};
+        if (arg.size() < (offset + sizeof(WebArgTLV)))
             return out;
-        }
 
-        offset += arg.offset + arg.size;
-    }
+        std::memcpy(&tlv, arg.data() + offset, sizeof(WebArgTLV));
+        offset += sizeof(WebArgTLV);
 
-    return {};
-}
+        offset += tlv.offset;
+        if (arg.size() < (offset + tlv.size))
+            return out;
 
-static FileSys::VirtualFile GetManualRomFS() {
-    auto& loader{Core::System::GetInstance().GetAppLoader()};
+        std::vector<u8> data(tlv.size);
+        std::memcpy(data.data(), arg.data() + offset, tlv.size);
+        offset += tlv.size;
 
-    FileSys::VirtualFile out;
-    if (loader.ReadManualRomFS(out) == Loader::ResultStatus::Success)
-        return out;
+        out.insert_or_assign(tlv.type, data);
+    }
 
+    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,
+                       Core::Frontend::ECommerceApplet* frontend_e_commerce)
+    : frontend(frontend), frontend_e_commerce(frontend_e_commerce) {}
 
 WebBrowser::~WebBrowser() = default;
 
@@ -111,24 +225,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);
-
-    manual_romfs = GetManualRomFS();
-    if (manual_romfs == nullptr) {
-        status = ResultCode(-1);
-        LOG_ERROR(Service_AM, "Failed to find manual for current process!");
-    }
+    args = GetWebArguments(web_arg);
 
-    filename =
-        FileUtil::SanitizePath(temporary_dir + DIR_SEP + "html-document" + DIR_SEP + filename,
-                               FileUtil::DirectorySeparator::PlatformDefault);
+    InitializeInternal();
 }
 
 bool WebBrowser::TransactionComplete() const {
diff --git a/src/core/hle/service/am/applets/web_browser.h b/src/core/hle/service/am/applets/web_browser.h
index 7e0f34c7dd944742bcec4266cb629efda51050b2..2474675decac33b65c5127c7cef83850f867faa5 100644
--- a/src/core/hle/service/am/applets/web_browser.h
+++ b/src/core/hle/service/am/applets/web_browser.h
@@ -10,6 +10,9 @@
 
 namespace Service::AM::Applets {
 
+enum class ShimKind : u32;
+enum class WebArgTLVType : u16;
+
 class WebBrowser final : public Applet {
 public:
     WebBrowser(Core::Frontend::WebBrowserApplet& frontend);
@@ -38,7 +41,9 @@ private:
     bool unpacked = false;
     ResultCode status = RESULT_SUCCESS;
 
-    FileSys::VirtualFile manual_romfs;
+    ShimKind kind;
+    std::map<WebArgTLVType, std::vector<u8>> args;
+
     std::string temporary_dir;
     std::string filename;
 };