How to access a clicked URL in a URL handler application created in Automator

I'm currently trying to modify the default URL handling behavior in OS X. I would like, when clicking on any link outside of a web browser, to copy this URL to the pasteboard instead of opening it in the default web browser – for instance, clicking a link in a Skype conversation should copy this URL to the OS X pasteboard instead of opening it in Firefox (which is currently my default web browser).

I have thought about solutions, but I’m currently unable to implement one. If I can create an application that puts URLs into the pasteboard that are sent to it, and can set this application as the default web browser, I would be able to achieve my goal.

I created an application with Automator that executes the shell command pbcopy and have set this application as my default web browser, but I didn’t get the expected result. I did some testing and I can confirm that the application runs on clicking on a link, however, I cannot get the URL passed to the application / shell script. I tried both stdin or a passed argument, but without success.

Is there a way for an application created with Automator to retrieve a clicked URL and send it to pbcopy, when that application is set as a (default) handler for URLs?

Alternatively, is there a better way to create a fake web browser that takes the input and puts it in the pasteboard than Automator? Or is there any other way that I can achieve my goal without a custom application / script?


The way URL opening in Mac OS X is actually more complicated than you would think. When you click a URL, Mac OS X does not just pass the browser the URL to open; instead, it sends it an Apple Event, with the ID kAEGetURL, containing the URL.

I never really used Automator (it's just way too slow and limited for my typical use), so I'm not sure about this, but I doubt it has the ability to handle Apple Events. Therefore you won't be able to use Automator to achieve what you want.

You'll therefore have to resort to a normal Objective-C app in Xcode.

The two basic things you need to do are:

  1. register your app for receiving the kAEGetURL event, and set the CFBundleURLTypes in your app's Info.plist to include http and https.

  2. Implement a method handling the kAEGetURL event, and make it copy the URL to the clipboard.

These two things are relatively straightforward to do in Objective-C; to illustrate, I've created a sample application that does this. You can view it at https://github.com/houbysoft/short/tree/master/Copy%20URL%20to%20Clipboard. The most important file is https://github.com/houbysoft/short/blob/master/Copy%20URL%20to%20Clipboard/Copy%20URL%20to%20Clipboard/AppDelegate.m, there you can see how to register for the event (this is done in the applicationWillFinishLaunching: method) and how to copy it to the clipboard (this is done in the getUrl:withReplyEvent: method).

If you're feeling lazy and just want to see that this works, grab this file, extract the application from it, set that as the default web browser (open Safari Preferences, and browse for that app in the Default web browser field). Then click on your link in Skype, and it should be copied straight to your clipboard.


Step 1: Install open source and actively maintained https://github.com/johnste/finicky. Finicky is an application that allows you to routes links to different browsers based on rules you specify. For this to work, Finicky should be your default browser.

Step 2: Open Script Editor, paste the following code, and save it as an application. Let's call this one UrlHandler.app:

on open location input
    set the clipboard to input
end open location

Step 3: Specify which browser Finicky should send links to by default. In ~/.finicky.js change the defaultBrowser to the UrlHandler.app in step 2.

module.exports = {
  defaultBrowser: "com.apple.ScriptEditor.id.UrlHandler",
  ...

Here's an alternative configuration which sends links to UrlHandler.app only when Command-clicking a link:

module.exports = {
  defaultBrowser: "Firefox",
  handlers: [
    {
      match: ({ keys }) => keys.command,
      browser: "com.apple.ScriptEditor.id.UrlHandler"
    }
  ]
};