How do you set your Cocoa application as the default web browser?

If you just want to change the default helper app for http(s), you can do so in the Safari preferences. There you’ll find a drop down which will let you select all the registered handler applications for http. To automatically have the app set itself as the default browser see the previous instructions.


macOS Big Sur and Up

Copy and paste this code into your info.plist

<key>CFBundleURLTypes</key>
    <array>
        <dict>
            <key>CFBundleURLName</key>
            <string>Web site URL</string>
            <key>CFBundleURLSchemes</key>
            <array>
                <string>http</string>
                <string>https</string>
            </array>
        </dict>
        <dict>
            <key>CFBundleURLName</key>
            <string>http URL</string>
            <key>CFBundleURLSchemes</key>
            <array>
                <string>http</string>
            </array>
        </dict>
        <dict>
            <key>CFBundleURLName</key>
            <string>Secure http URL</string>
            <key>CFBundleURLSchemes</key>
            <array>
                <string>https</string>
            </array>
        </dict>
        <dict>
            <key>CFBundleTypeName</key>
            <string>HTML document</string>
            <key>CFBundleTypeRole</key>
            <string>Viewer</string>
            <key>LSItemContentTypes</key>
            <array>
                <string>public.html</string>
            </array>
        </dict>
        <dict>
            <key>CFBundleTypeName</key>
            <string>XHTML document</string>
            <key>CFBundleTypeRole</key>
            <string>Viewer</string>
            <key>LSItemContentTypes</key>
            <array>
                <string>public.xhtml</string>
            </array>
        </dict>
    </array>
    <key>CFBundleDocumentTypes</key>
    <array>
        <dict>
            <key>CFBundleTypeIconFile</key>
            <string>document.icns</string>
            <key>CFBundleTypeName</key>
            <string>GIF image</string>
            <key>CFBundleTypeRole</key>
            <string>Viewer</string>
            <key>LSItemContentTypes</key>
            <array>
                <string>com.compuserve.gif</string>
            </array>
        </dict>
        <dict>
            <key>CFBundleTypeIconFile</key>
            <string>document.icns</string>
            <key>CFBundleTypeName</key>
            <string>HTML document</string>
            <key>CFBundleTypeRole</key>
            <string>Viewer</string>
            <key>LSItemContentTypes</key>
            <array>
                <string>public.html</string>
            </array>
        </dict>
        <dict>
            <key>CFBundleTypeIconFile</key>
            <string>document.icns</string>
            <key>CFBundleTypeName</key>
            <string>XHTML document</string>
            <key>CFBundleTypeRole</key>
            <string>Viewer</string>
            <key>LSItemContentTypes</key>
            <array>
                <string>public.xhtml</string>
            </array>
        </dict>
        <dict>
            <key>CFBundleTypeIconFile</key>
            <string>document.icns</string>
            <key>CFBundleTypeName</key>
            <string>JavaScript script</string>
            <key>CFBundleTypeRole</key>
            <string>Viewer</string>
            <key>LSItemContentTypes</key>
            <array>
                <string>com.netscape.javascript-​source</string>
            </array>
        </dict>
        <dict>
            <key>CFBundleTypeIconFile</key>
            <string>document.icns</string>
            <key>CFBundleTypeName</key>
            <string>JPEG image</string>
            <key>CFBundleTypeRole</key>
            <string>Viewer</string>
            <key>LSItemContentTypes</key>
            <array>
                <string>public.jpeg</string>
            </array>
        </dict>
        <dict>
            <key>CFBundleTypeIconFile</key>
            <string>document.icns</string>
            <key>CFBundleTypeName</key>
            <string>MHTML document</string>
            <key>CFBundleTypeRole</key>
            <string>Viewer</string>
            <key>LSItemContentTypes</key>
            <array>
                <string>org.ietf.mhtml</string>
            </array>
        </dict>
        <dict>
            <key>CFBundleTypeIconFile</key>
            <string>document.icns</string>
            <key>CFBundleTypeName</key>
            <string>HTML5 Audio (Ogg)</string>
            <key>CFBundleTypeRole</key>
            <string>Viewer</string>
            <key>LSItemContentTypes</key>
            <array>
                <string>org.xiph.ogg-audio</string>
            </array>
        </dict>
        <dict>
            <key>CFBundleTypeIconFile</key>
            <string>document.icns</string>
            <key>CFBundleTypeName</key>
            <string>HTML5 Video (Ogg)</string>
            <key>CFBundleTypeRole</key>
            <string>Viewer</string>
            <key>LSItemContentTypes</key>
            <array>
                <string>org.xiph.ogv</string>
            </array>
        </dict>
        <dict>
            <key>CFBundleTypeIconFile</key>
            <string>document.icns</string>
            <key>CFBundleTypeName</key>
            <string>PNG image</string>
            <key>CFBundleTypeRole</key>
            <string>Viewer</string>
            <key>LSItemContentTypes</key>
            <array>
                <string>public.png</string>
            </array>
        </dict>
        <dict>
            <key>CFBundleTypeIconFile</key>
            <string>document.icns</string>
            <key>CFBundleTypeName</key>
            <string>SVG document</string>
            <key>CFBundleTypeRole</key>
            <string>Viewer</string>
            <key>LSItemContentTypes</key>
            <array>
                <string>public.svg-image</string>
            </array>
        </dict>
        <dict>
            <key>CFBundleTypeIconFile</key>
            <string>document.icns</string>
            <key>CFBundleTypeName</key>
            <string>Plain text document</string>
            <key>CFBundleTypeRole</key>
            <string>Viewer</string>
            <key>LSItemContentTypes</key>
            <array>
                <string>public.text</string>
            </array>
        </dict>
        <dict>
            <key>CFBundleTypeIconFile</key>
            <string>document.icns</string>
            <key>CFBundleTypeName</key>
            <string>HTML5 Video (WebM)</string>
            <key>CFBundleTypeRole</key>
            <string>Viewer</string>
            <key>LSItemContentTypes</key>
            <array>
                <string>org.webmproject.webm</string>
            </array>
        </dict>
        <dict>
            <key>CFBundleTypeIconFile</key>
            <string>document.icns</string>
            <key>CFBundleTypeName</key>
            <string>WebP image</string>
            <key>CFBundleTypeRole</key>
            <string>Viewer</string>
            <key>LSItemContentTypes</key>
            <array>
                <string>org.webmproject.webp</string>
            </array>
        </dict>
        <dict>
            <key>CFBundleTypeRole</key>
            <string>Viewer</string>
            <key>LSItemContentTypes</key>
            <array>
                <string>org.chromium.extension</string>
            </array>
        </dict>
        <dict>
            <key>CFBundleTypeIconFile</key>
            <string>document.icns</string>
            <key>CFBundleTypeName</key>
            <string>PDF Document</string>
            <key>CFBundleTypeRole</key>
            <string>Viewer</string>
            <key>LSItemContentTypes</key>
            <array>
                <string>com.adobe.pdf</string>
            </array>
        </dict>
    </array>

