Customizing Safari Pinned Tabs
Ever pinned a few tabs in Safari and end up with a bunch of identical tabs which all had the same letter as the icon? I did.
If you want to customize Safaris pinned tab images, its pretty simple with the right tools. Youll need a 32 pixel squared PNg image and a Property List editor, such as Xcode. Heres how:
- First, you need an image to put there. On retina systems, you want a 32 pixel by 32 pixel image in PNG format. On non-retina, you want 16 by 16 pixels. IconFactory has a great article describing these images in detail.
- Next, you need to know what to name the image. The tab icon template cache uses the MD5 hash function to map domain names to image files. A simple python script (example here) will give you the correct name. For example, the hash of twitter.com is
7905D1C4E12C54933A44D19FCD5F9356
so the file should be called7905D1C4E12C54933A44D19FCD5F9356.png
. - Once you’ve run the script, you need to put the image in
~/Library/Safari/Template Icons/
. - For our final step, we need to tell Safari that the icon is there. Open up
~/Library/Safari/Template Icons/CacheSettings.plist
and open up the section called TemplateIcons. You should see the website that you’ve pinned. Expand it, and changeTemplateIconInCache
to YES. - The next step is optional. If you want to change the color that the icon becomes when the pinned tab is active, its easy. Add a new key called
TemplateIconThemeColor
and change it to be an Array. Add three items, each with a color value between0
and1
. The three values represent red, green, and blue, respectively.
Save the plist and restart Safari. Behold your beautiful new pinned tab icon.
So now we know it works. If youre curious to know how I worked this out, feel free to keep reading.
My first approach was to use the HTML inspector in Safari to edit the webpage before pinning it. The official way to add a custom icon to your website if you own it is to put a snippet of HTML into the page. I wondered if adding it to the page myself would do the trick. It did not. I had to dig deeper.
In order to tinker with the pinned tabs, I had to find out where Safari was storing them. If the data is saved even after Safari closes, it has to be written to your computers disk. The question was where.
I tried looking in ~/Library/Caches/
and ~/Library/Application Support/
but there was nothing useful. Then I found a tool called fs_usage
which monitors whenever a program reads or writes to the file system. It can be filtered to spit out messages for a particular process instead of all of the programs that are running. (There are hundreds of programs or processes running at any given moment. Finding the right information would be impossible without a filter.)
To find the appropriate process to observe, I used Activity Monitor.
There were a whole lot of Safari related processes, and I wasnt sure which one to observe, so I used the PIDs for Safari and Safari Database Storage. Next I opened Safari and pinned a tab. Boom! In the console, I saw a likely candidate: ~/Library/Safari/LastSession.plist.
When I opened it, I saw something called SessionPinnedTabs
which looked like what I wanted, but it was a red herring. There’s plenty of information stored there, including the URL that the tab contains, and even process IDs, but nothing about the icons.
I was close, though. Another file I poked around inside of was called WebpageIcons.db
. I thought that it might contain the images I wanted to change. I used an app called Base to open the database, but I couldn’t find anything related to pinned tabs.
Upon closer inspection, I found a subdirectory called Template Icons
which looked like it was some kind of cache. It had a few small PNG images of sites I had previously pinned. There was also a file that I hadnt noticed earlier. It was called CacheSettings.plist
.
I opened it, and started poking around. The top section TemplateIconFallbackConfiguration
, was really interesting. It had about 300 default icons in SVG format, sitting right there in the property list. Some entries had icons, while others referred to subdomains with the AlternateHost
key.
My next strategy was to add SVG files into this section and hope Safari would do the right thing with them. The difficulty here was to produce an SVG that was in the right format for Safari to read out of the plist. I took a screenshot of AppAnnie.com and cut out Annies glasses with the wand tool. I saved it as a PNG and got to work trying to convert it.
To make sure Safari wasnt generating garbage output based on garbage input, I copied the Apple logo, also stored in the CacheSettings.plist
file and deleted some random points. The new output did indeed appear in Safari. So if I got an SVG to show, I would achieve my goal, but there had to be an easier way.
I tried to save an SVG in Photoshop CS6, but I learned the hard way that older versions of Photoshop don’t support SVG graphics at all. I downloaded a couple of old tools: ImageMagick, potrace, and autotrace.
Photoshop CC 2015 could generate an SVG but not quite to spec. The headers and the contents of the SVG file didnt match the ones used in Safari.
ImageMagick could do almost anything but it couldn’t create SVG files. Autotrace is really old and didnt work. potrace could only work well with large images. That would mean that Id have to scale down any SVG files that I made with it, and it wasnt a process that would be easily repeated.
I managed to get Safari to show something in the pinned tab, but Safari wasnt scaling anything, so the cached icon was a simple cutout of part of the larger image. Not what I wanted.
I realized that if I was going to make this work, Id have to figure out how Safari was building the cache in Template Icons
. I went back to the WebpageIcons.db
database again but came up empty.
On a whim, I wrote a python script to convert a domain name to an MD5 hash and spit out the result. What if Safari hashes domain names to match to icons? I compared the result of running the script on twitter.com and the actual filename in the cache. It worked!
This was my big breakthrough. Safari is running domain names through an MD5 hash and saving a system-dependent resolution black-and-white icon in the Template Icons directory. Now, all I had to do was modify the CacheSettings.plist
and generate a tiny PNG image.
Its possible that this process might change in the future, but for now, it seems possible to customize icons as described above. Your mileage may vary, but its pretty cool that this works.