485

I have a web application that's branded according to the user that's currently logged in. I'd like to change the favicon of the page to be the logo of the private label, but I'm unable to find any code or any examples of how to do this. Has anybody successfully done this before?

I'm picturing having a dozen icons in a folder, and the reference to which favicon.ico file to use is just generated dynamically along with the HTML page. Thoughts?

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
SqlRyan
  • 33,116
  • 33
  • 114
  • 199
  • 60
    There is an [arcade game](http://www.p01.org/releases/DEFENDER_of_the_favicon/) in a favicon. – Corey Trager Nov 04 '08 at 04:16
  • 19
    The link for the arcade game changed. [This](http://www.p01.org/defender_of_the_favicon/) is the correct one. – Basil Jun 01 '16 at 13:24
  • See http://stackoverflow.com/questions/6296574/dynamic-favicon-with-count-like-gmail on how to dynamically update the favicon by drawing on top of a template image with canvas. – handle Aug 20 '16 at 09:37
  • 2
    Small bug in the code example provided in the accepted answer. I do not have sufficient reputation score to comment on answers, hence writing here instead. The last line has the parentheses swapped: }()); should read })(); It would be nice that the code example becomes updated since it is most likely copied and pasted by others. – Goran W Apr 21 '17 at 11:27
  • 4
    @CoreyTrager The url changed : http://www.p01.org/defender_of_the_favicon/ – Clément Oct 05 '17 at 14:37

18 Answers18

572

Why not?

var link = document.querySelector("link[rel~='icon']");
if (!link) {
    link = document.createElement('link');
    link.rel = 'icon';
    document.head.appendChild(link);
}
link.href = 'https://stackoverflow.com/favicon.ico';
user3840170
  • 26,597
  • 4
  • 30
  • 62
keparo
  • 33,450
  • 13
  • 60
  • 66
  • 2
    I'm thinking this is close to what I'm looking for, but how would I get the appropriate HREF from the database. I suppose I'll have to do a server lookup from javascript, but I don't want it to get too complicated. Thanks for the tip. – SqlRyan Nov 04 '08 at 04:57
  • Sure, you can always look them up from a database or a filesystem. If there are only a few, you could simply hard code an array of strings. – keparo Nov 04 '08 at 05:26
  • 39
    Since this doesn’t work in IE anyway, you can remove `shortcut` from the `rel` attribute. [`shortcut` is an invalid IE-proprietary link relation!](http://mathiasbynens.be/notes/rel-shortcut-icon) – Mathias Bynens Jun 07 '10 at 12:45
  • 9
    You could just as easily look for an existing favicon link and update it or replace it. – keparo Mar 31 '11 at 23:51
  • 8
    Google can give you a site's favicon by using this url, replacing stackoverflow.com with the domain you want: http://s2.googleusercontent.com/s2/favicons?domain=stackoverflow.com – kirb Oct 03 '11 at 04:20
  • +1 because it works! But you should prefix it with unary operator, like `+` or `-` or whatever like so `+function(){/*CHANGE ICON*/}()`, or to put function object between two `()` like `(function(){/*CHANGE ICON*/})()`, so it gets executed... ;) – Cipi Oct 12 '11 at 09:57
  • 7
    Should entering this in the Javascript console in Chrome work? I can't get it to change favicons on various sites that way. – powerj1984 May 25 '13 at 01:46
  • @keparo no, you can't. At least Firefox is ignoring a changing href on the link-tag, which doesn't effectively change the displayed icon. – Andy Nov 05 '13 at 14:42
  • @Andy- It was possible on November 4, 2008, but that was five years and one day ago. Mileage may vary according to the browser, as well as factors like whether you are replacing an existing value versus applying a new link element, etc. – keparo Nov 06 '13 at 05:15
  • @Andy Firefox doesn't support changing the href (it will not update), but it do support removing the old link node and adding a new one. You can cloneNode() the old one, change href, and then replaceChild() it, as per Mathias Bynens answer. – jishi Nov 18 '13 at 07:29
  • A note for anyone trying this in Firefox like I was: you can't use a file:// URL to the icon (changing it in Grasemonkey). Probably an edge case for most people, and rather obvious in retrospect (security issues), but it took me a bit to realize that was my problem. – Tarka May 01 '14 at 19:05
106

