[PWA/NavCapture]: Create `NavigationCapturingSettings` interface

This CL aims to align CrOS and W/M/L link capturing architecture.
Currently, CrOS does not interact with the same link capturing
architecture as W/M/L since it does not set the link capturing
preferences for web_apps in the DB.

Creating a NavigationCapturingSettings interface that both W/M/L and
CrOS will have their own implementation. This is constructed as part of
the navigation_capturing_process.

The implementation for W/M/L and CrOS is taken from
GetWebAppControllingUrl which can then be removed.

More information found in design document:
https://docs.google.com/document/d/11KjFz_sUmXsPwzLRWGYEOVPV0oK1G7H2wz57EKLPmn8/edit?tab=t.0

Bug: 392712186
Change-Id: I5b1d369769a31bbaa87ca44408276212f3b5ac41
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6230494
Reviewed-by: Daniel Murphy <[email protected]>
Reviewed-by: Marijn Kruisselbrink <[email protected]>
Commit-Queue: May Siem <[email protected]>
Cr-Commit-Position: refs/heads/main@{#1418878}
diff --git a/chrome/browser/apps/link_capturing/BUILD.gn b/chrome/browser/apps/link_capturing/BUILD.gn
index 755ba96..ea4caa0 100644
--- a/chrome/browser/apps/link_capturing/BUILD.gn
+++ b/chrome/browser/apps/link_capturing/BUILD.gn
@@ -53,6 +53,8 @@
       "chromeos_reimpl_navigation_capturing_throttle.h",
       "metrics/intent_handling_metrics.cc",
       "metrics/intent_handling_metrics.h",
+      "navigation_capturing_settings_cros_impl.cc",
+      "navigation_capturing_settings_cros_impl.h",
     ]
     deps += [
       "//ash/webui/projector_app/public/cpp",
@@ -84,15 +86,9 @@
 }
 
 source_set("features") {
-  sources = [
-    "link_capturing_features.cc",
-    "link_capturing_features.h",
-  ]
+  sources = [ "link_capturing_features.h" ]
   public_deps = [ "//base" ]
-  deps = [
-    "//chrome/common:chrome_features",
-    "//content/public/common",
-  ]
+  deps = [ "//chrome/browser/web_applications:web_applications" ]
 }
 
 source_set("test_support") {
diff --git a/chrome/browser/apps/link_capturing/link_capturing_features.h b/chrome/browser/apps/link_capturing/link_capturing_features.h
index 3df3f79c..6166a8a 100644
--- a/chrome/browser/apps/link_capturing/link_capturing_features.h
+++ b/chrome/browser/apps/link_capturing/link_capturing_features.h
@@ -5,26 +5,9 @@
 #ifndef CHROME_BROWSER_APPS_LINK_CAPTURING_LINK_CAPTURING_FEATURES_H_
 #define CHROME_BROWSER_APPS_LINK_CAPTURING_LINK_CAPTURING_FEATURES_H_
 
-#include "base/feature_list.h"
-#include "build/build_config.h"
-
-namespace apps::features {
-
-// Returns true if the updated UX for link capturing needs to be shown. Only set
-// to true on desktop platforms if kPwaNavigationCapturing is enabled, and
-// always on CrOS.
-bool ShouldShowLinkCapturingUX();
-
-// Returns true if the `kPwaNavigationCapturing` flag is enabled with the
-// reimplementation parameters set.
-//
-// NOTE: the reimplementation can also be enabled for particular applications
-// even if this flag is off. Hence only the `true` return value can be fully
-// trusted, but if `false` is returned extra considerations are required. See
-// `IsNavigationCapturingReimplExperimentEnabled()` at
-// //c/b/ui/web_applications/web_app_launch_utils.cc.
-bool IsNavigationCapturingReimplEnabled();
-
-}  // namespace apps::features
+// TODO(msiem): Refactor references to reference
+// "chrome/browser/web_applications/link_capturing_features.h" and remove this
+// file.
+#include "chrome/browser/web_applications/link_capturing_features.h"
 
 #endif  // CHROME_BROWSER_APPS_LINK_CAPTURING_LINK_CAPTURING_FEATURES_H_
diff --git a/chrome/browser/apps/link_capturing/navigation_capturing_settings_cros_impl.cc b/chrome/browser/apps/link_capturing/navigation_capturing_settings_cros_impl.cc
new file mode 100644
index 0000000..3e164d9
--- /dev/null
+++ b/chrome/browser/apps/link_capturing/navigation_capturing_settings_cros_impl.cc
@@ -0,0 +1,54 @@
+// Copyright 2025 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/apps/link_capturing/navigation_capturing_settings_cros_impl.h"
+
+#include "chrome/browser/apps/app_service/app_service_proxy_factory.h"
+#include "chrome/browser/apps/app_service/launch_utils.h"
+#include "chrome/browser/web_applications/chromeos_web_app_experiments.h"
+
+namespace web_app {
+
+std::unique_ptr<NavigationCapturingSettings>
+NavigationCapturingSettings::Create(Profile& profile) {
+  return std::make_unique<NavigationCapturingSettingsCrosImpl>(profile);
+}
+
+NavigationCapturingSettingsCrosImpl::NavigationCapturingSettingsCrosImpl(
+    Profile& profile)
+    : profile_(profile) {}
+
+NavigationCapturingSettingsCrosImpl::~NavigationCapturingSettingsCrosImpl() =
+    default;
+
+std::optional<webapps::AppId>
+NavigationCapturingSettingsCrosImpl::GetCapturingWebAppForUrl(const GURL& url) {
+  if (!apps::AppServiceProxyFactory::IsAppServiceAvailableForProfile(
+          &profile_.get())) {
+    return std::nullopt;
+  }
+
+  return apps::FindAppIdsToLaunchForUrl(
+             apps::AppServiceProxyFactory::GetForProfile(&profile_.get()), url)
+      .preferred;
+}
+
+// This is needed on ChromeOS to support the ChromeOsWebAppExperiments
+// code, see ChromeOsWebAppExperimentsNavigationBrowserTest for tests with
+// this on.
+bool NavigationCapturingSettingsCrosImpl::
+    ShouldAuxiliaryContextsKeepSameContainer(
+        const std::optional<webapps::AppId>& source_browser_app_id,
+        const GURL& url) {
+  if (source_browser_app_id.has_value() &&
+      ChromeOsWebAppExperiments::IsNavigationCapturingReimplEnabledForSourceApp(
+          *source_browser_app_id, url)) {
+    return true;
+  }
+
+  return NavigationCapturingSettings::ShouldAuxiliaryContextsKeepSameContainer(
+      source_browser_app_id, url);
+}
+
+}  // namespace web_app
diff --git a/chrome/browser/apps/link_capturing/navigation_capturing_settings_cros_impl.h b/chrome/browser/apps/link_capturing/navigation_capturing_settings_cros_impl.h
new file mode 100644
index 0000000..7239a78
--- /dev/null
+++ b/chrome/browser/apps/link_capturing/navigation_capturing_settings_cros_impl.h
@@ -0,0 +1,48 @@
+// Copyright 2025 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_APPS_LINK_CAPTURING_NAVIGATION_CAPTURING_SETTINGS_CROS_IMPL_H_
+#define CHROME_BROWSER_APPS_LINK_CAPTURING_NAVIGATION_CAPTURING_SETTINGS_CROS_IMPL_H_
+
+#include "base/memory/raw_ref.h"
+#include "chrome/browser/web_applications/navigation_capturing_settings.h"
+
+class Profile;
+
+namespace web_app {
+
+// This is created in the `NavigationCapturingSettings::Create` method, called
+// in `NavigationCapturingProcess`.
+//
+// ChromeOS uses a different source of truth for storing the preferred
+// application to capture navigations given a url, as it was implemented first
+// and it has to also deal with ARC++ apps. This specialization queries that
+// instead of the WebAppRegistrar.
+class NavigationCapturingSettingsCrosImpl : public NavigationCapturingSettings {
+ public:
+  explicit NavigationCapturingSettingsCrosImpl(Profile& profile);
+  ~NavigationCapturingSettingsCrosImpl() override;
+  NavigationCapturingSettingsCrosImpl(
+      const NavigationCapturingSettingsCrosImpl&) = delete;
+  NavigationCapturingSettingsCrosImpl& operator=(
+      const NavigationCapturingSettingsCrosImpl&) = delete;
+
+  std::optional<webapps::AppId> GetCapturingWebAppForUrl(
+      const GURL& url) override;
+
+  // Allows ChromeOS to sometimes disable auxiliary browser context handling in
+  // the NavigationCapturingProcess, as ChromeOsWebAppExperiments has some
+  // custom handling for auxiliary `about:blank` urls that then redirect.
+  // Otherwise falls back to default implementation.
+  bool ShouldAuxiliaryContextsKeepSameContainer(
+      const std::optional<webapps::AppId>& source_browser_app_id,
+      const GURL& url) override;
+
+ private:
+  raw_ref<Profile> profile_;
+};
+
+}  // namespace web_app
+
+#endif  // CHROME_BROWSER_APPS_LINK_CAPTURING_NAVIGATION_CAPTURING_SETTINGS_CROS_IMPL_H_
diff --git a/chrome/browser/ui/web_applications/navigation_capturing_process.cc b/chrome/browser/ui/web_applications/navigation_capturing_process.cc
index b81a0e0..dcf3156 100644
--- a/chrome/browser/ui/web_applications/navigation_capturing_process.cc
+++ b/chrome/browser/ui/web_applications/navigation_capturing_process.cc
@@ -18,6 +18,7 @@
 #include "chrome/browser/ui/web_applications/web_app_launch_navigation_handle_user_data.h"
 #include "chrome/browser/ui/web_applications/web_app_launch_utils.h"
 #include "chrome/browser/web_applications/navigation_capturing_log.h"
+#include "chrome/browser/web_applications/navigation_capturing_settings.h"
 #include "chrome/browser/web_applications/web_app_helpers.h"
 #include "chrome/browser/web_applications/web_app_provider.h"
 #include "chrome/browser/web_applications/web_app_registrar.h"
@@ -26,8 +27,6 @@
 #include "content/public/common/content_features.h"
 
 #if BUILDFLAG(IS_CHROMEOS)
-#include "chrome/browser/apps/app_service/app_service_proxy_factory.h"
-#include "chrome/browser/apps/app_service/launch_utils.h"
 #include "chrome/browser/web_applications/chromeos_web_app_experiments.h"
 #endif
 
@@ -37,53 +36,6 @@
 
 namespace {
 
-// Causes all new auxiliary browser contexts to share the same window container
-// type as where they were created from. For example, if an aux context was
-// created from standalone PWA, then the new context will be created in a new
-// window of the same PWA.
-// If this is off, then all auxiliary contexts will be created as browser tabs.
-const base::FeatureParam<bool> kEnableAuxContextKeepSameContainer{
-    &features::kPwaNavigationCapturing, "aux_context_keep_same_container",
-    /*default_value=*/false};
-
-// Keeping auxiliary contexts in an 'app' container was causing problems on
-// initial Canary testing, see https://crbug.com/379181271 for more information.
-// Either this will be rolled out separately or removed.
-bool ShouldDisableAuxiliaryBrowsingContextHandling(
-    const std::optional<webapps::AppId>& source_browser_app_id,
-    const GURL& url) {
-  // This is however needed on ChromeOS to support the ChromeOsWebAppExperiments
-  // code, see ChromeOsWebAppExperimentsNavigationBrowserTest for tests with
-  // this on.
-#if BUILDFLAG(IS_CHROMEOS)
-  if (source_browser_app_id.has_value() &&
-      ::web_app::ChromeOsWebAppExperiments::
-          IsNavigationCapturingReimplEnabledForSourceApp(*source_browser_app_id,
-                                                         url)) {
-    return true;
-  }
-#endif
-  return apps::features::IsNavigationCapturingReimplEnabled() &&
-         kEnableAuxContextKeepSameContainer.Get();
-}
-
-std::optional<webapps::AppId> GetWebAppControllingUrl(
-    Profile& profile,
-    const WebAppProvider* provider,
-    const GURL& url) {
-#if BUILDFLAG(IS_CHROMEOS)
-  if (!apps::AppServiceProxyFactory::IsAppServiceAvailableForProfile(
-          &profile)) {
-    return std::nullopt;
-  }
-  return apps::FindAppIdsToLaunchForUrl(
-             apps::AppServiceProxyFactory::GetForProfile(&profile), url)
-      .preferred;
-#else
-  return provider->registrar_unsafe().FindAppThatCapturesLinksInScope(url);
-#endif
-}
-
 bool IsDispositionValidForNavigationCapturing(
     WindowOpenDisposition disposition) {
   switch (disposition) {
@@ -275,6 +227,8 @@
   WebAppProvider* provider = WebAppProvider::GetForWebApps(&*profile_);
   CHECK(provider);
   web_app::WebAppRegistrar& registrar = provider->registrar_unsafe();
+  navigation_capturing_settings_ =
+      NavigationCapturingSettings::Create(*profile_);
 
   debug_data_.Set("referrer.url", params.referrer.url.possibly_invalid_spec());
   debug_data_.Set("source_contents.url",
@@ -302,7 +256,8 @@
   debug_data_.Set("is_user_modified_click", is_user_modified_click());
 
   first_navigation_app_id_ =
-      GetWebAppControllingUrl(profile_.get(), provider, params.url);
+      navigation_capturing_settings_->GetCapturingWebAppForUrl(params.url);
+
   debug_data_.Set("controlling_app_id",
                   first_navigation_app_id_.value_or("<none>"));
   if (first_navigation_app_id_) {
@@ -511,8 +466,9 @@
   // app browser.
   if (IsAuxiliaryBrowsingContext(params)) {
     debug_data_.Set("is_auxiliary_browsing_context", true);
-    if (!ShouldDisableAuxiliaryBrowsingContextHandling(source_browser_app_id_,
-                                                       params.url)) {
+    if (!navigation_capturing_settings_
+             ->ShouldAuxiliaryContextsKeepSameContainer(source_browser_app_id_,
+                                                        params.url)) {
       return CapturingDisabled();
     }
     if (source_browser_app_id_.has_value()) {
@@ -737,7 +693,7 @@
       WebAppProvider::GetForWebContents(web_contents_for_navigation);
   WebAppRegistrar& registrar = provider->registrar_unsafe();
   std::optional<webapps::AppId> target_app_id =
-      GetWebAppControllingUrl(profile_.get(), provider, final_url);
+      navigation_capturing_settings_->GetCapturingWebAppForUrl(final_url);
 
   // "Same first navigation state" case:
   // First, we can exit early if the first navigation app id matches the target
diff --git a/chrome/browser/ui/web_applications/navigation_capturing_process.h b/chrome/browser/ui/web_applications/navigation_capturing_process.h
index c4d218f..9d20a82 100644
--- a/chrome/browser/ui/web_applications/navigation_capturing_process.h
+++ b/chrome/browser/ui/web_applications/navigation_capturing_process.h
@@ -22,6 +22,8 @@
 
 namespace web_app {
 
+class NavigationCapturingSettings;
+
 // This class encompasses all of the logic for navigations in the browser to be
 // captured into installed web app launches.
 //
@@ -211,6 +213,8 @@
 
   PipelineState state_ = PipelineState::kCreated;
 
+  std::unique_ptr<NavigationCapturingSettings> navigation_capturing_settings_;
+
   // These fields are copied or derived from the NavigateParams of the original
   // navigation.
   const raw_ref<Profile> profile_;
diff --git a/chrome/browser/web_applications/BUILD.gn b/chrome/browser/web_applications/BUILD.gn
index b63b165..bafa171e 100644
--- a/chrome/browser/web_applications/BUILD.gn
+++ b/chrome/browser/web_applications/BUILD.gn
@@ -205,6 +205,8 @@
     "jobs/uninstall/uninstall_job.cc",
     "jobs/uninstall/uninstall_job.h",
     "jobs/uninstall/web_app_uninstall_and_replace_job.h",
+    "link_capturing_features.cc",
+    "link_capturing_features.h",
     "locks/all_apps_lock.cc",
     "locks/all_apps_lock.h",
     "locks/app_lock.cc",
@@ -235,6 +237,8 @@
     "manifest_update_utils.h",
     "navigation_capturing_log.cc",
     "navigation_capturing_log.h",
+    "navigation_capturing_settings.cc",
+    "navigation_capturing_settings.h",
     "os_integration/file_handling_sub_manager.cc",
     "os_integration/file_handling_sub_manager.h",
     "os_integration/os_integration_manager.cc",
@@ -468,6 +472,13 @@
     ]
   }
 
+  if (!is_chromeos) {
+    sources += [
+      "navigation_capturing_settings_impl.cc",
+      "navigation_capturing_settings_impl.h",
+    ]
+  }
+
   # Enable the "exit_time_destructors" warning here to avoid accidentally
   # adding exit time destructors and because the flag is not enabled by default.
   # TODO(http://crbug.com/101600):  Remove once exit_time_destructors is enabled
diff --git a/chrome/browser/apps/link_capturing/link_capturing_features.cc b/chrome/browser/web_applications/link_capturing_features.cc
similarity index 89%
rename from chrome/browser/apps/link_capturing/link_capturing_features.cc
rename to chrome/browser/web_applications/link_capturing_features.cc
index b16bc6e..c9bdfdd 100644
--- a/chrome/browser/apps/link_capturing/link_capturing_features.cc
+++ b/chrome/browser/web_applications/link_capturing_features.cc
@@ -1,8 +1,8 @@
-// Copyright 2022 The Chromium Authors
+// Copyright 2025 The Chromium Authors
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/apps/link_capturing/link_capturing_features.h"
+#include "chrome/browser/web_applications/link_capturing_features.h"
 
 #include "base/feature_list.h"
 #include "build/build_config.h"
diff --git a/chrome/browser/web_applications/link_capturing_features.h b/chrome/browser/web_applications/link_capturing_features.h
new file mode 100644
index 0000000..e96fb6e
--- /dev/null
+++ b/chrome/browser/web_applications/link_capturing_features.h
@@ -0,0 +1,30 @@
+// Copyright 2025 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_WEB_APPLICATIONS_LINK_CAPTURING_FEATURES_H_
+#define CHROME_BROWSER_WEB_APPLICATIONS_LINK_CAPTURING_FEATURES_H_
+
+#include "base/feature_list.h"
+#include "build/build_config.h"
+
+namespace apps::features {
+
+// Returns true if the updated UX for link capturing needs to be shown. Only set
+// to true on desktop platforms if kPwaNavigationCapturing is enabled, and
+// always on CrOS.
+bool ShouldShowLinkCapturingUX();
+
+// Returns true if the `kPwaNavigationCapturing` flag is enabled with the
+// reimplementation parameters set.
+//
+// NOTE: the reimplementation can also be enabled for particular applications
+// even if this flag is off. Hence only the `true` return value can be fully
+// trusted, but if `false` is returned extra considerations are required. See
+// `IsNavigationCapturingReimplExperimentEnabled()` at
+// //c/b/ui/web_applications/web_app_launch_utils.cc.
+bool IsNavigationCapturingReimplEnabled();
+
+}  // namespace apps::features
+
+#endif  // CHROME_BROWSER_WEB_APPLICATIONS_LINK_CAPTURING_FEATURES_H_
diff --git a/chrome/browser/web_applications/navigation_capturing_settings.cc b/chrome/browser/web_applications/navigation_capturing_settings.cc
new file mode 100644
index 0000000..77873f6
--- /dev/null
+++ b/chrome/browser/web_applications/navigation_capturing_settings.cc
@@ -0,0 +1,36 @@
+// Copyright 2025 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/web_applications/navigation_capturing_settings.h"
+
+#include "chrome/browser/web_applications/link_capturing_features.h"
+#include "content/public/common/content_features.h"
+#include "ui/base/ui_base_features.h"
+
+namespace web_app {
+
+namespace {
+
+// Causes all new auxiliary browser contexts to share the same window container
+// type as where they were created from. For example, if an aux context was
+// created from standalone PWA, then the new context will be created in a new
+// window of the same PWA.
+// If this is off, then all auxiliary contexts will be created as browser tabs.
+const base::FeatureParam<bool> kEnableAuxContextKeepSameContainer{
+    &features::kPwaNavigationCapturing, "aux_context_keep_same_container",
+    /*default_value=*/false};
+
+}  // namespace
+
+// Keeping auxiliary contexts in an 'app' container was causing problems on
+// initial Canary testing, see https://crbug.com/379181271 for more information.
+// Either this will be rolled out separately or removed.
+bool NavigationCapturingSettings::ShouldAuxiliaryContextsKeepSameContainer(
+    const std::optional<webapps::AppId>& source_browser_app_id,
+    const GURL& url) {
+  return apps::features::IsNavigationCapturingReimplEnabled() &&
+         kEnableAuxContextKeepSameContainer.Get();
+}
+
+}  // namespace web_app
diff --git a/chrome/browser/web_applications/navigation_capturing_settings.h b/chrome/browser/web_applications/navigation_capturing_settings.h
new file mode 100644
index 0000000..ccf046d
--- /dev/null
+++ b/chrome/browser/web_applications/navigation_capturing_settings.h
@@ -0,0 +1,49 @@
+// Copyright 2025 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_WEB_APPLICATIONS_NAVIGATION_CAPTURING_SETTINGS_H_
+#define CHROME_BROWSER_WEB_APPLICATIONS_NAVIGATION_CAPTURING_SETTINGS_H_
+
+#include <memory>
+#include <optional>
+
+#include "components/webapps/common/web_app_id.h"
+
+class Profile;
+
+namespace web_app {
+
+// This class is used by the `NavigationCapturingProcess` to get an installed
+// PWA's `apps::AppId` that captures a given url. This is abstracted behind an
+// interface because ChromeOS uses a separate storage / source of truth for this
+// information than other platforms, and has some extra constraints &
+// requirements due to needing to support ARC++ / Android apps.
+//
+// This class is used exclusively on the UI thread.
+class NavigationCapturingSettings {
+ public:
+  static std::unique_ptr<NavigationCapturingSettings> Create(Profile&);
+  virtual ~NavigationCapturingSettings() = default;
+
+  // Returns the app_id for the web app that a url should be captured in.
+  // Otherwise, return nullopt.
+  virtual std::optional<webapps::AppId> GetCapturingWebAppForUrl(
+      const GURL& url) = 0;
+
+  // Return if auxiliary contexts should be created in the same container (app
+  // or browser) that the navigation happened in. Due to breakage, this is
+  // disabled by default via feature flag, but is planned to be changed to
+  // always 'true'.
+  //
+  // In the meantime, on ChromeOS for <experiment class>, this is selectively
+  // enabled for certain cases to support that project, until we can ship the
+  // above change.
+  virtual bool ShouldAuxiliaryContextsKeepSameContainer(
+      const std::optional<webapps::AppId>& source_browser_app_id,
+      const GURL& url);
+};
+
+}  // namespace web_app
+
+#endif  // CHROME_BROWSER_WEB_APPLICATIONS_NAVIGATION_CAPTURING_SETTINGS_H_
diff --git a/chrome/browser/web_applications/navigation_capturing_settings_impl.cc b/chrome/browser/web_applications/navigation_capturing_settings_impl.cc
new file mode 100644
index 0000000..967d907
--- /dev/null
+++ b/chrome/browser/web_applications/navigation_capturing_settings_impl.cc
@@ -0,0 +1,30 @@
+// Copyright 2025 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/web_applications/navigation_capturing_settings_impl.h"
+
+#include "chrome/browser/web_applications/navigation_capturing_settings.h"
+#include "chrome/browser/web_applications/web_app_provider.h"
+#include "chrome/browser/web_applications/web_app_registrar.h"
+
+namespace web_app {
+
+std::unique_ptr<NavigationCapturingSettings>
+NavigationCapturingSettings::Create(Profile& profile) {
+  return std::make_unique<NavigationCapturingSettingsImpl>(profile);
+}
+
+NavigationCapturingSettingsImpl::NavigationCapturingSettingsImpl(
+    Profile& profile)
+    : profile_(profile) {}
+
+NavigationCapturingSettingsImpl::~NavigationCapturingSettingsImpl() = default;
+
+std::optional<webapps::AppId>
+NavigationCapturingSettingsImpl::GetCapturingWebAppForUrl(const GURL& url) {
+  auto* provider = web_app::WebAppProvider::GetForWebApps(&profile_.get());
+  return provider->registrar_unsafe().FindAppThatCapturesLinksInScope(url);
+}
+
+}  // namespace web_app
diff --git a/chrome/browser/web_applications/navigation_capturing_settings_impl.h b/chrome/browser/web_applications/navigation_capturing_settings_impl.h
new file mode 100644
index 0000000..e44baaf
--- /dev/null
+++ b/chrome/browser/web_applications/navigation_capturing_settings_impl.h
@@ -0,0 +1,38 @@
+// Copyright 2025 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_WEB_APPLICATIONS_NAVIGATION_CAPTURING_SETTINGS_IMPL_H_
+#define CHROME_BROWSER_WEB_APPLICATIONS_NAVIGATION_CAPTURING_SETTINGS_IMPL_H_
+
+#include "base/memory/raw_ref.h"
+#include "chrome/browser/web_applications/navigation_capturing_settings.h"
+
+class Profile;
+
+namespace web_app {
+
+// This is created in the `NavigationCapturingSettings::Create` method, called
+// in `NavigationCapturingProcess`.
+//
+// Windows, Mac, and Linux queries through the WebAppRegistrar to store the
+// preferred application to capturing navigations given a url.
+class NavigationCapturingSettingsImpl : public NavigationCapturingSettings {
+ public:
+  explicit NavigationCapturingSettingsImpl(Profile& profile);
+  ~NavigationCapturingSettingsImpl() override;
+  NavigationCapturingSettingsImpl(const NavigationCapturingSettingsImpl&) =
+      delete;
+  NavigationCapturingSettingsImpl& operator=(
+      const NavigationCapturingSettingsImpl&) = delete;
+
+  std::optional<webapps::AppId> GetCapturingWebAppForUrl(
+      const GURL& url) override;
+
+ private:
+  raw_ref<Profile> profile_;
+};
+
+}  // namespace web_app
+
+#endif  // CHROME_BROWSER_WEB_APPLICATIONS_NAVIGATION_CAPTURING_SETTINGS_IMPL_H_