Chrome works better for me than Safari, particularly when I have many, many tabs open. However, when I run my Macbook on batteries, Chrome drains batteries too fast, so I’d like to use Safari when I’m on battery power. I created a couple of Applescripts to move my open tabs from Chrome to Safari and vice versa.

I found scripts online to do these, but they appear to rely on obsolete editions of OS X. My scripts below work on OS X High Sierra with the current Google Chrome as of 2018.01.01.

Conceptually, it is a simple task: Take these tabs in one browser and open them in the other. (“Whoosh them” from one browser to the other.) There are some challenges along the way:

  • The object model (“dictionary” in Apple parlance) for the browsers differ.
  • The object model is incompletely documented. There are many properties and methods which you just have to discover via Googling.
  • Pinned tabs behave differently between Chrome and Safai. Frankly, the Safari practice of putting your pinned tabs in every Safari window is just stupid.
  • You can’t pin a tab via the object model – you must resort to GUI scripting.
  • Bringing a window or tab to the foreground changes the order of the browser’s windows/tabs, so you can’t iterate through windows/tabs while bringing them to the foreground. You have to collect the IDs and then iterate through the IDs.
  • AppleScript is just an all-around peculiar language and environment.

Here is Chrome-to-Safari:

-- Move all tabs from Chrome to Safari.


-- Optionally close existing Safari tabs first
set question to display dialog "Close exisisting Safari tabs first?" buttons {"Yes", "No"} default button 1
set answer to button returned of question
if answer is equal to "Yes" then
	closeAllSafariTabs()
end if

tell application "Google Chrome"
	
	-- for every Chrome window, open a Safari Window
	repeat with theChromeWindow in windows
		set theSafariWindow to my openNewSafariWindow()
		
		-- for every tab in the Chrome window, open a tab in the Safari window
		repeat with theChromeTab in theChromeWindow's tabs
			my makeSafariTab(theSafariWindow, URL of theChromeTab)
		end repeat
	end repeat
end tell

pinSpecialTabsInSafari()

tell me to activate
set question to display dialog "Close old Chrome tabs?" buttons {"Yes", "No"} default button 2
set answer to button returned of question
if answer is equal to "Yes" then
	closeAllChromeTabs()
end if

tell application "Safari" to activate


-- Open a *new* Safari window.
on openNewSafariWindow()
	tell application "Safari"
		make new document at end of documents
		set theSafariWindow to window 1
	end tell
	return theSafariWindow
end openNewSafariWindow



-- I have a set of sites for which I used pinned tabs in Chrome.
-- Note that because pinning behaves differently in Chrome and Safari, I don't always pin my pin-desired tabs when I move them to Safari.
on pinSpecialTabsInSafari()
	
	-- Note: You can't simply iterate windows and tabs because activating a window/tab re-orders the collection.
	--       You have to get a collection of IDs and iterate the IDs because they don't change.
	
	tell application "Safari" to set windowIds to (id of every window)
	tell application "Safari" to activate -- have to activate Safari because I'm automating clicks on its menus.
	
	repeat with wid in windowIds
		tell application "Safari"
			set theSafariWindow to (first window whose id = wid)
			set index of theSafariWindow to 1 -- bring THIS Safari window to top of Safari.
			
			tell theSafariWindow
				-- if you don't do this, sometimes Safari is the front app, with the desired window in the foreground, but it isn't actually activated.
				set visible to false
				set visible to true
			end tell
			
			repeat with t in every tab of theSafariWindow
				tell theSafariWindow to set current tab to t
				my waitForFrontTabToLoad()
				set theURL to URL of t
				if my shouldPinMe(theURL) then
					my pinActiveTab()
				end if
			end repeat
		end tell
	end repeat
	
	
end pinSpecialTabsInSafari


