Deleting Safari cookies via AppleScript

Generally speaking, I don’t mind it when websites set cookies in my browser. They provide a degree of continuity that the otherwise stateless web wouldn’t have, and that’s convenient for many types of website. But sometimes cookies either get in the way or are an unnecessary intrusion. It’s relatively easy in Safari to delete the cookies for a particular site, but I wanted a one-click solution to cover several sites. I got that with an AppleScript that uses GUI scripting.

Before I get into the script, you might be wondering why I don’t just open up the ~/Library/Cookies/Cookies.plist file and delete the cookies directly. After all, Python has a plist module that makes reading, manipulating, and writing plist files very easy. I did, in fact, start out with a script that deleted items from Cookies.plist, but I found that that didn’t always delete them from Safari itself. It wasn’t because I did the deletion when Safari was open—I knew that wouldn’t work. I suspect it had something to do with Safari’s cache reinstating the just-deleted cookies upon relaunch. Whatever the reason, that simple approach didn’t work.1

Since Safari’s AppleScript dictionary doesn’t have any commands for manipulating cookies, I had to resort to that last refuge of the AppleScript scoundrel, GUI scripting. In GUI scripting, you write your program to simulate the clicking of buttons, the selection of menu items, the pressing of keystrokes, and so on. In this case, I needed to have the script open Safari’s Privacy preferences, find the cookies associated with certain domains, and delete them.

Here’s the Privacy preferences window,

Safari Privacy preferences

and here’s the sheet used to find and delete particular cookies.

Safari cookies

The script that loops through and deletes the cookies from the sites I designate is called Cookie Crumble, and its source code is

 1:  set deCookie to {"", "", ""}
 3:  tell application "System Events"
 4:    tell process "Safari"
 5:      keystroke "," using command down
 6:      delay 1
 7:      tell window 1
 8:        click button "Privacy" of tool bar 1
 9:        delay 3
10:        repeat with d in deCookie
11:          click button "Details…" of group 1 of group 1
12:          try
13:            keystroke d
14:            delay 1
15:            select row 1 of table 1 of scroll area 1 of sheet 1
16:            click button "Remove" of sheet 1
17:          end try
18:          click button "Done" of sheet 1
19:        end repeat
20:      end tell
21:      keystroke "w" using command down
22:    end tell
23:  end tell

The deCookie list defined in Line 1 is the set of sites whose cookies I want deleted. Line 5 opens Safari’s Preferences, and Line 8 makes sure the Privacy preferences are selected. The delay in Line 6 is there to make sure the window is open before the script tries to click any buttons. Messing around with timing like this is pretty common in GUI scripting. Even after the window appears, it often takes a while for the Details… button to show up, hence the three-second delay in Line 9 before clicking the Details… button in Line 11.

The bulk of the script is taken up with entering the domain as a search term, selecting the top found item, and deleting it. This is wrapped in a try block because it’s possible for the script to be run when there are no cookies from one or more of the deCookie domains—without the try block, the script would halt with an error under that condition.

I figured out the weird button "Details…" of group 1 of group 1 and row 1 of table 1 of scroll area 1 of sheet 1 selectors by using the Accessibility Inspector and hovering over the items I needed to interact with.

Accessibility Inspector

This is the view when I hovered over the Details… button, and you can see from the hierarchy in the top section that it’s a button that’s in a group that’s in a group that’s in the window. It doesn’t say which groups, but because the Details… button is near the top of the Preferences window, I just guessed that group 1 of group 1 would work. I guessed right.

I have Cookie Crumble saved in ~/Library/Scripts/Applications/Safari, so it appears in the FastScripts menu only when Safari is the active application. Now I can eliminate several sets of cookies with a single menu selection.

Upon seeing in the list of sites I want to decookify, the alert reader may suspect that I’m using this script to get around the Times’ ten-stories-per-month limitation. That’s partially true, but only because the way the limitation is implemented seems wrong.

My understanding of the limitation is that the Times doesn’t object to me following any number of outside links into its site to read its stories (and see its ads). What it doesn’t want is for me to wander around on the site, day after day, without paying for a subscription. Fair enough.

The problem arises when I hit the limit even though I’ve only entered the site through outside links. How does this happen? Most commonly, it happens because the stories I read are—through the magic of maximizing pageviews—two or more pages long. The link from outside takes me to the first page only; after that, all the links are internal and count against the limit. I get halfway through a story—a story it’s supposedly allowing me to come in and read—and Page 2 gets blocked because I’ve already read ten Page 2’s that month. This strikes me as decidedly unfair. All I want to do is finish reading the article I was invited to read. Eliminating the cookies resets my counter and lets me do that.

So far, I have only news sites in my deCookie list, but I expect to add more as I think of them.

  1. I’m sure there’s a way to dig into the cache and delete the necessary entries, but I’m no SQL programmer.