Integrations

Links don't only arrive from clicks. This page covers sign-in popups, other URL schemes, scripts and browser add-ons, and shortened links.

Sign-in popups

Apps that sign in with ASWebAuthenticationSession send their URLs through AuthenticationServices rather than ordinary URL delivery. Grinch routes these requests with the same rules as other links, and opens the sign-in page in the selected browser as a normal tab. It does not move the authentication session into that browser or watch what the page does next. Since the requesting app isn't available to Grinch, rules see com.apple.AuthenticationServices as the opener and no modifier keys for these requests.

Requests that arrive while Grinch is starting wait for the first config load. If no config is available, a rule suppresses the URL, or the browser can't be opened, Grinch ends the sign-in request with an error. Requests cancelled during startup don't open a browser.

Ordinary links received during startup also wait for the first config load. If that load fails, Grinch drops those queued links and records their count in the diagnostic log. For a Universal Link delivered as a web activity, Grinch cannot identify the originating app, so ctx.opener is null.

Finishing the sign-in is best effort. The callback has to come back to Grinch to complete the pending session. Grinch matches incoming callback URLs against pending requests and returns matching ones to the app that asked. If a callback matches more than one pending request, Grinch cancels those requests so it doesn't deliver the response to the wrong app. Registering a callback with ASWebAuthenticationSession doesn't make Chrome send it to Grinch, so apps that rely only on the session callback can keep waiting after the sign-in page has done its job.

On macOS 13 through 14.3, callbacks are matched with the older custom-scheme API. HTTPS host-and-path callbacks need macOS 14.4 or later.

Startup timing and private sessions

Grinch installs its sign-in handler before it starts accepting events, so a request made while Grinch is still launching doesn't fall through to Safari. Grinch also declares CallbackURLMatchingIsSupported, because some apps, notably Slack, only use browsers that advertise it.

Grinch declares IsSupported but not EphemeralBrowserSessionIsSupported. It opens your regular browser tab, with your existing cookies and profile, so it can't provide the isolation a private (ephemeral) session asks for. macOS may handle those requests in Safari instead, and they bypass your rules.

Other URL schemes

Grinch can also route local .html files and Universal Links delivered as web activities. Delivery depends on your macOS file and link associations.

Grinch declares support for tel:, webcal:, and feed:, but macOS may send those links to another app. When a link is delivered to Grinch, it goes through the same rules; match it with a scheme pattern such as "webcal:*". You can also use the grinch: prefix to send an individual link through Grinch.

The grinch: scheme

Put grinch: in front of any URL to route it through your rules, even when Grinch isn't the default browser. This works from Shortcuts, AppleScript, and open in a shell:

Terminal
open grinch:https://example.com/path
open 'grinch:tel:+15551234567'

Grinch removes the grinch: prefix first, so your rules match the inner URL. Grinch --test grinch:… tests the same way.

Browser add-ons

Grinch also accepts grinch://open/<base64-url>, where the inner URL is encoded with btoa(). This is the format Finicky's Chrome and Firefox add-ons send. Point those add-ons at grinch://open/… instead of finicky://open/… and their "Open with Finicky" menu item routes through Grinch, whether or not it is the default browser. Standard (+, /) and URL-safe (-, _) base64 both work, with or without = padding.

URL shorteners

Grinch decides synchronously, so a rule can't follow a short link's redirects; await fetch() doesn't run. For hosts such as bit.ly, t.co, lnkd.in, and ow.ly, choose one of two approaches.

Send them to your usual browser

Your rules won't see the final host, but the browser opens normally with no added delay:

{
  match: domain("bit.ly", "t.co", "lnkd.in", "ow.ly", "buff.ly", "tinyurl.com"),
  open: browsers.personal,
}

Expand them before Grinch

examples/expand-shortener.sh follows redirects from bit.ly, t.co, goo.gl, lnkd.in, ow.ly, buff.ly, and tinyurl.com, including their www. forms, making at most ten requests in five seconds. It opens the first destination outside those hosts with open, leaving login redirects and cookies to your browser, and Grinch routes that destination normally. Other hosts pass through, and if expansion fails the original URL opens.

Terminal
chmod +x examples/expand-shortener.sh
examples/expand-shortener.sh "https://bit.ly/3GyNJpL"

Run it from a launcher you already use:

  • Raycast or Alfred: bind it to a hotkey that passes the URL on the clipboard.
  • Hammerspoon: register an hs.urlevent handler that calls the script with the URL.
  • Shortcuts: wrap it in a Quick Action that takes URLs from the share sheet and runs expand-shortener.sh "$1".
  • Terminal: copy the link, then run examples/expand-shortener.sh "$(pbpaste)".

Shortened links then wait for a network round trip, typically 50 to 500 ms, but that happens outside Grinch, so every other link still routes without it.