Chrome Manifest V3 brings a new API to fetch website favicons in extensions
There are too many interesting articles on the internet and too little time to read them all. One day when my “read later” bookmark folder reached 200 pages, I concluded that there is no way that I am going to read them all without a habit change. Like any software engineer I have decided to write some software to solve my problem. This is how a new extension was born to display my read later bookmarks in Chrome new tab page and give me constant reminder of unread articles.
Shortly after releasing my extension, Google announced transition to Manifest V3. My extension was a couple hundred lines of code so I thought that it would be piece of cake to migrate to Manifest V3. My thinking quickly changed after the first run in MV3 mode. The good part is that all my code on top of bookmark API worked as before with bonus of being promise based. The bad part is that all favicons for bookmarks failed to load. Not having favicons next to bookmarks would be a big UI downgrade. How do you display favicons in MV3? Well, it turns out that Google simply forgot (down prioritized) to implement this feature in MV3. Ups.
Recently, Google has finally filled the feature gap. We have a new API to access website favicons. API is slightly different from MV2, but still quite easy to use. Time to migrate my new tab bookmark extension to MV3.
Favicon URL is formed using chrome-extension protocol as before, but now all requests are routed through your extension using extension id. Target website is provided using pageUrl query parameter. And you can still request a specific favicon size with a size query parameter.
chrome-extension://EXTENSION_ID/_favicon/?pageUrl=htts%3A%2F%2Fextension.ninja&size=16
Additionally, there is a new permission required: “favicon”.
{
"permissions": ["favicon"]
}
If you want to load favicons in your content scripts, there is more configuration you need to do. You need to expose “_favicon” folder as web accessible path.
{
"web_accessible_resources": [
{
"resources": ["_favicon/*"],
"matches": ["<all_urls>"],
"extension_ids": ["*"]
}
]
}
Lastly, it is a good idea to generate favicon programmatically since your extension ID at dev and release time may be different. You can do that using chrome.runtime.getURL method.
chrome.runtime.getURL("/_favicon/")
I restored my extension functionality using the new favicon API. Now I am waiting for a Chrome Web Store validation triggered by a new permission added 🙁 Unfortunately, users will also be prompted about the new permission, and I will lose some of the users who will get spooked by it. Favicon permission does not cause a warning if you already have “tabs” or host permissions.