Your app will be shown in the system preferences and will be default browser

Make sure you do this

    func application(_ application: NSApplication, open urls: [URL]) {
// do a for loop, I recommend it
}

There are four steps to making an app that can act as the default web browser. The first three steps allow your app to act as a role handler for the relevant URL schemes (HTTP and HTTPS) and the final step makes it the default role handler for those schemes.

1) Add the URL schemes your app can handle to your application's info.plist file

To add support for http:// and https:// you'd need to add the following to your application's info.plist file. This tells the OS that your application is capable of handling HTTP and HTTP URLs.

<key>CFBundleURLTypes</key>
<array>
    <dict>
        <key>CFBundleURLName</key>
        <string>http URL</string>
        <key>CFBundleURLSchemes</key>
        <array>
            <string>http</string>
        </array>
    </dict>
    <dict>
        <key>CFBundleURLName</key>
        <string>Secure http URL</string>
        <key>CFBundleURLSchemes</key>
        <array>
            <string>https</string>
        </array>
    </dict>
</array>

2) Write an URL handler method

This method will be called by the OS when it wants to use your application to open a URL. It doesn't matter which object you add this method to, that'll be explicitly passed to the Event Manager in the next step. The URL handler method should look something like this:

- (void)getUrl:(NSAppleEventDescriptor *)event 
    withReplyEvent:(NSAppleEventDescriptor *)replyEvent
{
  // Get the URL
  NSString *urlStr = [[event paramDescriptorForKeyword:keyDirectObject] 
    stringValue];

  //TODO: Your custom URL handling code here
}

3) Register the URL handler method

Next, tell the event manager which object and method to call when it wants to use your app to load an URL. In the code here I'm passed self as the event handler, assuming that we're calling setEventHandler from the same object that defines the getUrl:withReplyEvent: method.

You should add this code somewhere in your application's initialisation code.

NSAppleEventManager *em = [NSAppleEventManager sharedAppleEventManager];
[em 
  setEventHandler:self 
  andSelector:@selector(getUrl:withReplyEvent:) 
  forEventClass:kInternetEventClass 
  andEventID:kAEGetURL];

Some applications, including early versions of Adobe AIR, use the alternative WWW!/OURL AppleEvent to request that an application opens URLs, so to be compatible with those applications you should also add the following:

[em
  setEventHandler:self 
  andSelector:@selector(getUrl:withReplyEvent:) 
  forEventClass:'WWW!' 
  andEventID:'OURL'];

4) Set your app as the default browser

Everything we've done so far as told the OS that your application is a browser, now we need to make it the default browser.

We've got to use the Launch Services API to do this. In this case we're setting our app to be the default role handler for HTTP and HTTPS links:

CFStringRef bundleID = (CFStringRef)[[NSBundle mainBundle] bundleIdentifier];
OSStatus httpResult = LSSetDefaultHandlerForURLScheme(CFSTR("http"), bundleID);
OSStatus httpsResult = LSSetDefaultHandlerForURLScheme(CFSTR("https"), bundleID);
//TODO: Check httpResult and httpsResult for errors

(It's probably best to ask the user's permission before changing their default browser.)

Custom URL schemes

It's worth noting that you can also use these same steps to handle your own custom URL schemes. If you're creating a custom URL scheme it's a good idea to base it on your app's bundle identifier to avoid clashes with other apps. So if your bundle ID is com.example.MyApp you should consider using x-com-example-myapp:// URLs.