Customizing Safari’s 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 Safari’s pinned tab images, it’s pretty simple with the right tools. You’ll need a 32px image and a Property List editor, such as Xcode. Here’s 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.
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 called 7905D1C4E12C54933A44D19FCD5F9356.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 change TemplateIconInCache to YES.
The last thing you’ll want to change is the color that the icon becomes when the pinned tab is active. Add a new key called TemplateIconThemeColor and change it to be an Array. Add three items, each with a color value between 0 and 1. 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 you’re 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 computer’s 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.
Using Activity Monitor to find the process ID to use with fs_usage.
There were a whole lot of Safari related processes, and I wasn’t 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.
Using fs_usage to find 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 hadn’t 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.
The iCloud logo as an SVG.
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 Annie’s glasses with the wand tool. I saved it as a PNG and got to work trying to convert it.
To make sure Safari wasn’t 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 didn’t match the ones used in Safari.
ImageMagick could do almost anything but it couldn’t create SVG files. Autotrace is really old and didn’t work. potrace could only work well with large images. That would mean that I’d have to scale down any SVG files that I made with it, and it wasn’t a process that would be easily repeated.
I managed to get Safari to show something in the pinned tab, but Safari wasn’t 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, I’d 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!
Hashing Domain Names
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.
It’s 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 it’s pretty cool that this works.