Here’s some code that works in Firefox, Opera, and Chrome (unlike every other answer posted here). Here is a different demo of code that works in IE11 too. The following example might not work in Safari or Internet Explorer.

/*!
 * Dynamically changing favicons with JavaScript
 * Works in all A-grade browsers except Safari and Internet Explorer
 * Demo: http://mathiasbynens.be/demo/dynamic-favicons
 */

// HTML5™, baby! http://mathiasbynens.be/notes/document-head
document.head = document.head || document.getElementsByTagName('head')[0];

function changeFavicon(src) {
 var link = document.createElement('link'),
     oldLink = document.getElementById('dynamic-favicon');
 link.id = 'dynamic-favicon';
 link.rel = 'shortcut icon';
 link.href = src;
 if (oldLink) {
  document.head.removeChild(oldLink);
 }
 document.head.appendChild(link);
}

You would then use it as follows:

var btn = document.getElementsByTagName('button')[0];
btn.onclick = function() {
 changeFavicon('http://www.google.com/favicon.ico');
};

Fork away or view a demo.

robocat
  • 5,293
  • 48
  • 65
Mathias Bynens
  • 144,855
  • 52
  • 216
  • 248
  • The [Chrome bug](http://code.google.com/p/chromium/issues/detail?id=9982) was fixed in Chrome 6 (released Sep 10), so the Chrome hack isn't really necessary anymore -- in fact, I'd strongly suggest not using it since it breaks the forward button. – josh3736 Apr 29 '11 at 01:17
  • The Chrome bug might have been fixed, but it’s broken again in 14.0.835.187. – danorton Oct 07 '11 at 21:05
  • The [demo](http://mathiasbynens.be/demo/dynamic-favicons) isn't working for me with Chrome 21/WinXP. – Hugo Sep 08 '12 at 09:47
  • Demo isn't working for me in Chrome 26/Win7. `document.head || document.head = document.getElementsByTagName('head')[0];` `Uncaught ReferenceError: Invalid left-hand side in assignment` – Patrick May 07 '13 at 20:20
  • Is there any reason why this wouldn't work with using a base 64 encoded image string as the source? – powerj1984 May 25 '13 at 03:11
  • @powerj1984 `data` URLs aren’t supported in old IE. Also note that IE only supports `.ico` favicons. – Mathias Bynens May 26 '13 at 15:35
  • 2
    This works in all currently supported browsers (IE 11, Edge, FF, and Chrome) unable to test with safari – Aaron Feb 02 '16 at 20:55
  • @MathiasBynens Is it possible to set favicon dynamically for a PDF which is opened in a new tab? – SE_User Mar 13 '17 at 06:05
  • Your demo is broken, likely because of http to google instead of https – mplungjan Feb 10 '19 at 06:54
  • @mplungjan Woah, this is an old demo! Fixed. – Mathias Bynens Feb 18 '19 at 16:56
55

If you have the following HTML snippet:

<link id="favicon" rel="shortcut icon" type="image/png" href="favicon.png" />

You can change the favicon using Javascript by changing the HREF element on this link, for instance (assuming you're using JQuery):

$("#favicon").attr("href","favicon2.png");

You can also create a Canvas element and set the HREF as a ToDataURL() of the canvas, much like the Favicon Defender does.

fserb
  • 4,004
  • 2
  • 26
  • 23
  • 2
    I'd think by the time the JS runs, the browser will already have seen the link and tried to load `favicon.png`. This might need to be done server-side. – cHao Jul 13 '12 at 14:42
  • 2
    If you don't use JQuery, you can change the `href` attribute of `#favicon` using `document.getElementById('favicon').setAttribute('href','favicon2.png')` Maybe you can add it to your post @fserb? – johannchopin Apr 22 '20 at 12:53
47

jQuery Version:

$("link[rel='shortcut icon']").attr("href", "favicon.ico");

or even better:

$("link[rel*='icon']").attr("href", "favicon.ico");

Vanilla JS version:

document.querySelector("link[rel='shortcut icon']").href = "favicon.ico";

document.querySelector("link[rel*='icon']").href = "favicon.ico";
ndugger
  • 7,373
  • 5
  • 31
  • 42
vorillaz
  • 6,098
  • 2
  • 30
  • 46
  • @pkExec A combination of this and keparo's answer above (the chosen answer) got it working in both ff and chrome for me. – MrShmee Feb 20 '15 at 16:25
26

A more modern approach:

const changeFavicon = link => {
  let $favicon = document.querySelector('link[rel="icon"]')
  // If a <link rel="icon"> element already exists,
  // change its href to the given link.
  if ($favicon !== null) {
    $favicon.href = link
  // Otherwise, create a new element and append it to <head>.
  } else {
    $favicon = document.createElement("link")
    $favicon.rel = "icon"
    $favicon.href = link
    document.head.appendChild($favicon)
  }
}

You can then use it like this:

changeFavicon("http://www.stackoverflow.com/favicon.ico")
Michał Perłakowski
  • 88,409
  • 26
  • 156
  • 177
24

Here's a snippet to make the favicon be an emoji, or text. It works in the console when I'm at stackoverflow.

function changeFavicon(text) {
  const canvas = document.createElement('canvas');
  canvas.height = 64;
  canvas.width = 64;
  const ctx = canvas.getContext('2d');
  ctx.font = '64px serif';
  ctx.fillText(text, 0, 64);

  const link = document.createElement('link');
  const oldLinks = document.querySelectorAll('link[rel="shortcut icon"]');
  oldLinks.forEach(e => e.parentNode.removeChild(e));
  link.id = 'dynamic-favicon';
  link.rel = 'shortcut icon';
  link.href = canvas.toDataURL();
  document.head.appendChild(link);
}

changeFavicon('❤️');
ubershmekel
  • 11,864
  • 10
  • 72
  • 89
13

The favicon is declared in the head tag with something like:

<link rel="shortcut icon" type="image/ico" href="favicon.ico">

You should be able to just pass the name of the icon you want along in the view data and throw it into the head tag.

rubo77
  • 19,527
  • 31
  • 134
  • 226
Jeff Sheldon
  • 2,074
  • 1
  • 14
  • 23
9

Here's some code I use to add dynamic favicon support to Opera, Firefox and Chrome. I couldn't get IE or Safari working though. Basically Chrome allows dynamic favicons, but it only updates them when the page's location (or an iframe etc in it) changes as far as I can tell:

var IE = navigator.userAgent.indexOf("MSIE")!=-1
var favicon = {
    change: function(iconURL) {
        if (arguments.length == 2) {
            document.title = optionalDocTitle}
        this.addLink(iconURL, "icon")
        this.addLink(iconURL, "shortcut icon")

        // Google Chrome HACK - whenever an IFrame changes location 
        // (even to about:blank), it updates the favicon for some reason
        // It doesn't work on Safari at all though :-(
        if (!IE) { // Disable the IE "click" sound
            if (!window.__IFrame) {
                __IFrame = document.createElement('iframe')
                var s = __IFrame.style
                s.height = s.width = s.left = s.top = s.border = 0
                s.position = 'absolute'
                s.visibility = 'hidden'
                document.body.appendChild(__IFrame)}
            __IFrame.src = 'about:blank'}},

    addLink: function(iconURL, relValue) {
        var link = document.createElement("link")
        link.type = "image/x-icon"
        link.rel = relValue
        link.href = iconURL
        this.removeLinkIfExists(relValue)
        this.docHead.appendChild(link)},

    removeLinkIfExists: function(relValue) {
        var links = this.docHead.getElementsByTagName("link");
        for (var i=0; i<links.length; i++) {
            var link = links[i]
            if (link.type == "image/x-icon" && link.rel == relValue) {
                this.docHead.removeChild(link)
                return}}}, // Assuming only one match at most.

    docHead: document.getElementsByTagName("head")[0]}

To change favicons, just go favicon.change("ICON URL") using the above.

(credits to http://softwareas.com/dynamic-favicons for the code I based this on.)

cryo
  • 14,219
  • 4
  • 32
  • 35
  • The [Chrome bug](http://code.google.com/p/chromium/issues/detail?id=9982) was fixed in Chrome 6 (released Sep 10), so the Chrome hack isn't really necessary anymore -- in fact, I'd strongly suggest not using it since it breaks the forward button. – josh3736 Apr 29 '11 at 01:17
  • Chrome still has that same bug, albeit in slightly different circumstances than the specific bug noted. http://code.google.com/p/chromium/issues/detail?id=99549 – danorton Oct 08 '11 at 00:41
9

Or if you want an emoticon :)

var canvas = document.createElement("canvas");
canvas.height = 64;
canvas.width = 64;

var ctx = canvas.getContext("2d");
ctx.font = "64px serif";
ctx.fillText("☠️", 0, 64); 

$("link[rel*='icon']").prop("href", canvas.toDataURL());

Props to https://koddsson.com/posts/emoji-favicon/

max4ever
  • 11,909
  • 13
  • 77
  • 115
5

in most cases, favicon is declared like this.

<link rel="icon" href"...." />

This way you can attain reference to it with this.

const linkElement = document.querySelector('link[rel=icon]');

and you can change the picture with this

linkElement.href = 'url/to/any/picture/remote/or/relative';
yooneskh
  • 784
  • 7
  • 11
4

The only way to make this work for IE is to set you web server to treat requests for *.ico to call your server side scripting language (PHP, .NET, etc). Also setup *.ico to redirect to a single script and have this script deliver the correct favicon file. I'm sure there is still going to be some interesting issues with cache if you want to be able to bounce back and forth in the same browser between different favicons.

Greg
  • 41
  • 1
4

There is a single line solution for those who use jQuery:

$("link[rel*='icon']").prop("href",'https://www.stackoverflow.com/favicon.ico');
Pepelegal
  • 81
  • 1
  • 3
4

I use this feature all the time when developing sites ... so I can see at-a-glance which tab has local, dev or prod running in it.

Now that Chrome supports SVG favicons it makes it a whole lot easier.

Tampermonkey Script

Have a gander at https://gist.github.com/elliz/bb7661d8ed1535c93d03afcd0609360f for a tampermonkey script that points to a demo site I chucked up at https://elliz.github.io/svg-favicon/

Basic code

Adapted this from another answer ... could be improved but good enough for my needs.

(function() {
    'use strict';

    // play with https://codepen.io/elliz/full/ygvgay for getting it right
    // viewBox is required but does not need to be 16x16
    const svg = `
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
      <circle cx="8" cy="8" r="7.2" fill="gold" stroke="#000" stroke-width="1" />
      <circle cx="8" cy="8" r="3.1" fill="#fff" stroke="#000" stroke-width="1" />
    </svg>
    `;

    var favicon_link_html = document.createElement('link');
    favicon_link_html.rel = 'icon';
    favicon_link_html.href = svgToDataUri(svg);
    favicon_link_html.type = 'image/svg+xml';

    try {
        let favicons = document.querySelectorAll('link[rel~="icon"]');
        favicons.forEach(function(favicon) {
            favicon.parentNode.removeChild(favicon);
        });

        const head = document.getElementsByTagName('head')[0];
        head.insertBefore( favicon_link_html, head.firstChild );
    }
    catch(e) { }

    // functions -------------------------------
    function escapeRegExp(str) {
        return str.replace(/([.*+?^=!:${}()|\[\]\/\\])/g, "\\$1");
    }

    function replaceAll(str, find, replace) {
        return str.replace(new RegExp(escapeRegExp(find), 'g'), replace);
    }

    function svgToDataUri(svg) {
        // these may not all be needed - used to be for uri-encoded svg in old browsers
        var encoded = svg.replace(/\s+/g, " ")
        encoded = replaceAll(encoded, "%", "%25");
        encoded = replaceAll(encoded, "> <", "><"); // normalise spaces elements
        encoded = replaceAll(encoded, "; }", ";}"); // normalise spaces css
        encoded = replaceAll(encoded, "<", "%3c");
        encoded = replaceAll(encoded, ">", "%3e");
        encoded = replaceAll(encoded, "\"", "'"); // normalise quotes ... possible issues with quotes in <text>
        encoded = replaceAll(encoded, "#", "%23"); // needed for ie and firefox
        encoded = replaceAll(encoded, "{", "%7b");
        encoded = replaceAll(encoded, "}", "%7d");
        encoded = replaceAll(encoded, "|", "%7c");
        encoded = replaceAll(encoded, "^", "%5e");
        encoded = replaceAll(encoded, "`", "%60");
        encoded = replaceAll(encoded, "@", "%40");
        var dataUri = 'data:image/svg+xml;charset=UTF-8,' + encoded.trim();
        return dataUri;
    }

})();

Just pop your own SVG (maybe cleaned with Jake Archibald's SVGOMG if you're using a tool) into the const at the top. Make sure it is square (using the viewBox attribute) and you're good to go.

Ruskin
  • 5,721
  • 4
  • 45
  • 62
  • @flyingsheep because it is too greedy. I only want to encode the glyphs that are problematic in some browsers. With the subset above the output is much more human readable and editable. List above may be out of date now that we don't have to worry about older IE. I have not tested recently. – Ruskin Aug 24 '20 at 10:21
4

I would use Greg's approach and make a custom handler for favicon.ico Here is a (simplified) handler that works:

using System;
using System.IO;
using System.Web;

namespace FaviconOverrider
{
    public class IcoHandler : IHttpHandler
    {
    public void ProcessRequest(HttpContext context)
    {
        context.Response.ContentType = "image/x-icon";
        byte[] imageData = imageToByteArray(context.Server.MapPath("/ear.ico"));
        context.Response.BinaryWrite(imageData);
    }

    public bool IsReusable
    {
        get { return true; }
    }

    public byte[] imageToByteArray(string imagePath)
    {
        byte[] imageByteArray;
        using (FileStream fs = new FileStream(imagePath, FileMode.Open, FileAccess.Read))
        {
        imageByteArray = new byte[fs.Length];
        fs.Read(imageByteArray, 0, imageByteArray.Length);
        }

        return imageByteArray;
    }
    }
}

Then you can use that handler in the httpHandlers section of the web config in IIS6 or use the 'Handler Mappings' feature in IIS7.

Dan
  • 165
  • 2
  • 2
  • 1
    i'm actually curious why this got downvoted? this is actually the best answer considering al lthe others rely on scripting which may or may not be available. – ethermal Feb 20 '15 at 18:04
  • 2
    @ethermal Because it looks like it's dynamic on the server side. OP was asking for dynamism on the client's side. – Alexis Wilke Aug 25 '18 at 02:27
3

I use favico.js in my projects.

It allows to change the favicon to a range of predefined shapes and also custom ones.

Internally it uses canvas for rendering and base64 data URL for icon encoding.

The library also has nice features: icon badges and animations; purportedly, you can even stream the webcam video into the icon :)

Dima Tisnek
  • 11,241
  • 4
  • 68
  • 120
Oscar Nevarez
  • 994
  • 12
  • 24
2

According to WikiPedia, you can specify which favicon file to load using the link tag in the head section, with a parameter of rel="icon".

For example:

 <link rel="icon" type="image/png" href="/path/image.png">

I imagine if you wanted to write some dynamic content for that call, you would have access to cookies so you could retrieve your session information that way and present appropriate content.

You may fall foul of file formats (IE reportedly only supports it's .ICO format, whilst most everyone else supports PNG and GIF images) and possibly caching issues, both on the browser and through proxies. This would be because of the original itention of favicon, specifically, for marking a bookmark with a site's mini-logo.

staticsan
  • 29,935
  • 4
  • 60
  • 73
2

Yes totally possible

  • Use a querystring after the favicon.ico (and other files links - see answer link below)
  • Simply make sure the server responds to the "someUserId" with the correct image file (that could be static routing rules, or dynamic server side code).

e.g.

<link rel="shortcut icon" href="/favicon.ico?userId=someUserId">

Then whatever server side language / framework you use should easily be able to find the file based on the userId and serve it up in response to that request.

But to do favicons properly (its actually a really complex subject) please see the answer here https://stackoverflow.com/a/45301651/661584

A lot lot easier than working out all the details yourself.

Enjoy.

MemeDeveloper
  • 6,457
  • 2
  • 42
  • 58
  • Yeah, the link is good. I think that the main reason why these answers don't work in IE is because they don't use that default icon ``, but instead look for the `apple-touch-icon` or some other such variant. – Alexis Wilke Aug 25 '18 at 02:32
1

Testing the proposed solutions on 2021 on Chrome, I found that some times the browser cache the favicon and do not show the change, even if the link was changed

This code worked (similar to previous proposal but adds a random parameter to avoid caching)

let oldFavicon = document.getElementById('favicon')
var link = document.createElement('link')
link.id = 'favicon';
link.type = 'image/x-icon'
link.rel = 'icon';
link.href = new_favicon_url +'?=' + Math.random();
if (oldFavicon) {
    document.head.removeChild(oldFavicon);
}
document.head.appendChild(link);

Copied from https://gist.github.com/mathiasbynens/428626#gistcomment-1809869 in case that someone else have the same problem

Gonzalo Odiard
  • 1,238
  • 12
  • 19