I kept running into this problem: I clicked a link in Slack, and it opened in Safari. But I was logged into that AWS account in Chrome Profile 3, and the Figma link should just open in the desktop app, not another browser tab.
Yojam fixes that. Set it as your default browser, and it catches every link you click. Using rules you define, it routes each link exactly where it belongs - or pops up a fast picker right at your cursor so you can choose on the fly.
utm_source, fbclid, gclid, and 30+ other tracking parameters before the browser ever sees them. Per-browser or globally.mailto: links and routes them to your preferred client.~/Library/Application Support/Yojam/config.json. Edits in the file get picked up by the app in real time, and vice-versa. Good for dotfile repos or scripted changes.Yojam picks up links from every source macOS can offer:
http/https URLs (the default-browser path).ASWebAuthenticationSession, such as Slack and Claude..html, .xhtml, .webloc, .inetloc, and .url files..webloc files, which Yojam unwraps transparently.yojam:// URL scheme, for Shortcuts, Raycast, Alfred, shell scripts, and any other automation.Every one of these goes through the same rule engine, tracker scrubber, and rewrite pipeline as a direct click. There is no second-class handling.
Yojam forwards the first URL from a web authentication session to your chosen browser. It cannot see later navigation inside that browser or send the callback to the source app. An app that depends only on the session callback can keep waiting after you finish in the browser. Apps with a separate callback URL handler can still finish the sign-in. Yojam does not claim ephemeral-session support because the chosen browser keeps its cookies and profile state.
Install via Homebrew:
brew install --cask yojam
Or grab the DMG from yoj.am and drag Yojam to your Applications folder. On first launch, Yojam asks to become your default browser.
Yojam checks yoj.am for updates every hour. When a new version is ready, a dot appears on the menu bar icon, the menu gains an Update to Yojam x.y.z… entry, Preferences shows an Install Update button, and Yojam posts a notification if you allow it. You can also check any time from Preferences > General > Updates, from the About tab, or from the menu bar icon > Check for Updates….
You need macOS 14+ and Xcode 16+. Yojam uses XcodeGen for the project file.
# Install xcodegen if you haven't
brew install xcodegen
# Generate the Xcode project and build
xcodegen generate
open Yojam.xcodeproj
Build and run from Xcode. On first launch, Yojam asks to become your default browser - say yes, that's how it intercepts links.
Note:
swift build/swift runcompiles the code and runs tests, but won't produce a working.appbundle. macOS requires a proper app bundle with Info.plist and URL scheme registration to function as a default browser. The Share Extension, Safari Web Extension, and native messaging host are Xcode-only targets produced byxcodegen generate && xcodebuild.
swift build only builds the bare Yojam executable and YojamCore library.Extensions/build.sh produces dist/yojam-chrome.zip and dist/yojam-firefox.xpi from the shared WebExtension source. Signing and store submission are out of scope for this script.When you click a link anywhere on your Mac, Yojam processes it through a pipeline:
mailto: so subjects and bodies stay intact)| Mode | What happens |
|---|---|
| Always show picker | Unmatched links show the browser picker; matching rules still fire immediately. |
| Hold Shift to pick | Links route via rules or your default. Keep Shift held until the picker appears to choose instead. |
| Smart + Fallback | Rules fire automatically. Learned domains auto-route. Everything else shows the picker. |
Shift also acts as a one-off escape hatch in the other modes: it skips matching rules and URL rewrites, then shows the picker with the original link. macOS delivers an external URL separately from the originating click, so keep Shift held until Yojam's picker appears.
| Key | Action |
|---|---|
| 1–9 | Jump to browser at that position |
| ←→ / ↑↓ | Move selection |
| Enter / Space | Open in selected browser |
| Cmd+C | Copy URL to clipboard |
| Esc | Dismiss picker |
Yojam ships with built-in rules for Zoom, Telegram, Slack, Discord, Spotify, Apple Music, FaceTime, Apple Maps, Microsoft Teams, Figma, Linear, Notion, WhatsApp, Signal, App Store, TestFlight, and Podcasts. They auto-disable when the target app isn't installed and re-enable when it is. Built-in rules are also fully editable - tweak, duplicate, or delete them, and Restore Default Rules in Advanced brings them back.
Discord ignores plain web links handed to it, so Yojam converts discord.com channel, message, and invite links (and discord.gg invites) to discord:// deep links at launch time. The URL tester shows the converted link.
Add your own rules matching on all URLs, domain (exact), domain suffix, URL prefix, URL substring, or regex. Rules can optionally filter by source app - only route links from Slack to your work browser, for example.
Beyond picking the target app or browser, each rule can pin:
github.com to Chrome specifically in the Work profile, while your other Chrome rules use Personal.$URL as the placeholder.--user-data-dir setups.These overrides only apply to the specific rule, so a rule-level private-window toggle won't flip the browser's own default.
For ingress paths that don't have a real originating app, Yojam uses synthetic bundle identifiers. You can target these in rules to handle links differently depending on how they arrived:
| Sentinel | Ingress path |
|---|---|
com.yojam.source.handoff | Handoff from another Apple device |
com.yojam.source.authentication-session | App sign-in session |
com.yojam.source.airdrop | AirDropped .webloc files |
com.yojam.source.share-extension | Share menu |
com.yojam.source.service | Services menu |
com.yojam.source.safari-extension | Safari extension |
com.yojam.source.chrome-extension | Chrome/Chromium extension |
com.yojam.source.firefox-extension | Firefox extension |
com.yojam.source.url-scheme | yojam:// URL scheme |
For example, you could write a rule like: Source App = com.yojam.source.handoff → always open in Work profile.
The Share Extension adds "Open in Yojam" to the macOS share menu. It shows up in Safari, Notes, Mail, Finder, Reminders, Photos, and other apps that support the share sheet. One tap forwards the URL to Yojam silently.
To enable it: System Settings > Privacy & Security > Extensions > Sharing, then turn on Yojam.
The "Open in Yojam" entry appears in the Services menu in every Cocoa app. Highlight any URL text, right-click, and pick it from the Services submenu.
To add a global keyboard shortcut: System Settings > Keyboard > Keyboard Shortcuts > Services, find "Open in Yojam", and assign a shortcut.
Ships inside Yojam.app. Enable it in Safari > Settings > Extensions.
Download yojam-chrome.zip from the latest GitHub release, unzip it, then load the extracted folder as an unpacked extension. Until a stable Chrome Web Store ID is published, the unpacked build uses the yojam:// fallback and Chrome may ask once before handing the link to Yojam. The no-prompt native-messaging path will be enabled for the store build.
Firefox release builds require Mozilla-signed extensions, and Yojam is not on AMO yet. The raw yojam-firefox.xpi attached to GitHub releases is for Orion and Firefox development builds configured to allow unsigned extensions. A normal Firefox install will need the AMO build once it is published.
Container routing needs Orion 1.1 or newer and the Firefox build of the Yojam WebExtension. Download yojam-firefox.xpi from the latest GitHub release. In Orion > Settings > Advanced, allow third-party Firefox extensions. Then open Tools > Extensions > Manage Extensions, choose Add Extension, and install the XPI. See Orion's WebExtension guide for Orion's current installation and compatibility details.
Alt+Shift+Y sends the current tab to Yojam.yojam:// URL schemeYojam registers a yojam:// URL scheme for automation. Any app, script, or shortcut can trigger it:
yojam://route?url=<percent-encoded>&source=<bundle-id>&browser=<bundle-id>&pick=1&private=1
yojam://settings
Parameters:
url (required): the target URL. Must decode to http, https, or mailto.source (optional): bundle identifier for source-app rule matching.browser (optional): force a specific target browser by bundle ID, skipping rules.pick=1 (optional): force the picker regardless of activation mode.private=1 (optional): open in private/incognito window if the target browser supports it.Example Shortcuts recipe: create a Shortcut with an "Open URL" action pointing at yojam://route?url= followed by the URL you want to route.
Not limited to browsers. Click + Add in the Browsers tab and pick any .app or executable. For apps that don't natively handle URLs, use $URL where the link belongs. Without it, Yojam appends the URL after your custom arguments:
$URL
--url $URL
--browse $URL
Yojam passes these arguments directly - no shell involved.
For Chromium-based browsers, set Data Dir when an entry should use a custom --user-data-dir; the profile menu reloads from that directory and Yojam opens it as a new app instance. $HOME and leading ~/ are expanded without invoking a shell.
Six tabs in preferences (menu bar icon > Preferences, or Cmd+,):
On first launch Yojam shows a Quick Start card above the tabs. It guides you through default-browser registration. If Bumpr, Choosy, or Finicky is installed, it also offers to import compatible routes and rewrites.
The URL tester on the Link Handling tab lets you paste a URL and see exactly what Yojam would do - which rewrites fire, whether trackers get stripped, which rule matches, and where it ends up.
Settings can be exported as JSON and imported on another machine.
group.org.yojam.shared — shared storage between the main app and its extensions.The first time certain features are used, macOS will show:
yojam:// (from browser extension fallback path).Everything happens locally on your Mac. Yojam doesn't phone home, track your clicks, or send your data anywhere. The Share Extension and browser extensions only hand a URL to the local Yojam process. The native messaging host only forwards URLs you explicitly trigger — it never reads page contents. Nothing hits the network.
The only network activity is iCloud sync (uses your own Apple ID, off by default) and checking for updates via yoj.am (can be disabled in Preferences).
.webloc from Preferences > Integrations.~/Library/Preferences/com.yojam.app.plist are not read. Reconfigure from Preferences.BSD 3-Clause. See LICENSE.
There are other browser pickers out there. I wanted one that felt invisible most of the time, stripped trackers globally, supported browser profiles as first-class citizens, and let me pass custom CLI arguments when I needed to do something weird.
This project follows a hard-cut policy: we delete old-state compatibility code rather than carrying it forward. Any temporary migration or compatibility code must be called out in the same diff with why it exists, why the canonical path is insufficient, exact deletion criteria, and the task that tracks its removal.
Swift
97.0%
Shell
1.8%
I kept running into this problem: I clicked a link in Slack, and it opened in Safari. But I was logged into that AWS account in Chrome Profile 3, and the Figma link should just open in the desktop app, not another browser tab.
Yojam fixes that. Set it as your default browser, and it catches every link you click. Using rules you define, it routes each link exactly where it belongs - or pops up a fast picker right at your cursor so you can choose on the fly.
utm_source, fbclid, gclid, and 30+ other tracking parameters before the browser ever sees them. Per-browser or globally.mailto: links and routes them to your preferred client.~/Library/Application Support/Yojam/config.json. Edits in the file get picked up by the app in real time, and vice-versa. Good for dotfile repos or scripted changes.Yojam picks up links from every source macOS can offer:
http/https URLs (the default-browser path).ASWebAuthenticationSession, such as Slack and Claude..html, .xhtml, .webloc, .inetloc, and .url files..webloc files, which Yojam unwraps transparently.yojam:// URL scheme, for Shortcuts, Raycast, Alfred, shell scripts, and any other automation.Every one of these goes through the same rule engine, tracker scrubber, and rewrite pipeline as a direct click. There is no second-class handling.
Yojam forwards the first URL from a web authentication session to your chosen browser. It cannot see later navigation inside that browser or send the callback to the source app. An app that depends only on the session callback can keep waiting after you finish in the browser. Apps with a separate callback URL handler can still finish the sign-in. Yojam does not claim ephemeral-session support because the chosen browser keeps its cookies and profile state.
Install via Homebrew:
brew install --cask yojam
Or grab the DMG from yoj.am and drag Yojam to your Applications folder. On first launch, Yojam asks to become your default browser.
Yojam checks yoj.am for updates every hour. When a new version is ready, a dot appears on the menu bar icon, the menu gains an Update to Yojam x.y.z… entry, Preferences shows an Install Update button, and Yojam posts a notification if you allow it. You can also check any time from Preferences > General > Updates, from the About tab, or from the menu bar icon > Check for Updates….
You need macOS 14+ and Xcode 16+. Yojam uses XcodeGen for the project file.
# Install xcodegen if you haven't
brew install xcodegen
# Generate the Xcode project and build
xcodegen generate
open Yojam.xcodeproj
Build and run from Xcode. On first launch, Yojam asks to become your default browser - say yes, that's how it intercepts links.
Note:
swift build/swift runcompiles the code and runs tests, but won't produce a working.appbundle. macOS requires a proper app bundle with Info.plist and URL scheme registration to function as a default browser. The Share Extension, Safari Web Extension, and native messaging host are Xcode-only targets produced byxcodegen generate && xcodebuild.
swift build only builds the bare Yojam executable and YojamCore library.Extensions/build.sh produces dist/yojam-chrome.zip and dist/yojam-firefox.xpi from the shared WebExtension source. Signing and store submission are out of scope for this script.When you click a link anywhere on your Mac, Yojam processes it through a pipeline:
mailto: so subjects and bodies stay intact)| Mode | What happens |
|---|---|
| Always show picker | Unmatched links show the browser picker; matching rules still fire immediately. |
| Hold Shift to pick | Links route via rules or your default. Keep Shift held until the picker appears to choose instead. |
| Smart + Fallback | Rules fire automatically. Learned domains auto-route. Everything else shows the picker. |
Shift also acts as a one-off escape hatch in the other modes: it skips matching rules and URL rewrites, then shows the picker with the original link. macOS delivers an external URL separately from the originating click, so keep Shift held until Yojam's picker appears.
| Key | Action |
|---|---|
| 1–9 | Jump to browser at that position |
| ←→ / ↑↓ | Move selection |
| Enter / Space | Open in selected browser |
| Cmd+C | Copy URL to clipboard |
| Esc | Dismiss picker |
Yojam ships with built-in rules for Zoom, Telegram, Slack, Discord, Spotify, Apple Music, FaceTime, Apple Maps, Microsoft Teams, Figma, Linear, Notion, WhatsApp, Signal, App Store, TestFlight, and Podcasts. They auto-disable when the target app isn't installed and re-enable when it is. Built-in rules are also fully editable - tweak, duplicate, or delete them, and Restore Default Rules in Advanced brings them back.
Discord ignores plain web links handed to it, so Yojam converts discord.com channel, message, and invite links (and discord.gg invites) to discord:// deep links at launch time. The URL tester shows the converted link.
Add your own rules matching on all URLs, domain (exact), domain suffix, URL prefix, URL substring, or regex. Rules can optionally filter by source app - only route links from Slack to your work browser, for example.
Beyond picking the target app or browser, each rule can pin:
github.com to Chrome specifically in the Work profile, while your other Chrome rules use Personal.$URL as the placeholder.--user-data-dir setups.These overrides only apply to the specific rule, so a rule-level private-window toggle won't flip the browser's own default.
For ingress paths that don't have a real originating app, Yojam uses synthetic bundle identifiers. You can target these in rules to handle links differently depending on how they arrived:
| Sentinel | Ingress path |
|---|---|
com.yojam.source.handoff | Handoff from another Apple device |
com.yojam.source.authentication-session | App sign-in session |
com.yojam.source.airdrop | AirDropped .webloc files |
com.yojam.source.share-extension | Share menu |
com.yojam.source.service | Services menu |
com.yojam.source.safari-extension | Safari extension |
com.yojam.source.chrome-extension | Chrome/Chromium extension |
com.yojam.source.firefox-extension | Firefox extension |
com.yojam.source.url-scheme | yojam:// URL scheme |
For example, you could write a rule like: Source App = com.yojam.source.handoff → always open in Work profile.
The Share Extension adds "Open in Yojam" to the macOS share menu. It shows up in Safari, Notes, Mail, Finder, Reminders, Photos, and other apps that support the share sheet. One tap forwards the URL to Yojam silently.
To enable it: System Settings > Privacy & Security > Extensions > Sharing, then turn on Yojam.
The "Open in Yojam" entry appears in the Services menu in every Cocoa app. Highlight any URL text, right-click, and pick it from the Services submenu.
To add a global keyboard shortcut: System Settings > Keyboard > Keyboard Shortcuts > Services, find "Open in Yojam", and assign a shortcut.
Ships inside Yojam.app. Enable it in Safari > Settings > Extensions.
Download yojam-chrome.zip from the latest GitHub release, unzip it, then load the extracted folder as an unpacked extension. Until a stable Chrome Web Store ID is published, the unpacked build uses the yojam:// fallback and Chrome may ask once before handing the link to Yojam. The no-prompt native-messaging path will be enabled for the store build.
Firefox release builds require Mozilla-signed extensions, and Yojam is not on AMO yet. The raw yojam-firefox.xpi attached to GitHub releases is for Orion and Firefox development builds configured to allow unsigned extensions. A normal Firefox install will need the AMO build once it is published.
Container routing needs Orion 1.1 or newer and the Firefox build of the Yojam WebExtension. Download yojam-firefox.xpi from the latest GitHub release. In Orion > Settings > Advanced, allow third-party Firefox extensions. Then open Tools > Extensions > Manage Extensions, choose Add Extension, and install the XPI. See Orion's WebExtension guide for Orion's current installation and compatibility details.
Alt+Shift+Y sends the current tab to Yojam.yojam:// URL schemeYojam registers a yojam:// URL scheme for automation. Any app, script, or shortcut can trigger it:
yojam://route?url=<percent-encoded>&source=<bundle-id>&browser=<bundle-id>&pick=1&private=1
yojam://settings
Parameters:
url (required): the target URL. Must decode to http, https, or mailto.source (optional): bundle identifier for source-app rule matching.browser (optional): force a specific target browser by bundle ID, skipping rules.pick=1 (optional): force the picker regardless of activation mode.private=1 (optional): open in private/incognito window if the target browser supports it.Example Shortcuts recipe: create a Shortcut with an "Open URL" action pointing at yojam://route?url= followed by the URL you want to route.
Not limited to browsers. Click + Add in the Browsers tab and pick any .app or executable. For apps that don't natively handle URLs, use $URL where the link belongs. Without it, Yojam appends the URL after your custom arguments:
$URL
--url $URL
--browse $URL
Yojam passes these arguments directly - no shell involved.
For Chromium-based browsers, set Data Dir when an entry should use a custom --user-data-dir; the profile menu reloads from that directory and Yojam opens it as a new app instance. $HOME and leading ~/ are expanded without invoking a shell.
Six tabs in preferences (menu bar icon > Preferences, or Cmd+,):
On first launch Yojam shows a Quick Start card above the tabs. It guides you through default-browser registration. If Bumpr, Choosy, or Finicky is installed, it also offers to import compatible routes and rewrites.
The URL tester on the Link Handling tab lets you paste a URL and see exactly what Yojam would do - which rewrites fire, whether trackers get stripped, which rule matches, and where it ends up.
Settings can be exported as JSON and imported on another machine.
group.org.yojam.shared — shared storage between the main app and its extensions.The first time certain features are used, macOS will show:
yojam:// (from browser extension fallback path).Everything happens locally on your Mac. Yojam doesn't phone home, track your clicks, or send your data anywhere. The Share Extension and browser extensions only hand a URL to the local Yojam process. The native messaging host only forwards URLs you explicitly trigger — it never reads page contents. Nothing hits the network.
The only network activity is iCloud sync (uses your own Apple ID, off by default) and checking for updates via yoj.am (can be disabled in Preferences).
.webloc from Preferences > Integrations.~/Library/Preferences/com.yojam.app.plist are not read. Reconfigure from Preferences.BSD 3-Clause. See LICENSE.
There are other browser pickers out there. I wanted one that felt invisible most of the time, stripped trackers globally, supported browser profiles as first-class citizens, and let me pass custom CLI arguments when I needed to do something weird.
This project follows a hard-cut policy: we delete old-state compatibility code rather than carrying it forward. Any temporary migration or compatibility code must be called out in the same diff with why it exists, why the canonical path is insufficient, exact deletion criteria, and the task that tracks its removal.
Swift
97.0%
Shell
1.8%