-- Create a new Safari tab in the specified window.
on makeSafariTab(theSafariWindow, theURL)
	
	if (theURL as string) = "chrome://newtab/" then
		-- skip empty tabs.  (You'd need to change chrome://newtab/ to about:blank in order to open it in Safari.)
	else
		tell application "Safari"
			try
				tell window 1 to set current tab to make new tab at end of tabs of theSafariWindow with properties {URL:theURL}
			on error
				open location theURL
			end try
			
			-- Close empty 'Favorites' tab created when making new window.
			set thisTab to tab 1 of theSafariWindow
			if thisTab's name as string = "Favorites" then close tab 1 of window 1
			
		end tell
	end if
end makeSafariTab


-- Wait for the front-most tab of Safari to finish loading (at least until it has a title).
on waitForFrontTabToLoad()
	repeat until leftString((name of front document of application "Safari"), 8) is not "Untitled"
		delay 0.1
	end repeat
end waitForFrontTabToLoad


-- I always pin certain tabs.
-- Note that because pinning behaves differently in Chrome and Safari, I don't always pin my pin-desired tabs when I move them to Safari.
on shouldPinMe(uri)
	
	tell application "Safari" to set wCount to count of windows
	if wCount > 1 then return false -- pinned tabs are stupid in Safari.  Pinning a tab in one window will add it to ALL safari windows
	
	if (uri as string) = "missing value" then error "no URI in shouldPinMe"
	if uri contains "//pinboard.in" then return true
	if uri contains "//focus.nirvanahq.com" then return true
	if uri contains "//www.nirvanahq.com" then return true
	if uri contains "//workflowy.com" then return true
	if uri contains "//voice.google.com" then return true
	if uri contains "//calendar.google.com" then return true
	if uri contains "//mail.google.com" then return true
	
	return false
end shouldPinMe


-- Pin the tab which is currently front-most in Safari.
on pinActiveTab()
	-- delay 1
	tell application "System Events"
		tell process "Safari"
			set frontmost to true
			click menu item "Pin Tab" of menu "Window" of menu bar 1
		end tell
	end tell
end pinActiveTab


-- Close every Safari tab.
on closeAllSafariTabs()
	tell application "Safari"
		set wCount to count of windows
		repeat with i from 1 to wCount
			set theSafariWindow to window 1
			repeat with theSafariTab in theSafariWindow's tabs
				tell theSafariWindow to close tab 1
			end repeat
		end repeat
	end tell
end closeAllSafariTabs


-- Close every Chrome tab.
on closeAllChromeTabs()
	tell application "Google Chrome"
		set windowList to every tab of every window
		repeat with tabList in windowList
			set tabList to tabList as any
			repeat with tabItr in tabList
				set tabItr to tabItr as any
				delete tabItr
			end repeat
		end repeat
	end tell
end closeAllChromeTabs


-- Return the first n characters of string s.
on leftString(s, n)
	if length of s is less than n then
		return s
	else
		return text 1 thru n of s
	end if
end leftString

Here is Safari-to-Chrome:

-- Move all tabs from Safari to Chrome

-- Optionally close existing Chrome tabs first
tell me to activate
set question to display dialog "Close exisisting Chrome tabs first?" buttons {"Yes", "No"} default button 1
set answer to button returned of question
if answer is equal to "Yes" then
	closeAllChromeTabs()
end if


tell application "Safari"
	repeat with theSafariWindow in windows
		tell application "Google Chrome" to set theChromeWindow to make new window
		repeat with theSafariTab in theSafariWindow's tabs
			set theURL to URL of theSafariTab
			tell application "Google Chrome"
				set theChromeTab to make new tab at end of tabs of theChromeWindow
				set URL of theChromeTab to theURL
				
			end tell
		end repeat
		-- Close empty tab created when making new window.
		tell application "Google Chrome" to close tab 1 of theChromeWindow
		
		
		tell application "Google Chrome" to set tabCount to number of tabs in theChromeWindow
		repeat with i from 1 to tabCount
			tell application "Google Chrome" to set active tab index of first window to i
			tell application "Google Chrome" to set theURL to URL of active tab of front window
			if my ShouldPinMe(theURL) then
				my pinActiveTab()
			end if
		end repeat
		
	end repeat
end tell


tell me to activate
set question to display dialog "Close exisisting Safari tabs?" buttons {"Yes", "No"} default button 2
set answer to button returned of question
if answer is equal to "Yes" then
	closeAllSafariTabs()
end if


-- I always pin certain tabs.
on ShouldPinMe(uri)
	if uri contains "//pinboard.in" then return true
	if uri contains "//focus.nirvanahq.com" then return true
	if uri contains "//workflowy.com" then return true
	if uri contains "//voice.google.com" then return true
	if uri contains "//calendar.google.com" then return true
	if uri contains "//mail.google.com" then return true
	return false
end ShouldPinMe

on pinActiveTab()
	tell application "Google Chrome" to activate
	tell window 1 of application "Google Chrome" to set visible to true
	tell application "System Events"
		tell process "Google Chrome"
			set m1 to (first menu bar item where name is "Window") of menu bar 1
			set mx to menu item "Pin Tab" of menu 1 of m1
			click mx
		end tell
	end tell
end pinActiveTab


on closeAllChromeTabs()
	tell application "Google Chrome"
		set windowList to every tab of every window
		repeat with tabList in windowList
			set tabList to tabList as any
			repeat with tabItr in tabList
				set tabItr to tabItr as any
				delete tabItr
			end repeat
		end repeat
	end tell
end closeAllChromeTabs


on closeAllSafariTabs()
	tell application "Safari"
		set wCount to count of windows
		repeat with i from 1 to wCount
			set theSafariWindow to window 1
			repeat with theSafariTab in theSafariWindow's tabs
				tell theSafariWindow to close tab 1
			end repeat
		end repeat
	end tell
end closeAllSafariTabs