{"id":145,"date":"2026-01-13T02:00:28","date_gmt":"2026-01-13T02:00:28","guid":{"rendered":"https:\/\/blogs.igalia.com\/mshin\/?p=145"},"modified":"2026-01-13T02:00:28","modified_gmt":"2026-01-13T02:00:28","slug":"our-journey-to-support-extensions-for-embedders","status":"publish","type":"post","link":"https:\/\/blogs.igalia.com\/mshin\/2026\/01\/13\/our-journey-to-support-extensions-for-embedders\/","title":{"rendered":"Our Journey to support Extensions for embedders"},"content":{"rendered":"\n<h1 class=\"wp-block-heading\"><strong>A History of Extensions for Embedders \u2014 and Where We\u2019re Heading<\/strong><\/h1>\n\n\n\n<p>Chromium\u2019s Extensions platform has long been a foundational part of the desktop browsing experience. Major Chromium-based browsers\u2014such as Chrome and Microsoft Edge\u2014ship with full support for the Chrome Extensions ecosystem, and user expectations around extension availability and compatibility continue to grow.<\/p>\n\n\n\n<p>In contrast, some Chromium embedders\u2014 for instance, products built directly on the \/\/content API without the full \/\/chrome stack\u2014do not naturally have access to Extensions. Similarly, the traditional Chrome for Android app does not support Extensions. While some embedders have attempted to enable limited Extensions functionality by pulling in selected pieces of the \/\/chrome layer, this approach is heavyweight, difficult to maintain, and fundamentally incapable of delivering full feature parity.<\/p>\n\n\n\n<p>At Igalia we have been willing to help on the long term-goal of making Extensions usable on lightweight, \/\/content-based products, without requiring embedders to depend on \/\/chrome. This post outlines the background of that effort, the phases of work so far, the architectural challenges involved, and where the project is headed.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"><strong>Note:<\/strong> ChromeOS supporting extensions (ChromeOS has <a href=\"https:\/\/blog.chromium.org\/2024\/06\/building-faster-smarter-chromebook.html\" data-type=\"link\" data-id=\"https:\/\/blog.chromium.org\/2024\/06\/building-faster-smarter-chromebook.html\">announced<\/a> plans to incorporate more of the Android build stack) is not the same thing as Chrome-Android App supporting extensions. The two codepaths and platform constraints differ significantly. While the traditional Chrome app on Android phones and tablets still does not officially support extensions, recent beta builds of desktop-class Chrome on Android have begun to close this gap by enabling native extension installation and execution.<br><br>Tracking bug: <a href=\"https:\/\/issues.chromium.org\/issues\/356905053\">https:\/\/issues.chromium.org\/issues\/356905053<\/a><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Extensions Architecture \u2014 Layered View<\/h3>\n\n\n\n<p>The following diagram illustrates the architectural evolution of Extensions support for Chromium embedders.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Traditional Chromium Browser Stack<\/h4>\n\n\n\n<p>At the top of the stack, Chromium-based browsers such as Chrome and Edge rely on the full <code>\/\/chrome<\/code> layer. Historically, the Extensions platform has lived deeply inside this layer, tightly coupled with Chrome-specific concepts such as <code>Profile<\/code>, browser windows, UI surfaces, and Chrome services.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>+-----------------------+\n|      \/\/chrome         |\n|  (UI, Browser, etc.)  |\n+-----------------------+\n|     \/\/extensions      |\n+-----------------------+\n|      \/\/content        |\n+-----------------------+\n<\/code><\/pre>\n\n\n\n<p>This architecture works well for full browsers, but it is problematic for embedders. Products built directly on <code>\/\/content<\/code> cannot reuse Extensions without pulling in a large portion of <code>\/\/chrome<\/code>, leading to high integration and maintenance costs.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\" \/>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Phase 1 \u2014 Extensions on Android (Downstream Work)<\/strong><\/h3>\n\n\n\n<p>In 2023, a downstream project at Igalia required extension support on a Chromium-based <strong>Android<\/strong> application. The scope was limited\u2014we only needed to support a small number of specific extensions\u2014so we implemented:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>basic installation logic,<\/li>\n\n\n\n<li>manifest handling,<\/li>\n\n\n\n<li>extension launch\/execution flows, and<\/li>\n\n\n\n<li>a minimal subset of Extensions APIs that those extensions depended on.<\/li>\n<\/ul>\n\n\n\n<p>This work demonstrated that Extensions <em>can<\/em> function in an Android environment. However, it also highlighted a major problem: <strong>modifying the Android <code>\/\/chrome<\/code> codepath is expensive<\/strong>. Rebasing costs are high, upstream alignment is difficult, and the resulting solution is tightly coupled to Chrome-specific abstractions. The approach was viable only because the downstream requirements were narrow and controlled.<\/p>\n\n\n\n<p>I shared this experience at <a href=\"https:\/\/youtu.be\/FYYi_XiyL74?si=jG6ZrqZANRygo6AJ&amp;t=300\"><strong>BlinkOn Lightning Talk: &#8220;Extensions on Android&#8221;<\/strong><\/a>.<\/p>\n\n\n\n<figure class=\"wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio\"><div class=\"wp-block-embed__wrapper\">\n<iframe loading=\"lazy\" title=\"Pre-Recorded Lightning Talks Day 2 [BlinkOn 20]\" width=\"660\" height=\"371\" src=\"https:\/\/www.youtube.com\/embed\/FYYi_XiyL74?start=300&#038;feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" referrerpolicy=\"strict-origin-when-cross-origin\" allowfullscreen><\/iframe>\n<\/div><\/figure>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\" \/>\n\n\n\n<h3 class=\"wp-block-heading\">Phase 2 \u2014 Extensions for Embedders <br>( \/\/content + \/\/extensions + \/\/components\/extensions )<\/h3>\n\n\n\n<p>Following Phase 1, we began asking a broader question:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p><em>Can we provide a reusable, upstream-friendly Extensions implementation that works for embedders without pulling in the <code>\/\/chrome<\/code> layer?<\/em><\/p>\n<\/blockquote>\n\n\n\n<h4 class=\"wp-block-heading\">Motivation<\/h4>\n\n\n\n<p>Many embedders aim to remain as lightweight as possible. Requiring <code>\/\/chrome<\/code> introduces unnecessary complexity, long build times, and ongoing maintenance costs. Our hypothesis was that <strong>large portions of the Extensions stack could be decoupled from Chrome and reused directly by content-based products<\/strong>.<\/p>\n\n\n\n<p>One early idea was to componentize the Extensions code by migrating substantial parts of <code>\/\/chrome\/*\/extensions<\/code> into <code>\/\/components\/extensions<\/code>.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>+-------------------------+\n| \/\/components\/extensions |\n+-------------------------+\n|      \/\/extensions       |\n+-------------------------+\n|       \/\/content         |\n+-------------------------+<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Proof-of-concept : Wolvic<\/h4>\n\n\n\n<p>We tested this idea through <a href=\"https:\/\/www.wolvic.com\/en\/\">Wolvic <\/a>, a VR browser used in several commercial<br>solutions.  Wolvic has two implementations:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>a Gecko-based version, and <\/li>\n\n\n\n<li>a Chromium-based version built directly on the <code>\/\/content<\/code> API.<\/li>\n<\/ul>\n\n\n\n<p><br>Originally, Extensions were already supported in Wolvic-Gecko, but not in Wolvic-Chromium. To close that gap, we migrated core pieces of the Extensions machinery into <code>\/\/components\/extensions<\/code> and enabled extension loading and execution in a content-only environment.<\/p>\n\n\n\n<p>By early 2025, this work successfully demonstrated that Extensions could run without the <code>\/\/chrome<\/code> layer.<\/p>\n\n\n\n<p>Demo video::<br><a href=\"https:\/\/youtube.com\/shorts\/JmQnpC-lxR8?si=Xf0uB6q__j4pmlSj\">https:\/\/youtube.com\/shorts\/JmQnpC-lxR8?si=Xf0uB6q__j4pmlSj<\/a><\/p>\n\n\n\n<p>Design document:<br><a href=\"https:\/\/docs.google.com\/document\/d\/1I5p4B0XpypR7inPqq1ZnGMP4k-IGeOpKGvCFS0EDWHk\/edit?usp=sharing\">https:\/\/docs.google.com\/document\/d\/1I5p4B0XpypR7inPqq1ZnGMP4k-IGeOpKGvCFS0EDWHk\/edit?usp=sharing<\/a><\/p>\n\n\n\n<p>However, this work lived entirely in the Wolvic repository, which is a fork of Chromium. While open source, this meant that other embedders could not easily benefit without additional rebasing and integration work.<\/p>\n\n\n\n<p>This raised an important question:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p>Why not do this work directly in the Chromium upstream so that all embedders can benefit?<\/p>\n<\/blockquote>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\" \/>\n\n\n\n<h3 class=\"wp-block-heading\">Phase 3 \u2014 Extensions for Embedders<br>(\/\/content + \/\/extensions)<\/h3>\n\n\n\n<p>Following discussions with the Extensions owner (rdevlin.cronin@chromium.org), we refined the approach further.<\/p>\n\n\n\n<p>Rather than migrating functionality into <code>\/\/components<\/code>, the preferred long-term direction is to <strong>move Extensions logic directly into the <code>\/\/extensions<\/code> layer wherever possible<\/strong>.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>+-----------------------+\n|      Embedder UI      | (minimal interfaces)\n+-----------------------+\n|      \/\/extensions     |\n+-----------------------+\n|       \/\/content       |\n+-----------------------+<\/code><\/pre>\n\n\n\n<p>This approach offers several advantages:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>clearer layering and ownership,<\/li>\n\n\n\n<li>fewer architectural violations,<\/li>\n\n\n\n<li>reduced duplication between Chrome and embedders,<\/li>\n\n\n\n<li>a cleaner API surface for integration.<\/li>\n<\/ul>\n\n\n\n<p>We aligned on this direction and began upstream work accordingly.<\/p>\n\n\n\n<p>Tracking bug: \ud83d\udd17 <a href=\"https:\/\/issues.chromium.org\/issues\/358567092\">https:\/\/issues.chromium.org\/issues\/358567092<\/a><\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"697\" height=\"366\" src=\"https:\/\/blogs.igalia.com\/mshin\/files\/2026\/01\/image.png\" alt=\"\" class=\"wp-image-151\" srcset=\"https:\/\/blogs.igalia.com\/mshin\/files\/2026\/01\/image.png 697w, https:\/\/blogs.igalia.com\/mshin\/files\/2026\/01\/image-580x305.png 580w\" sizes=\"auto, (max-width: 697px) 100vw, 697px\" \/><\/figure>\n\n\n\n<h4 class=\"wp-block-heading\">Our goals for Content Shell + \/\/extensions are:<\/h4>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Embedders should only implement a small set of interfaces, primarily for UI surfaces (install prompts, permission dialogs) and optional behaviors.<\/li>\n\n\n\n<li><strong>Full Web Extensions APIs support<\/strong> <br>w3c standard : <a href=\"https:\/\/w3c.github.io\/webextensions\/specification\/\">https:\/\/w3c.github.io\/webextensions\/specification\/<\/a><\/li>\n\n\n\n<li><strong>Chrome Web Store compatibility<\/strong><br>Embedders should be able to install and run extensions directly from the Chrome Web Store.<\/li>\n<\/ol>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\" \/>\n\n\n\n<h4 class=\"wp-block-heading\"><strong>Short-term Goal: Installation Support<\/strong><\/h4>\n\n\n\n<p>Our immediate milestone is to make <strong>installation<\/strong> work entirely using \/\/content + \/\/extensions.<\/p>\n\n\n\n<p><strong>Current progress:<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\u2705 <code>.zip<\/code> installation support already lives in \/\/extensions<\/li>\n\n\n\n<li>\ud83d\udea7 Migrating <strong>Unpacked directory installation<\/strong> from \/\/chrome to \/\/extensions<br>(including replacing Profile with BrowserContext abstractions)<\/li>\n\n\n\n<li>\ud83d\udd1c Moving <strong>.crx installation<\/strong> code from \/\/chrome \u2192 \/\/extensions<br><br>As part of this effort, we are introducing <strong>clean, well-defined interfaces<\/strong> for install prompts and permission confirmations:<\/li>\n\n\n\n<li>Chrome will continue to provide its full-featured UI<\/li>\n\n\n\n<li>Embedders can implement minimal, custom UI as needed<\/li>\n<\/ul>\n\n\n\n<p><strong>What Comes Next<\/strong>:<\/p>\n\n\n\n<p>Once installation is fully supported, we will move on to:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Chrome Web Store integration flows<\/li>\n\n\n\n<li>Core WebExtensions APIs required by commonly used extensions<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\" \/>\n\n\n\n<h4 class=\"wp-block-heading\"><strong>Main Engineering Challenge \u2014 Detaching from the Chrome Layer<\/strong><\/h4>\n\n\n\n<p>The hardest part of this migration is not moving files\u2014it is <strong>breaking long-standing dependencies on the <code>\/\/chrome<\/code> layer<\/strong>.<\/p>\n\n\n\n<p>The Extensions codebase is large and historically coupled to Chrome-only concepts such as:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>Profile<\/code><\/li>\n\n\n\n<li><code>Browser<\/code><\/li>\n\n\n\n<li>Chrome-specific <code>WebContents<\/code> delegates<\/li>\n\n\n\n<li>Chrome UI surfaces<\/li>\n\n\n\n<li>Chrome services (sync, signin, prefs)<\/li>\n<\/ul>\n\n\n\n<p>Each migration requires careful refactoring, layering reviews, and close collaboration with component owners. While the process is slow, it has already resulted in meaningful architectural improvements.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\" \/>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>What&#8217;s Next?<\/strong><\/h3>\n\n\n\n<p>In the next post, We\u2019ll demonstrate:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p><strong>A functioning version of Extensions running on top of<br>\/\/content + \/\/extensions only \u2014 capable of installing and running extensions app.<\/strong><\/p>\n<\/blockquote>\n\n\n\n<p>from Igalia side, we continue working on ways to make easier integrating Chromium on other platforms, etc. This will mark the first end-to-end, \/\/chrome-free execution path for extensions in content-based browsers.<\/p>\n\n\n\n<p>Stay tuned!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>A History of Extensions for Embedders \u2014 and Where We\u2019re Heading Chromium\u2019s Extensions platform has long been a foundational part of the desktop browsing experience. Major Chromium-based browsers\u2014such as Chrome and Microsoft Edge\u2014ship with full support for the Chrome Extensions ecosystem, and user expectations around extension availability and compatibility continue to grow. In contrast, some &hellip; <a href=\"https:\/\/blogs.igalia.com\/mshin\/2026\/01\/13\/our-journey-to-support-extensions-for-embedders\/\" class=\"more-link\">Continue reading <span class=\"screen-reader-text\">Our Journey to support Extensions for embedders<\/span><\/a><\/p>\n","protected":false},"author":58,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[2,3],"tags":[4,10,6],"class_list":["post-145","post","type-post","status-publish","format-standard","hentry","category-chromium","category-igalia","tag-chromium","tag-extensions","tag-igalia"],"_links":{"self":[{"href":"https:\/\/blogs.igalia.com\/mshin\/wp-json\/wp\/v2\/posts\/145","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blogs.igalia.com\/mshin\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blogs.igalia.com\/mshin\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blogs.igalia.com\/mshin\/wp-json\/wp\/v2\/users\/58"}],"replies":[{"embeddable":true,"href":"https:\/\/blogs.igalia.com\/mshin\/wp-json\/wp\/v2\/comments?post=145"}],"version-history":[{"count":7,"href":"https:\/\/blogs.igalia.com\/mshin\/wp-json\/wp\/v2\/posts\/145\/revisions"}],"predecessor-version":[{"id":157,"href":"https:\/\/blogs.igalia.com\/mshin\/wp-json\/wp\/v2\/posts\/145\/revisions\/157"}],"wp:attachment":[{"href":"https:\/\/blogs.igalia.com\/mshin\/wp-json\/wp\/v2\/media?parent=145"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blogs.igalia.com\/mshin\/wp-json\/wp\/v2\/categories?post=145"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blogs.igalia.com\/mshin\/wp-json\/wp\/v2\/tags?post=145"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}