diff --git a/chrome/updater/installer.cc b/chrome/updater/installer.cc
index 96206f00b0bfb..4775f82f624a8 100644
--- a/chrome/updater/installer.cc
+++ b/chrome/updater/installer.cc
@@ -19,6 +19,7 @@
 #include "base/threading/scoped_blocking_call.h"
 #include "base/time/time.h"
 #include "base/values.h"
+#include "base/version.h"
 #include "build/build_config.h"
 #include "chrome/updater/action_handler.h"
 #include "chrome/updater/constants.h"
@@ -47,7 +48,8 @@ AppInfo MakeAppInfo(UpdaterScope scope,
                     const base::FilePath& brand_path,
                     const std::string& brand_key,
                     const base::FilePath& ec_path) {
-  const base::Version pv_lookup = LookupVersion(pv_path, pv_key, pv);
+  const base::Version pv_lookup =
+      LookupVersion(scope, app_id, pv_path, pv_key, pv);
   return AppInfo(scope, app_id, LookupString(ap_path, ap_key, ap),
                  LookupString(brand_path, brand_key, brand),
                  pv_lookup.IsValid() ? pv_lookup : base::Version(kNullVersion),
diff --git a/chrome/updater/installer.h b/chrome/updater/installer.h
index fc441d31d143e..161694dd35ccc 100644
--- a/chrome/updater/installer.h
+++ b/chrome/updater/installer.h
@@ -70,8 +70,13 @@ InstallerResult RunApplicationInstaller(
 std::string LookupString(const base::FilePath& path,
                          const std::string& keyname,
                          const std::string& default_value);
-base::Version LookupVersion(const base::FilePath& path,
-                            const std::string& keyname,
+
+// Retrieves the version of the installed application. If the version cannot
+// be determined the `default_value` is returned.
+base::Version LookupVersion(UpdaterScope scope,
+                            const std::string& app_id,
+                            const base::FilePath& version_path,
+                            const std::string& version_key,
                             const base::Version& default_value);
 
 // Manages the install of one application. Some of the functions of this
diff --git a/chrome/updater/installer_linux.cc b/chrome/updater/installer_linux.cc
index eafe893ce7e08..5daf97e9951e5 100644
--- a/chrome/updater/installer_linux.cc
+++ b/chrome/updater/installer_linux.cc
@@ -5,13 +5,17 @@
 #include "chrome/updater/installer.h"
 
 #include <optional>
+#include <string>
 
+#include "base/files/file_path.h"
 #include "base/files/file_util.h"
 #include "base/logging.h"
 #include "base/process/launch.h"
 #include "base/strings/string_split.h"
 #include "base/strings/string_util.h"
+#include "base/version.h"
 #include "chrome/updater/constants.h"
+#include "chrome/updater/updater_scope.h"
 
 namespace updater {
 
@@ -65,8 +69,10 @@ std::string LookupString(const base::FilePath& path,
   return default_value;
 }
 
-base::Version LookupVersion(const base::FilePath& path,
-                            const std::string& keyname,
+base::Version LookupVersion(UpdaterScope scope,
+                            const std::string& app_id,
+                            const base::FilePath& version_path,
+                            const std::string& version_key,
                             const base::Version& default_value) {
   return default_value;
 }
diff --git a/chrome/updater/installer_mac.cc b/chrome/updater/installer_mac.cc
index ac97773fb4c59..ae6d8a2e7a17b 100644
--- a/chrome/updater/installer_mac.cc
+++ b/chrome/updater/installer_mac.cc
@@ -5,14 +5,17 @@
 #include "chrome/updater/installer.h"
 
 #include <optional>
+#include <string>
 
 #include "base/files/file_path.h"
 #include "base/functional/callback.h"
 #include "base/logging.h"
 #include "base/strings/strcat.h"
 #include "base/time/time.h"
+#include "base/version.h"
 #include "chrome/updater/constants.h"
 #include "chrome/updater/mac/install_from_archive.h"
+#include "chrome/updater/updater_scope.h"
 #include "chrome/updater/util/mac_util.h"
 
 namespace updater {
@@ -48,10 +51,13 @@ std::string LookupString(const base::FilePath& path,
   return value ? *value : default_value;
 }
 
-base::Version LookupVersion(const base::FilePath& path,
-                            const std::string& keyname,
+base::Version LookupVersion(UpdaterScope scope,
+                            const std::string& app_id,
+                            const base::FilePath& version_path,
+                            const std::string& version_key,
                             const base::Version& default_value) {
-  std::optional<std::string> value = ReadValueFromPlist(path, keyname);
+  std::optional<std::string> value =
+      ReadValueFromPlist(version_path, version_key);
   if (value) {
     base::Version value_version(*value);
     return value_version.IsValid() ? value_version : default_value;
diff --git a/chrome/updater/win/installer_api.cc b/chrome/updater/win/installer_api.cc
index 2c62bd65c2c6b..804d675965f56 100644
--- a/chrome/updater/win/installer_api.cc
+++ b/chrome/updater/win/installer_api.cc
@@ -24,6 +24,7 @@
 #include "base/threading/platform_thread.h"
 #include "base/time/time.h"
 #include "base/timer/elapsed_timer.h"
+#include "base/version.h"
 #include "base/win/registry.h"
 #include "chrome/updater/constants.h"
 #include "chrome/updater/enum_traits.h"
@@ -544,9 +545,18 @@ std::string LookupString(const base::FilePath& path,
   return default_value;
 }
 
-base::Version LookupVersion(const base::FilePath& path,
-                            const std::string& keyname,
+base::Version LookupVersion(UpdaterScope scope,
+                            const std::string& app_id,
+                            const base::FilePath& version_path,
+                            const std::string& version_key,
                             const base::Version& default_value) {
+  std::wstring pv;
+  if (base::win::RegKey(UpdaterScopeToHKeyRoot(scope),
+                        GetAppClientsKey(app_id).c_str(), Wow6432(KEY_READ))
+          .ReadValue(kRegValuePV, &pv) == ERROR_SUCCESS) {
+    base::Version value_version = base::Version(base::WideToUTF8(pv));
+    return value_version.IsValid() ? value_version : default_value;
+  }
   return default_value;
 }
 
diff --git a/chrome/updater/win/installer_api_unittest.cc b/chrome/updater/win/installer_api_unittest.cc
index 4d5f62f6cfd90..5c47783341ad2 100644
--- a/chrome/updater/win/installer_api_unittest.cc
+++ b/chrome/updater/win/installer_api_unittest.cc
@@ -7,8 +7,10 @@
 #include <optional>
 #include <string>
 
+#include "base/files/file_path.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/test_reg_util_win.h"
+#include "base/version.h"
 #include "base/win/registry.h"
 #include "chrome/updater/constants.h"
 #include "chrome/updater/updater_scope.h"
@@ -260,4 +262,52 @@ TEST_P(InstallerAPITest, ClientStateAppKeyOpen) {
   EXPECT_TRUE(ClientStateAppKeyOpen(updater_scope_, kAppId, KEY_READ));
 }
 
+TEST_P(InstallerAPITest, LookupVersionMissing) {
+  ASSERT_NO_FATAL_FAILURE(registry_override_.OverrideRegistry(
+      UpdaterScopeToHKeyRoot(updater_scope_)));
+  base::Version default_version = base::Version("1.1.1.1");
+  base::Version version =
+      LookupVersion(updater_scope_, "{4e346bdc-c3d1-460e-83d7-31555eef96c7}",
+                    base::FilePath(), "", default_version);
+  EXPECT_EQ(default_version, version);
+}
+
+TEST_P(InstallerAPITest, LookupVersionInvalid) {
+  HKEY root = UpdaterScopeToHKeyRoot(updater_scope_);
+  ASSERT_NO_FATAL_FAILURE(registry_override_.OverrideRegistry(root));
+
+  base::win::RegKey key;
+  ASSERT_EQ(
+      key.Create(root,
+                 UPDATER_KEY L"Clients\\{4e346bdc-c3d1-460e-83d7-31555eef96c7}",
+                 Wow6432(KEY_WRITE)),
+      ERROR_SUCCESS);
+  ASSERT_EQ(key.WriteValue(kRegValuePV, L"invalid"), ERROR_SUCCESS);
+
+  base::Version default_version = base::Version("1.1.1.1");
+  base::Version version =
+      LookupVersion(updater_scope_, "{4e346bdc-c3d1-460e-83d7-31555eef96c7}",
+                    base::FilePath(), "", default_version);
+  EXPECT_EQ(default_version, version);
+}
+
+TEST_P(InstallerAPITest, LookupVersionValid) {
+  HKEY root = UpdaterScopeToHKeyRoot(updater_scope_);
+  ASSERT_NO_FATAL_FAILURE(registry_override_.OverrideRegistry(root));
+
+  base::win::RegKey key;
+  ASSERT_EQ(
+      key.Create(root,
+                 UPDATER_KEY L"Clients\\{4e346bdc-c3d1-460e-83d7-31555eef96c7}",
+                 Wow6432(KEY_WRITE)),
+      ERROR_SUCCESS);
+  ASSERT_EQ(key.WriteValue(kRegValuePV, L"1.1.1.2"), ERROR_SUCCESS);
+
+  base::Version default_version = base::Version("1.1.1.1");
+  base::Version version =
+      LookupVersion(updater_scope_, "{4e346bdc-c3d1-460e-83d7-31555eef96c7}",
+                    base::FilePath(), "", default_version);
+  EXPECT_EQ(version, base::Version("1.1.1.2"));
+}
+
 }  // namespace updater
diff --git a/docs/updater/functional_spec.md b/docs/updater/functional_spec.md
index 6b2fff4c49a31..7de819d57a513 100644
--- a/docs/updater/functional_spec.md
+++ b/docs/updater/functional_spec.md
@@ -1323,6 +1323,14 @@ POSIX platforms, they will additionally lchown the existence checker path
 registered by the application to be owned by the root user. User-scope updaters
 use this as a signal that the application is managed by a system-scope updater.
 
+#### Windows
+
+Application installers are expected to register with the updater by setting
+[HKCU or HKLM]\SOFTWARE\{Company}\Update\Clients\{AppID} → pv to the installed
+version of the application. If pv is present and valid in the app's Clients
+key it will be used by the updater as the source of truth for the registered
+version.
+
 For backwards compatibility with third party software, on Windows, after a
 successful registration and on each update, the updater will set
 [HKCU or HKLM]\SOFTWARE\{Company}\Update\ClientState\{AppID} → pv to the