Reliably getting favicons in Chrome extensions, chrome://favicon?

Erik Rothoff picture Erik Rothoff · May 19, 2012 · Viewed 9.3k times · Source

I'm using the chrome://favicon/ in my Google Chrome extension to get the favicon for RSS feeds. What I do is get the base path of linked page, and append it to chrome://favicon/http://<domainpath>.

It's working really unreliably. A lot of the time it's reporting the standard "no-favicon"-icon, even when the page really has a favicon. There is almost 0 documentation regarding the chrome://favicon mechanism, so it's difficult to understand how it actually works. Is it just a cache of links that have been visited? Is it possible to detect if there was an icon or not?

From some simple testing it's just a cache of favicons for pages you have visited. So if I subscribe to dribbble.com's RSS feed, it won't show a favicon in my extension. Then if I visit chrome://favicon/http://dribbble.com/ it won't return right icon. Then I open dribbble.com in another tab, it shows its icon in the tab, then when I reload the chrome://favicon/http://dribbble.com/-tab, it will return the correct favicon. Then I open my extensions popup and it still shows the standard icon. But if I then restart Chrome it will get the correct icon everywhere.

Now that's just from some basic research, and doesn't get me any closer to a solution. So my question is: Is the chrome://favicon/ a correct use-case for what I'm doing. Is there any documentation for it? And what is this its intended behavior?

Answer

joelpt picture joelpt · May 20, 2012

I've seen this problem as well and it's really obnoxious.

From what I can tell, Chrome populates the chrome://favicon/ cache after you visit a URL (omitting the #hash part of the URL if any). It appears to usually populate this cache sometime after a page is completely loaded. If you try to access chrome://favicon/http://yoururl.com before the associated page is completely loaded you will often get back the default 'globe icon'. Subsequently refreshing the page you're displaying the icon(s) on will then fix them.

So, if you can, possibly just refreshing the page you're displaying the icons on just prior to displaying it to the user may serve as a fix.

In my use case, I am actually opening tabs which I want to obtain the favicons from. So far the most reliable approach I have found to obtain them looks roughly like this:

chrome.webNavigation.onCompleted.addListener(onCompleted);

function onCompleted(details)
{
    if (details.frameId > 0)
    {
        // we don't care about activity occurring within a subframe of a tab
        return;
    }

    chrome.tabs.get(details.tabId, function(tab) {
        var url = tab.url ? tab.url.replace(/#.*$/, '') : ''; // drop #hash
        var favicon;
        var delay;

        if (tab.favIconUrl && tab.favIconUrl != '' 
            && tab.favIconUrl.indexOf('chrome://favicon/') == -1) {
            // favicon appears to be a normal url
            favicon = tab.favIconUrl;
            delay = 0;
        }
        else {
            // couldn't obtain favicon as a normal url, try chrome://favicon/url
            favicon = 'chrome://favicon/' + url;
            delay = 100; // larger values will probably be more reliable
        }

        setTimeout(function() {
            /// set favicon wherever it needs to be set here
            console.log('delay', delay, 'tabId', tab.id, 'favicon', favicon);
        }, delay);
    });
}

This approach returns the correct favicon about 95% of the time for new URLs, using delay=100. Increasing the delay if you can accept it will increase the reliability (I'm using 1500ms for my use case and it misses <1% of the time on new URLs; this reliability worsens when many tabs are being opened simultaneously). Obviously this is a pretty imprecise way of making it work but it is the best method I've figured out so far.

Another possible approach is to instead pull favicons from http://www.google.com/s2/favicons?domain=somedomain.com. I don't like this approach very much as it requires accessing the external network, relies on a service that has no guarantee of being up, and is itself somewhat unreliable; I have seen it inconsistently return the "globe" icon for a www.domain.com URL yet return the proper icon for just domain.com.

Hope this helps in some way.