diff --git a/fuchsia_web/common/test/test_realm_support.cc b/fuchsia_web/common/test/test_realm_support.cc
index caebd9d432f92..e7a6203108e02 100644
--- a/fuchsia_web/common/test/test_realm_support.cc
+++ b/fuchsia_web/common/test/test_realm_support.cc
@@ -12,6 +12,7 @@
 
 #include "base/check.h"
 #include "base/command_line.h"
+#include "base/ranges/algorithm.h"
 
 using ::component_testing::ChildRef;
 using ::component_testing::Directory;
@@ -22,24 +23,61 @@ using ::component_testing::Route;
 
 namespace test {
 
+namespace {
+
+void AppendCommandLineArgumentsToProgram(
+    fuchsia::component::decl::Program& program,
+    const base::CommandLine& command_line) {
+  // Find the "args" list in the program declaration.
+  fuchsia::data::DictionaryEntry* args_entry = nullptr;
+  auto* entries = program.mutable_info()->mutable_entries();
+  for (auto& entry : *entries) {
+    if (entry.key == "args") {
+      DCHECK(entry.value->is_str_vec());
+      args_entry = &entry;
+      break;
+    }
+  }
+  if (!args_entry) {
+    // Create a new "args" list and insert it at the proper location in the
+    // program's entries; entries' keys must be sorted as per
+    // https://fuchsia.dev/reference/fidl/fuchsia.data?hl=en#Dictionary.
+    auto lower_bound = base::ranges::lower_bound(
+        *entries, "args", /*comp=*/{},
+        [](const fuchsia::data::DictionaryEntry& entry) { return entry.key; });
+    auto it = entries->emplace(lower_bound);
+    it->key = "args";
+    it->value = fuchsia::data::DictionaryValue::New();
+    it->value->set_str_vec({});
+    args_entry = &*it;
+  }
+
+  // Append all args following the program name in `command_line` to the
+  // program's args.
+  args_entry->value->str_vec().insert(args_entry->value->str_vec().end(),
+                                      command_line.argv().begin() + 1,
+                                      command_line.argv().end());
+}
+
+}  // namespace
+
 void AppendCommandLineArguments(RealmBuilder& realm_builder,
                                 base::StringPiece child_name,
                                 const base::CommandLine& command_line) {
   const std::string child_name_str(child_name);
-  auto context_provider_decl = realm_builder.GetComponentDecl(child_name_str);
-  for (auto& entry : *context_provider_decl.mutable_program()
-                          ->mutable_info()
-                          ->mutable_entries()) {
-    if (entry.key == "args") {
-      DCHECK(entry.value->is_str_vec());
-      entry.value->str_vec().insert(entry.value->str_vec().end(),
-                                    command_line.argv().begin() + 1,
-                                    command_line.argv().end());
-      break;
-    }
-  }
+  auto child_component_decl = realm_builder.GetComponentDecl(child_name_str);
+  AppendCommandLineArgumentsToProgram(*child_component_decl.mutable_program(),
+                                      command_line);
   realm_builder.ReplaceComponentDecl(child_name_str,
-                                     std::move(context_provider_decl));
+                                     std::move(child_component_decl));
+}
+
+void AppendCommandLineArgumentsForRealm(
+    ::component_testing::RealmBuilder& realm_builder,
+    const base::CommandLine& command_line) {
+  auto decl = realm_builder.GetRealmDecl();
+  AppendCommandLineArgumentsToProgram(*decl.mutable_program(), command_line);
+  realm_builder.ReplaceRealmDecl(std::move(decl));
 }
 
 void AddSyslogRoutesFromParent(RealmBuilder& realm_builder,
diff --git a/fuchsia_web/common/test/test_realm_support.h b/fuchsia_web/common/test/test_realm_support.h
index 5cd155412840a..2d3cd57f2b143 100644
--- a/fuchsia_web/common/test/test_realm_support.h
+++ b/fuchsia_web/common/test/test_realm_support.h
@@ -24,6 +24,12 @@ void AppendCommandLineArguments(
     base::StringPiece child_name,
     const base::CommandLine& command_line);
 
+// Appends the arguments of `command_line` (ignoring the program name at
+// position zero) to the command line for the realm.
+void AppendCommandLineArgumentsForRealm(
+    ::component_testing::RealmBuilder& realm_builder,
+    const base::CommandLine& command_line);
+
 // In the functions below, the term "parent" is the `#realm_builder` collection
 // for the test component that is using these helpers to build a test realm.
 // Each test component must use a .cml fragment that routes the required
diff --git a/fuchsia_web/shell/BUILD.gn b/fuchsia_web/shell/BUILD.gn
index 85111da3999d4..74c969c2fed98 100644
--- a/fuchsia_web/shell/BUILD.gn
+++ b/fuchsia_web/shell/BUILD.gn
@@ -39,9 +39,13 @@ fuchsia_component("web_engine_shell_component") {
   data_deps = [ ":web_engine_shell_exec" ]
 }
 
-fuchsia_component("web_engine_shell_component_v1") {
+# WebInstanceHost needs to serve capabilities to web_instance. Since the
+# primary web_engine_shell component is a test component, it is not able to do
+# this directly. Instead, it launches this here component to start instances via
+# WebInstanceHost.
+fuchsia_component("web_engine_shell_for_web_instance_host_component") {
   testonly = true
-  manifest = "web_engine_shell.cmx"
+  manifest = "web_engine_shell_for_web_instance_host.cml"
   data_deps = [ ":web_engine_shell_exec" ]
 }
 
@@ -52,7 +56,7 @@ fuchsia_package("web_engine_shell_pkg") {
   package_name = "web_engine_shell"
   deps = [
     ":web_engine_shell_component",
-    ":web_engine_shell_component_v1",
+    ":web_engine_shell_for_web_instance_host_component",
   ]
 }
 
@@ -82,11 +86,15 @@ executable("web_engine_shell_exec") {
     ":remote_debugging_port",
     "//base",
     "//fuchsia_web/common",
-    "//fuchsia_web/webinstance_host:webinstance_host_v1",
+    "//fuchsia_web/common/test:test_support",
+    "//fuchsia_web/webinstance_host:webinstance_host",
+    "//third_party/fuchsia-sdk/sdk/fidl/fuchsia.component:fuchsia.component_hlcpp",
     "//third_party/fuchsia-sdk/sdk/fidl/fuchsia.ui.policy:fuchsia.ui.policy_hlcpp",
     "//third_party/fuchsia-sdk/sdk/fidl/fuchsia.web:fuchsia.web_hlcpp",
     "//third_party/fuchsia-sdk/sdk/pkg/fdio",
+    "//third_party/fuchsia-sdk/sdk/pkg/fidl_cpp",
     "//third_party/fuchsia-sdk/sdk/pkg/scenic_cpp",
+    "//third_party/fuchsia-sdk/sdk/pkg/sys_component_cpp_testing",
     "//third_party/fuchsia-sdk/sdk/pkg/sys_cpp",
     "//third_party/widevine/cdm:buildflags",
     "//url",
diff --git a/fuchsia_web/shell/README.md b/fuchsia_web/shell/README.md
index e4fcb424bb244..1174d607129ad 100644
--- a/fuchsia_web/shell/README.md
+++ b/fuchsia_web/shell/README.md
@@ -12,8 +12,7 @@ To build and run WebEngine Shell, execute the following commands:
 $ autoninja -C $OUTDIR web_engine_shell
 $ $OUTDIR/bin/deploy_web_engine_shell --fuchsia-out-dir $FUCHSIA_OUTDIR
 $ cd $FUCHSIA
-$ fx shell
-$ run fuchsia-pkg://fuchsia.com/web_engine_shell#meta/web_engine_shell.cmx --remote-debugging-port=1234 http://www.example.com
+$ ffx test run fuchsia-pkg://fuchsia.com/web_engine_shell#meta/web_engine_shell.cm -- --remote-debugging-port=1234 http://www.example.com
 ```
 
 Local files can be deployed with the WebEngine Shell and accessed via the
@@ -22,5 +21,5 @@ by placing them under the path `//fuchsia_web/webengine/data`.
 
 Here is an example command line which loads a local file:
 ```
-$ run fuchsia-pkg://fuchsia.com/web_engine_shell#meta/web_engine_shell.cmx fuchsia-dir://data/index.html
+$ ffx test run fuchsia-pkg://fuchsia.com/web_engine_shell#meta/web_engine_shell.cm -- fuchsia-dir://data/index.html
 ```
diff --git a/fuchsia_web/shell/web_engine_shell.cc b/fuchsia_web/shell/web_engine_shell.cc
index 5c3ffa469bb6d..e5855d149a1c9 100644
--- a/fuchsia_web/shell/web_engine_shell.cc
+++ b/fuchsia_web/shell/web_engine_shell.cc
@@ -2,16 +2,21 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <fuchsia/component/cpp/fidl.h>
 #include <fuchsia/ui/policy/cpp/fidl.h>
 #include <fuchsia/web/cpp/fidl.h>
 #include <lib/fdio/directory.h>
+#include <lib/fidl/cpp/interface_ptr.h>
+#include <lib/sys/component/cpp/testing/realm_builder.h>
 #include <lib/sys/cpp/component_context.h>
+#include <lib/sys/cpp/service_directory.h>
 #include <lib/ui/scenic/cpp/view_token_pair.h>
-#include <lib/vfs/cpp/pseudo_file.h>
+
 #include <iostream>
 #include <utility>
 
 #include "base/base_paths.h"
+#include "base/check.h"
 #include "base/command_line.h"
 #include "base/files/file_util.h"
 #include "base/fuchsia/file_utils.h"
@@ -27,9 +32,10 @@
 #include "base/values.h"
 #include "build/build_config.h"
 #include "fuchsia_web/common/init_logging.h"
+#include "fuchsia_web/common/test/test_realm_support.h"
 #include "fuchsia_web/shell/remote_debugging_port.h"
+#include "fuchsia_web/webinstance_host/web_instance_host.h"
 #include "fuchsia_web/webinstance_host/web_instance_host_constants.h"
-#include "fuchsia_web/webinstance_host/web_instance_host_v1.h"
 #include "third_party/widevine/cdm/buildflags.h"
 #include "url/gurl.h"
 
@@ -38,6 +44,9 @@ namespace {
 constexpr char kHeadlessSwitch[] = "headless";
 constexpr char kEnableProtectedMediaIdentifier[] =
     "enable-protected-media-identifier";
+// Included on the command line when the shell is relaunched for use of
+// WebInstanceHost; see web_engine_shell_for_web_instance_host.cml.
+constexpr char kFromLauncher[] = "from-launcher";
 constexpr char kUseWebInstance[] = "use-web-instance";
 constexpr char kEnableWebInstanceTmp[] = "enable-web-instance-tmp";
 
@@ -69,17 +78,51 @@ GURL GetUrlFromArgs(const base::CommandLine::StringVector& args) {
   return url;
 }
 
+// web_engine_shell needs to provide capabilities to children it launches (via
+// WebInstanceHost, for example). Test components are not able to do this, so
+// use RealmBuilder to relaunch web_engine_shell via
+// `web_engine_shell_for_web_instance_host_component` (which includes
+// `--from-launcher` on its command line) with the contents of this process's
+// command line.
+int RelaunchForWebInstanceHost(const base::CommandLine& command_line) {
+  auto realm_builder = component_testing::RealmBuilder::CreateFromRelativeUrl(
+      "#meta/web_engine_shell_for_web_instance_host.cm");
+  test::AppendCommandLineArgumentsForRealm(realm_builder,  // IN-TEST
+                                           command_line);
+
+  auto realm = realm_builder.Build();
+
+  fuchsia::component::BinderPtr binder_proxy =
+      realm.component().Connect<fuchsia::component::Binder>();
+
+  // Wait for binder_proxy to be closed.
+  base::RunLoop run_loop;
+  binder_proxy.set_error_handler(
+      [quit_closure = run_loop.QuitClosure()](zx_status_t status) {
+        std::move(quit_closure).Run();
+      });
+  run_loop.Run();
+
+  // Nothing depends on the process exit code of web_engine_shell today, so
+  // simply return success in all cases.
+  return 0;
+}
+
 }  // namespace
 
 int main(int argc, char** argv) {
+  base::CommandLine::Init(argc, argv);
+
+  base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+  CHECK(InitLoggingFromCommandLine(*command_line));
+
   base::SingleThreadTaskExecutor executor(base::MessagePumpType::IO);
 
-  // Parse the command line arguments and set up logging.
-  CHECK(base::CommandLine::Init(argc, argv));
-  base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
-
-  CHECK(InitLoggingFromCommandLineDefaultingToStderrForTest(  // IN-TEST
-      command_line));
+  const bool is_run_from_launcher = command_line->HasSwitch(kFromLauncher);
+  const bool use_context_provider = !command_line->HasSwitch(kUseWebInstance);
+  if (!is_run_from_launcher && !use_context_provider) {
+    return RelaunchForWebInstanceHost(*command_line);
+  }
 
   absl::optional<uint16_t> remote_debugging_port =
       GetRemoteDebuggingPort(*command_line);
@@ -91,7 +134,6 @@ int main(int argc, char** argv) {
   const bool is_headless = command_line->HasSwitch(kHeadlessSwitch);
   const bool enable_protected_media_identifier_access =
       command_line->HasSwitch(kEnableProtectedMediaIdentifier);
-  const bool use_context_provider = !command_line->HasSwitch(kUseWebInstance);
   const bool enable_web_instance_tmp =
       command_line->HasSwitch(kEnableWebInstanceTmp);
   const bool with_webui = command_line->HasSwitch(switches::kWithWebui);
@@ -173,12 +215,9 @@ int main(int argc, char** argv) {
 
   base::RunLoop run_loop;
 
-  // Create the browser |context|.
-  fuchsia::web::ContextPtr context;
-
-  // Keep alive in run_loop scope.
   fuchsia::web::ContextProviderPtr web_context_provider;
-  std::unique_ptr<WebInstanceHostV1> web_instance_host;
+  std::unique_ptr<WebInstanceHost> web_instance_host;
+  fuchsia::web::ContextPtr context;
   fuchsia::io::DirectoryHandle tmp_directory;
 
   if (use_context_provider) {
@@ -189,7 +228,7 @@ int main(int argc, char** argv) {
     web_context_provider->Create(std::move(create_context_params),
                                  context.NewRequest());
   } else {
-    web_instance_host = std::make_unique<WebInstanceHostV1>();
+    web_instance_host = std::make_unique<WebInstanceHost>();
     if (enable_web_instance_tmp) {
       const zx_status_t status = fdio_open(
           "/tmp",
@@ -290,6 +329,8 @@ int main(int argc, char** argv) {
 
   LOG(INFO) << "Launched browser at URL " << url.spec();
 
+  base::ComponentContextForProcess()->outgoing()->ServeFromStartupInfo();
+
   // Run until the process is killed with CTRL-C or the connections to Web
   // Engine interfaces are dropped.
   run_loop.Run();
diff --git a/fuchsia_web/shell/web_engine_shell.cml b/fuchsia_web/shell/web_engine_shell.cml
index 1ea9df29071f5..5b32a331c1101 100644
--- a/fuchsia_web/shell/web_engine_shell.cml
+++ b/fuchsia_web/shell/web_engine_shell.cml
@@ -10,38 +10,36 @@
     // to function correctly.
     "//build/config/fuchsia/test/chromium_test_facet.shard.test-cml",
     "//build/config/fuchsia/test/elf_test_ambient_exec_runner.shard.test-cml",
+    "sys/component/realm_builder_absolute.shard.cml",
     "syslog/client.shard.cml",
   ],
   program: {
     binary: "web_engine_shell_exec",
   },
   use: [
-    {
-      protocol: [
-        "fuchsia.feedback.ComponentDataRegister",
-        "fuchsia.feedback.CrashReportingProductRegister",
-        "fuchsia.sys.Environment",
-        "fuchsia.sys.Launcher",
-        "fuchsia.sys.Loader",
-      ],
-    },
-
     // Used conditionally based on the absence of `--use-web-instance` on the
     // command line at runtime.
     {
       protocol: "fuchsia.web.ContextProvider",
       availability: "optional",
     },
+
+    // Used to hold the cdm_data directory passed to web_instance.
     {
       storage: "data",
       path: "/data",
     },
+
+    // Needed when launched with --enable-web-instance-tmp.
     {
       storage: "tmp",
       path: "/tmp",
+      availability: "optional",
     },
 
-    // Uses below this line are for web_instance.cmx
+    // Uses below this line are for web_instance.cmx.
+    // TODO(crbug.com/1280703): Revise as needed when context_provider is
+    // migrated to launch web_instance.cm.
     {
       protocol: [
         "fuchsia.buildinfo.Provider",
@@ -93,10 +91,103 @@
       availability: "optional",
     },
   ],
+  offer: [
+    {
+      storage: [
+        "data",
+        "tmp",
+      ],
+      from: "parent",
+      to: "#realm_builder",
+    },
+    {
+      directory: "root-ssl-certificates",
+      from: "parent",
+      to: "#realm_builder",
+    },
+
+    // Offers for web_instance.cm.
+    // The chromium test realm offers the system-wide config-data dir to test
+    // components. Route the web_engine sub-directory of this as required by
+    // WebInstanceHost.
+    {
+      directory: "config-data",
+      from: "parent",
+      as: "config-data-for-web-instance",
+      to: "#realm_builder",
+      subdir: "web_engine",
+      availability: "optional",
+    },
+    {
+      protocol: [
+        "fuchsia.buildinfo.Provider",
+        "fuchsia.device.NameProvider",
+        "fuchsia.feedback.ComponentDataRegister",
+        "fuchsia.feedback.CrashReportingProductRegister",
+        "fuchsia.fonts.Provider",
+        "fuchsia.hwinfo.Product",
+        "fuchsia.input.virtualkeyboard.ControllerCreator",
+        "fuchsia.intl.PropertyProvider",
+        "fuchsia.kernel.VmexResource",
+        "fuchsia.media.Audio",
+        "fuchsia.media.AudioDeviceEnumerator",
+        "fuchsia.media.ProfileProvider",
+        "fuchsia.media.SessionAudioConsumerFactory",
+        "fuchsia.mediacodec.CodecFactory",
+        "fuchsia.memorypressure.Provider",
+        "fuchsia.net.interfaces.State",
+        "fuchsia.net.name.Lookup",
+        "fuchsia.posix.socket.Provider",
+        "fuchsia.process.Launcher",
+        "fuchsia.sysmem.Allocator",
+        "fuchsia.ui.input3.Keyboard",
+      ],
+      from: "parent",
+      to: "#realm_builder",
+    },
+
+    // Used conditionally based on the value of `enable_widevine` at build time.
+    // TODO(crbug.com/1379411): Use a shard to conditionally use based on
+    // build-time config.
+    {
+      protocol: "fuchsia.media.drm.Widevine",
+      from: "parent",
+      to: "#realm_builder",
+      availability: "optional",
+    },
+
+    // Used conditionally based on the absence of `--headless` on the command
+    // line at runtime.
+    {
+      protocol: [
+        "fuchsia.accessibility.semantics.SemanticsManager",
+        "fuchsia.tracing.provider.Registry",
+        "fuchsia.ui.composition.Allocator",
+        "fuchsia.ui.composition.Flatland",
+        "fuchsia.ui.policy.Presenter",
+        "fuchsia.ui.scenic.Scenic",
+        "fuchsia.vulkan.loader.Loader",
+      ],
+      from: "parent",
+      to: "#realm_builder",
+      availability: "optional",
+    },
+
+    // Optional capabilities, dependent on availability of tracing services.
+    {
+      protocol: "fuchsia.tracing.perfetto.ProducerConnector",
+      from: "parent",
+      to: "#realm_builder",
+      availability: "optional",
+    },
+  ],
   facets: {
-    "fuchsia.test.deprecated-allowed-packages": [
-      "web_engine",
-      "web_engine_with_webui",
-    ],
+    "fuchsia.test": {
+      "deprecated-allowed-packages": [
+        "test_manager",
+        "web_engine",
+        "web_engine_with_webui",
+      ],
+    },
   },
 }
diff --git a/fuchsia_web/shell/web_engine_shell.cmx b/fuchsia_web/shell/web_engine_shell.cmx
deleted file mode 100644
index fd05f249eec4b..0000000000000
--- a/fuchsia_web/shell/web_engine_shell.cmx
+++ /dev/null
@@ -1,50 +0,0 @@
-{
-  "program": {
-    "binary": "web_engine_shell_exec"
-  },
-  "sandbox": {
-    "features": [
-      "deprecated-ambient-replace-as-executable",
-      "isolated-persistent-storage",
-      "isolated-temp"
-    ],
-    "services": [
-      "fuchsia.accessibility.semantics.SemanticsManager",
-      "fuchsia.buildinfo.Provider",
-      "fuchsia.camera3.DeviceWatcher",
-      "fuchsia.device.NameProvider",
-      "fuchsia.feedback.ComponentDataRegister",
-      "fuchsia.feedback.CrashReportingProductRegister",
-      "fuchsia.fonts.Provider",
-      "fuchsia.hwinfo.Product",
-      "fuchsia.input.virtualkeyboard.ControllerCreator",
-      "fuchsia.intl.PropertyProvider",
-      "fuchsia.kernel.VmexResource",
-      "fuchsia.logger.LogSink",
-      "fuchsia.media.Audio",
-      "fuchsia.media.AudioDeviceEnumerator",
-      "fuchsia.media.ProfileProvider",
-      "fuchsia.media.SessionAudioConsumerFactory",
-      "fuchsia.media.drm.Widevine",
-      "fuchsia.mediacodec.CodecFactory",
-      "fuchsia.memorypressure.Provider",
-      "fuchsia.net.interfaces.State",
-      "fuchsia.net.name.Lookup",
-      "fuchsia.posix.socket.Provider",
-      "fuchsia.process.Launcher",
-      "fuchsia.sys.Environment",
-      "fuchsia.sys.Launcher",
-      "fuchsia.sys.Loader",
-      "fuchsia.sysmem.Allocator",
-      "fuchsia.tracing.perfetto.ProducerConnector",
-      "fuchsia.tracing.provider.Registry",
-      "fuchsia.ui.composition.Allocator",
-      "fuchsia.ui.composition.Flatland",
-      "fuchsia.ui.input3.Keyboard",
-      "fuchsia.ui.policy.Presenter",
-      "fuchsia.ui.scenic.Scenic",
-      "fuchsia.vulkan.loader.Loader",
-      "fuchsia.web.ContextProvider"
-    ]
-  }
-}
diff --git a/fuchsia_web/shell/web_engine_shell_for_web_instance_host.cml b/fuchsia_web/shell/web_engine_shell_for_web_instance_host.cml
new file mode 100644
index 0000000000000..c022c67a7fdc1
--- /dev/null
+++ b/fuchsia_web/shell/web_engine_shell_for_web_instance_host.cml
@@ -0,0 +1,47 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// A component that is launched by web_engine_shell since web_engine_shell
+// itself runs as a test component, and therefore cannot run WebInstanceHost
+// directly.
+{
+  include: [
+    "//fuchsia_web/webinstance_host/web_instance_host.shard.cml",
+    "syslog/client.shard.cml",
+  ],
+  program: {
+    runner: "elf",
+    binary: "web_engine_shell_exec",
+    args: [
+      // Inform web_engine_shell that it is running as the sub-process in which
+      // WebInstanceHost may be used. In this scenario, the main test component
+      // is running only as a launcher of this child.
+      "--from-launcher",
+    ],
+
+    // Required to allow JIT in child processes such as renderers.
+    // Known as 'deprecated-ambient-replace-as-executable' in CFv1.
+    job_policy_ambient_mark_vmo_exec: "true",
+  },
+  use: [
+    // Required if not run with --headless.
+    {
+      protocol: "fuchsia.ui.policy.Presenter",
+      availability: "optional",
+    },
+
+    // Used to hold the cdm_data directory passed to web_instance.
+    {
+      storage: "data",
+      path: "/data",
+    },
+
+    // Needed when launched with --enable-web-instance-tmp.
+    {
+      storage: "tmp",
+      path: "/tmp",
+      availability: "optional",
+    },
+  ],
+}
diff --git a/fuchsia_web/webengine/BUILD.gn b/fuchsia_web/webengine/BUILD.gn
index 1004e511fd0a6..113715d9ac34b 100644
--- a/fuchsia_web/webengine/BUILD.gn
+++ b/fuchsia_web/webengine/BUILD.gn
@@ -491,6 +491,7 @@ fuchsia_package_installer("web_engine_installer") {
 fuchsia_package("web_engine_with_webui") {
   # TODO(fxbug.dev/100944): Add appropriate visibility when fixed.
   deps = [
+    ":web_instance_component",
     ":web_instance_component_cfv1",
     ":webui_resources",
   ]
diff --git a/fuchsia_web/webengine/web_instance.cml b/fuchsia_web/webengine/web_instance.cml
index a99d0d450467e..6fa3d8bca7225 100644
--- a/fuchsia_web/webengine/web_instance.cml
+++ b/fuchsia_web/webengine/web_instance.cml
@@ -77,6 +77,13 @@
       path: "/config/command-line",
       availability: "optional",
     },
+    // Temporary directory specified by WebInstanceHost.set_tmp_dir.
+    {
+      directory: "tmp",
+      path: "/tmp",
+      rights: [ "rw*" ],
+      availability: "optional",
+    },
     {
       // Required capabilities for all configurations.
       protocol: [
@@ -155,10 +162,5 @@
       ],
       availability: "optional",
     },
-    {
-      storage: "cache",
-      path: "/cache",
-      availability: "optional",
-    },
   ]
 }
diff --git a/fuchsia_web/webinstance_host/BUILD.gn b/fuchsia_web/webinstance_host/BUILD.gn
index 3a7b6d0e93cef..d51a0bb4af96f 100644
--- a/fuchsia_web/webinstance_host/BUILD.gn
+++ b/fuchsia_web/webinstance_host/BUILD.gn
@@ -29,7 +29,10 @@ source_set("webinstance_host") {
     "web_instance_host_internal.cc",
     "web_instance_host_internal.h",
   ]
-  public = [ "web_instance_host.h" ]
+  public = [
+    "web_instance_host.h",
+    "web_instance_host_constants.h",
+  ]
   deps = [
     "//base:base_static",
     "//build:chromecast_buildflags",
diff --git a/fuchsia_web/webinstance_host/web_instance_host.cc b/fuchsia_web/webinstance_host/web_instance_host.cc
index 28dbfd3aedf5f..86a69dd0fb444 100644
--- a/fuchsia_web/webinstance_host/web_instance_host.cc
+++ b/fuchsia_web/webinstance_host/web_instance_host.cc
@@ -20,6 +20,7 @@
 #include <vector>
 
 #include "base/check.h"
+#include "base/containers/fixed_flat_map.h"
 #include "base/fuchsia/fuchsia_logging.h"
 #include "base/fuchsia/process_context.h"
 #include "base/logging.h"
@@ -32,6 +33,7 @@
 #include "base/types/expected.h"
 #include "components/fuchsia_component_support/serialize_arguments.h"
 #include "fuchsia_web/webengine/switches.h"
+#include "fuchsia_web/webinstance_host/web_instance_host_constants.h"
 #include "fuchsia_web/webinstance_host/web_instance_host_internal.h"
 
 namespace {
@@ -43,6 +45,10 @@ namespace fcdecl = ::fuchsia::component::decl;
 constexpr char kWebInstanceComponentUrl[] =
     "fuchsia-pkg://fuchsia.com/web_engine#meta/web_instance.cm";
 
+// Test-only URL for web hosting Component instances with WebUI resources.
+const char kWebInstanceWithWebUiComponentUrl[] =
+    "fuchsia-pkg://fuchsia.com/web_engine_with_webui#meta/web_instance.cm";
+
 // The name of the component collection hosting the instances.
 constexpr char kCollectionName[] = "web_instances";
 
@@ -58,7 +64,8 @@ std::string InstanceNameFromId(const base::GUID& id) {
   return base::StrCat({kCollectionName, "_", id.AsLowercaseString()});
 }
 
-void DestroyChild(fuchsia::component::Realm& realm, const std::string& name) {
+void DestroyInstance(fuchsia::component::Realm& realm,
+                     const std::string& name) {
   realm.DestroyChild(
       fcdecl::ChildRef{.name = name, .collection = kCollectionName},
       [](::fuchsia::component::Realm_DestroyChild_Result destroy_result) {
@@ -67,8 +74,8 @@ void DestroyChild(fuchsia::component::Realm& realm, const std::string& name) {
       });
 }
 
-void DestroyChildDirectory(vfs::PseudoDir* instances_dir,
-                           const std::string& name) {
+void DestroyInstanceDirectory(vfs::PseudoDir* instances_dir,
+                              const std::string& name) {
   zx_status_t status = instances_dir->RemoveEntry(name);
   ZX_DCHECK(status == ZX_OK, status);
 }
@@ -138,13 +145,50 @@ class InstanceBuilder {
   // directory.
   void ServeCommandLine();
 
-  // Serves `directory` as `name` in the instance's subtree as a read-only or
-  // a read-write (if `writeable`) directory. `name` is both the name of the
-  // directory and the name of the capability expected by the instance.
-  void ServeDirectory(base::StringPiece name,
-                      std::unique_ptr<vfs::internal::Directory> directory,
+  // Adds offers from `void` for any offered directories that are not being
+  // served for the invoker.
+  void OfferMissingDirectoriesFromVoid();
+
+  // The directories that are optionally offered to `web_instance.cm` based on
+  // the invoker's configuration.
+  enum class OptionalDirectory {
+    kFirst = 0,
+    kCdmData = kFirst,
+    kCommandLineConfig,
+    kContentDirectories,
+    kData,
+    kTmp,
+    kCount,
+  };
+
+  // Returns a bitmask for `directory` for use with the `served_directories_`
+  // bitfield.
+  static uint32_t directory_bitmask(OptionalDirectory directory) {
+    return 1u << static_cast<int>(directory);
+  }
+
+  // Returns true if the host will serve `directory` to the instance.
+  bool is_directory_served(OptionalDirectory directory) const {
+    return served_directories_ & directory_bitmask(directory);
+  }
+
+  // Records that `directory` will be served to the instance.
+  void set_directory_served(OptionalDirectory directory) {
+    served_directories_ |= directory_bitmask(directory);
+  }
+
+  // Returns the capability and directory name for `directory`.
+  static base::StringPiece GetDirectoryName(OptionalDirectory directory);
+
+  // Serves `directory` as `offer` in the instance's subtree as a read-only or
+  // a read-write (if `writeable`) directory.
+  void ServeDirectory(OptionalDirectory directory,
+                      std::unique_ptr<vfs::internal::Directory> fs_directory,
                       bool writeable);
 
+  // Offers the directory `directory` from `void`.
+  void OfferDirectoryFromVoid(OptionalDirectory directory);
+
   // Offers the read-only directory capability named `name` from the parent.
   void OfferDirectoryFromParent(base::StringPiece name);
 
@@ -153,6 +197,10 @@ class InstanceBuilder {
   const std::string name_;
   raw_ptr<vfs::PseudoDir> instance_dir_;
   base::CommandLine args_;
+
+  // A bitfield of `directory_bitmask()` values indicating which optional
+  // directories are being served to the instance.
+  uint32_t served_directories_ = 0;
   std::vector<fuchsia::component::decl::Offer> dynamic_offers_;
   fidl::InterfaceRequest<fuchsia::web::Debug> debug_request_;
 };
@@ -197,7 +245,7 @@ InstanceBuilder::InstanceBuilder(fuchsia::component::Realm& realm,
 
 InstanceBuilder::~InstanceBuilder() {
   if (instance_dir_) {
-    DestroyChildDirectory(GetWebInstancesCollectionDir(), name_);
+    DestroyInstanceDirectory(GetWebInstancesCollectionDir(), name_);
   }
 }
 
@@ -222,7 +270,7 @@ void InstanceBuilder::ServeRootSslCertificates() {
 void InstanceBuilder::ServeDataDirectory(
     fidl::InterfaceHandle<fuchsia::io::Directory> data_directory) {
   DCHECK(instance_dir_);
-  ServeDirectory("data",
+  ServeDirectory(OptionalDirectory::kData,
                  std::make_unique<vfs::RemoteDir>(std::move(data_directory)),
                  /*writeable=*/true);
 }
@@ -244,7 +292,8 @@ zx_status_t InstanceBuilder::ServeContentDirectories(
     }
   }
 
-  ServeDirectory("content-directories", std::move(content_dirs),
+  ServeDirectory(OptionalDirectory::kContentDirectories,
+                 std::move(content_dirs),
                  /*writeable=*/false);
   return ZX_OK;
 }
@@ -253,13 +302,14 @@ void InstanceBuilder::ServeCdmDataDirectory(
     fidl::InterfaceHandle<fuchsia::io::Directory> cdm_data_directory) {
   DCHECK(instance_dir_);
   ServeDirectory(
-      "cdm_data",
+      OptionalDirectory::kCdmData,
       std::make_unique<vfs::RemoteDir>(std::move(cdm_data_directory)),
       /*writeable=*/true);
 }
 
 void InstanceBuilder::ServeTmpDirectory(fuchsia::io::DirectoryHandle tmp_dir) {
-  ServeDirectory("tmp", std::make_unique<vfs::RemoteDir>(std::move(tmp_dir)),
+  ServeDirectory(OptionalDirectory::kTmp,
+                 std::make_unique<vfs::RemoteDir>(std::move(tmp_dir)),
                  /*writeable=*/true);
 }
 
@@ -272,9 +322,20 @@ Instance InstanceBuilder::Build(
     fidl::InterfaceRequest<fuchsia::io::Directory> services_request) {
   ServeCommandLine();
 
+  // Create dynamic offers from `void` for any optional directories
+  // expected by web_instance.cm that are not being provided by the invoker.
+  OfferMissingDirectoriesFromVoid();
+
   fcdecl::Child child_decl;
   child_decl.set_name(name_);
-  child_decl.set_url(kWebInstanceComponentUrl);
+  // TODO(crbug.com/1010222): Make kWebInstanceComponentUrl a relative
+  // component URL and remove this workaround.
+  // TODO(crbug.com/1395054): Better yet, replace the with_webui component with
+  // direct routing of the resources from web_engine_shell.
+  child_decl.set_url(
+      base::CommandLine::ForCurrentProcess()->HasSwitch(switches::kWithWebui)
+          ? kWebInstanceWithWebUiComponentUrl
+          : kWebInstanceComponentUrl);
   child_decl.set_startup(fcdecl::StartupMode::LAZY);
 
   ::fuchsia::component::CreateChildArgs create_child_args;
@@ -335,17 +396,48 @@ void InstanceBuilder::ServeCommandLine() {
           }));
   ZX_DCHECK(status == ZX_OK, status);
 
-  ServeDirectory("command-line-config", std::move(config_dir),
+  ServeDirectory(OptionalDirectory::kCommandLineConfig, std::move(config_dir),
                  /*writeable=*/false);
 }
 
+void InstanceBuilder::OfferMissingDirectoriesFromVoid() {
+  for (auto directory = OptionalDirectory::kFirst;
+       directory != OptionalDirectory::kCount;
+       directory =
+           static_cast<OptionalDirectory>(static_cast<int>(directory) + 1)) {
+    if (!is_directory_served(directory)) {
+      OfferDirectoryFromVoid(directory);
+    }
+  }
+}
+
+// static
+base::StringPiece InstanceBuilder::GetDirectoryName(
+    OptionalDirectory directory) {
+  static constexpr auto kNames =
+      base::MakeFixedFlatMap<OptionalDirectory, base::StringPiece>({
+          {OptionalDirectory::kCdmData, "cdm_data"},
+          {OptionalDirectory::kCommandLineConfig, "command-line-config"},
+          {OptionalDirectory::kContentDirectories, "content-directories"},
+          {OptionalDirectory::kData, "data"},
+          {OptionalDirectory::kTmp, "tmp"},
+      });
+  static_assert(kNames.size() == static_cast<int>(OptionalDirectory::kCount));
+  return kNames.at(directory);
+}
+
 void InstanceBuilder::ServeDirectory(
-    base::StringPiece name,
-    std::unique_ptr<vfs::internal::Directory> directory,
+    OptionalDirectory directory,
+    std::unique_ptr<vfs::internal::Directory> fs_directory,
     bool writeable) {
   DCHECK(instance_dir_);
+  DCHECK(!is_directory_served(directory));
+
+  set_directory_served(directory);
+  const auto name = GetDirectoryName(directory);
+
   zx_status_t status =
-      instance_dir_->AddEntry(std::string(name), std::move(directory));
+      instance_dir_->AddEntry(std::string(name), std::move(fs_directory));
   ZX_DCHECK(status == ZX_OK, status);
 
   dynamic_offers_.push_back(fcdecl::Offer::WithDirectory(
@@ -360,6 +452,22 @@ void InstanceBuilder::ServeDirectory(
                     .set_availability(fcdecl::Availability::REQUIRED))));
 }
 
+void InstanceBuilder::OfferDirectoryFromVoid(OptionalDirectory directory) {
+  DCHECK(!is_directory_served(directory));
+
+  // TODO(fxbug.dev/121722): Enable this once dynamic offer-from-void is
+  // supported in Fuchsia.
+#if 0
+  const auto name = GetDirectoryName(directory);
+  dynamic_offers_.push_back(fcdecl::Offer::WithDirectory(
+      std::move(fcdecl::OfferDirectory()
+                    .set_source(fcdecl::Ref::WithVoidType({}))
+                    .set_target_name(std::string(name))
+                    .set_dependency_type(fcdecl::DependencyType::STRONG)
+                    .set_availability(fcdecl::Availability::OPTIONAL))));
+#endif
+}
+
 void InstanceBuilder::OfferDirectoryFromParent(base::StringPiece name) {
   DCHECK(instance_dir_);
   dynamic_offers_.push_back(fcdecl::Offer::WithDirectory(
@@ -446,7 +554,7 @@ WebInstanceHost::WebInstanceHost() {
 
 WebInstanceHost::~WebInstanceHost() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  DCHECK(instances_.empty());
+  Uninitialize();
 }
 
 zx_status_t WebInstanceHost::CreateInstanceForContextWithCopiedArgs(
@@ -530,28 +638,29 @@ void WebInstanceHost::Initialize() {
 
 void WebInstanceHost::Uninitialize() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  DCHECK(instances_.empty());
+
+  // Destroy all child instances and each one's outgoing directory subtree.
+  auto* const instances_dir = GetWebInstancesCollectionDir();
+  for (auto& [id, binder_ptr] : instances_) {
+    const std::string name(InstanceNameFromId(id));
+    if (realm_) {
+      DestroyInstance(*realm_, name);
+    }
+    DestroyInstanceDirectory(instances_dir, name);
+    binder_ptr.Unbind();
+  }
+  instances_.clear();
 
   realm_.Unbind();
 
   // Note: the entry in the outgoing directory for the top-level instances dir
-  // is leaked in case multiple hosts are active in the same process.
+  // is leaked in support of having multiple hosts active in a single process.
 }
 
 void WebInstanceHost::OnRealmError(zx_status_t status) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   ZX_LOG(ERROR, status) << "RealmBuilder channel error";
-
-  // Disconnect from all children and remove their directories.
-  auto* const instances_dir = GetWebInstancesCollectionDir();
-  for (auto& [id, binder_ptr] : instances_) {
-    DestroyChildDirectory(instances_dir, InstanceNameFromId(id));
-    binder_ptr.Unbind();
-  }
-  instances_.clear();
-
-  // Go back to the initial state.
   Uninitialize();
 }
 
@@ -561,10 +670,10 @@ void WebInstanceHost::OnComponentBinderClosed(const base::GUID& id,
 
   // Destroy the child instance.
   const std::string name(InstanceNameFromId(id));
-  DestroyChild(*realm_, name);
+  DestroyInstance(*realm_, name);
 
   // Drop the directory subtree for the child instance.
-  DestroyChildDirectory(GetWebInstancesCollectionDir(), name);
+  DestroyInstanceDirectory(GetWebInstancesCollectionDir(), name);
 
   // Drop the hold on the instance's Binder. Note: destroying the InterfacePtr
   // here also deletes the lambda into which `id` was bound, so `id` must not
diff --git a/fuchsia_web/webinstance_host/web_instance_host.h b/fuchsia_web/webinstance_host/web_instance_host.h
index 2eaa9effe8693..9363d80653654 100644
--- a/fuchsia_web/webinstance_host/web_instance_host.h
+++ b/fuchsia_web/webinstance_host/web_instance_host.h
@@ -77,8 +77,8 @@ class WebInstanceHost {
   // Connects to the fuchsia.component/Realm protocol.
   void Initialize();
 
-  // Unbinds from the fuchsia.component/Realm protocol. May only be called once
-  // all web_instances have terminated.
+  // Destroys all child instances and associated resources and unbinds from the
+  // fuchsia.component/Realm protocol.
   void Uninitialize();
 
   // Error handler for the channel to RealmBuilder.
diff --git a/fuchsia_web/webinstance_host/web_instance_host.shard.cml b/fuchsia_web/webinstance_host/web_instance_host.shard.cml
index 17b66ebdd78b4..0b3165231867d 100644
--- a/fuchsia_web/webinstance_host/web_instance_host.shard.cml
+++ b/fuchsia_web/webinstance_host/web_instance_host.shard.cml
@@ -56,7 +56,6 @@
         "fuchsia.memorypressure.Provider",
         "fuchsia.process.Launcher",
         "fuchsia.sysmem.Allocator",
-        "fuchsia.tracing.provider.Registry",
       ],
       from: "parent",
       to: "#web_instances",
@@ -78,12 +77,6 @@
       from: "parent",
       to: "#web_instances",
       availability: "optional",
-      source_availability: "unknown",
-    },
-    {
-      storage: "cache",
-      from: "parent",
-      to: "#web_instances",
     },
   ],
 }
diff --git a/fuchsia_web/webinstance_host/web_instance_host_internal.cc b/fuchsia_web/webinstance_host/web_instance_host_internal.cc
index 1f8776d3a5153..9c7d064c33303 100644
--- a/fuchsia_web/webinstance_host/web_instance_host_internal.cc
+++ b/fuchsia_web/webinstance_host/web_instance_host_internal.cc
@@ -434,6 +434,8 @@ void AppendDynamicServices(fuchsia::web::ContextFeatureFlags features,
      "fuchsia.media.AudioDeviceEnumerator"},
     {ContextFeatureFlags::AUDIO, ContextFeatureFlags::AUDIO,
      "fuchsia.media.SessionAudioConsumerFactory"},
+    {ContextFeatureFlags::VULKAN, ContextFeatureFlags::VULKAN,
+     "fuchsia.tracing.provider.Registry"},
     {ContextFeatureFlags::VULKAN, ContextFeatureFlags::VULKAN,
      "fuchsia.vulkan.loader.Loader"},
     {ContextFeatureFlags::HARDWARE_VIDEO_DECODER,
diff --git a/fuchsia_web/webinstance_host/web_instance_host_v1.cc b/fuchsia_web/webinstance_host/web_instance_host_v1.cc
index 7de75f25bfec5..dd7e08ae1104b 100644
--- a/fuchsia_web/webinstance_host/web_instance_host_v1.cc
+++ b/fuchsia_web/webinstance_host/web_instance_host_v1.cc
@@ -146,7 +146,6 @@ std::vector<std::string> GetRequiredServicesForConfig(
       "fuchsia.settings.Display",  // Used if preferred theme is DEFAULT.
       "fuchsia.sysmem.Allocator",
       "fuchsia.tracing.perfetto.ProducerConnector",
-      "fuchsia.tracing.provider.Registry",
       "fuchsia.ui.scenic.Scenic"};
 
   // TODO(crbug.com/1209031): Provide these conditionally, once corresponding
@@ -186,6 +185,7 @@ std::vector<std::string> GetRequiredServicesForConfig(
 
   if ((features & fuchsia::web::ContextFeatureFlags::VULKAN) ==
       fuchsia::web::ContextFeatureFlags::VULKAN) {
+    services.emplace_back("fuchsia.tracing.provider.Registry");
     services.emplace_back("fuchsia.vulkan.loader.Loader");
   }