xbar on Mac: how to set it up

xbar puts the output of any script into the macOS menu bar. Installing it does nothing visible on its own, which is where most first sessions stall. Nothing appears until a plugin file exists in the right folder, with the right name, and with the execute bit set.

This walks through the setup in the order it actually happens: getting the app onto the machine, placing the first plugin, understanding the output format, moving settings out of the script, and diagnosing the case where the menu bar stays empty.

Installing it

Two routes exist. The disk image can be downloaded from the project site or its release page and dragged to the Applications folder, or Homebrew can handle it, where the cask is named xbar and currently resolves to version v2.1.7-beta.

The stated requirement from the project README is macOS Catalina or newer, meaning 10.15 and above. Inspecting the shipped build confirms a few things worth knowing before installation. The binary is universal, covering both Intel and Apple silicon natively. It carries a Developer ID signature with the hardened runtime enabled, and it passes notarisation checks, so first launch does not trigger a Gatekeeper block.

Size is modest. The disk image is about 8.5 MB and the installed application is roughly 24 MB, which is small for a resident app. The Homebrew cask lists supported platforms from Big Sur through the current release, and the cask is neither deprecated nor disabled.

The application registers a custom URL scheme, xbar://. That is the mechanism the plugin site uses to hand an installation off to the app, and it is worth knowing about because clicking an install link on a web page will open the local application rather than downloading a file.

Where plugins live

The plugin directory is ~/Library/Application Support/xbar/plugins. Every executable file in it becomes one menu bar entry.

Reaching it from Finder is fastest through Go to Folder, pasting that path. Keeping the window open during setup saves time, because most early troubleshooting comes down to whether a file is in this exact folder.

For browsing published plugins, the application has a built in directory reachable from its menu under Preferences and then Plugins. The project site carries the same catalogue organised by category, covering areas such as AWS, Cloud, Dev, Finance, Music, Network, System, Time, and Weather.

One decision belongs here rather than later: whether xbar launches at login. Registering it as a login item makes sense once a configuration has settled. During evaluation, leaving it unregistered keeps removal simple.

The filename is the configuration

The single most surprising part of xbar is that the refresh interval is not set in a preferences window. It is set in the filename, using the convention {name}.{time}.{ext}.

A file named date.1m.sh runs every minute. Documented interval formats include 10s for ten seconds, 1m for a minute, 2h for two hours, and 1d for a day. Changing how often a plugin runs is a rename, nothing more.

Two other requirements sit alongside it. The file must be executable, which means running chmod +x on it. And it should begin with a shebang line, with the guide recommending the #!/usr/bin/env form, such as #!/usr/bin/env bash. A file that is present but not executable produces exactly the same symptom as a file that is absent: nothing in the menu bar.

Choose the interval deliberately at this stage. A value that changes every few minutes gains nothing from a ten second refresh, and if the script makes a network request, that interval multiplies directly into request volume. Matching the interval to how fast the underlying value actually moves avoids reworking it later.

The output format, in three rules

A plugin is any executable that prints lines to standard output. Three rules cover almost everything.

A line containing only three hyphens is a divider. Everything above it appears in the menu bar. Everything below appears in the dropdown after a click. Lines beginning with two hyphens become submenu items, and each additional pair of hyphens nests one level deeper.

Parameters are appended after a pipe character. The list is long, but the useful subset is short.

Parameter Effect
href= Makes the line clickable and opens the target
shell= Runs a script, with arguments passed as param1= and onward
refresh=true Re-runs the plugin after the line is clicked
length= Truncates the line and adds a tooltip with the full text
color= and size= Change appearance
disabled=true Greys the line out and stops it responding
key= Assigns a keyboard shortcut to the item

Two behaviours catch people out. Multiple lines above the divider do not stack, they cycle, rotating every few seconds in the menu bar. And plugin execution has a time limit, raised from one minute to two minutes in version v2.1.7-beta, so a script that queries several endpoints in sequence needs to finish inside that window.

A third parameter is worth knowing early because its name suggests the opposite of what it does. Setting dropdown=false keeps a line in the status bar while removing it from the dropdown, rather than removing it from the bar. Alongside it, alternate=true marks a line as a replacement for the one before it, shown only while the Option key is held, which is a tidy way to offer a second action without adding a permanent row. Neither changes how many slots the plugin occupies, only what those slots display.

Write the first plugin rather than installing one

Installing a published plugin as the first step makes diagnosis harder, because a failure could be the script, the folder, the permissions, or the environment. A hand written plugin of three lines eliminates most of those variables.

The sequence is short. Create a file in any text editor, put a shebang on the first line, add one command that prints text, save it into the plugin folder with an interval in the name, then set the execute bit. Text appears in the menu bar.

While that file is open, it is worth testing the divider. Print three lines, then insert a line of three hyphens after the first one. Only the first line will show in the bar, and the other two will appear on click. Seeing that once makes every published plugin readable at a glance, because the divider position tells you exactly what the thing will occupy.

For anything intended to be kept, add the metadata comments the guide describes: xbar.title, xbar.version, xbar.author, and xbar.desc. Those fields populate the listing in the app and on the site, and even for a private script they answer the question of what it was for when it gets opened again months later.

Move settings out of the script

Hardcoding an API token or a display limit inside a plugin means editing code every time it changes. xbar provides a way to lift those values out.

Declaring a variable takes one comment line using an xbar.var tag. Four types are supported: string, number, boolean, and select, where select also lists its valid options. Declared variables appear as editable fields in the application preferences, and whatever the user enters is passed to the script at run time as an environment variable of the same name. Prefixing names with VAR_ makes the app format the label neatly.

Values are stored beside the plugin in a JSON file named after it with a .vars.json suffix, so tail.5s.sh is accompanied by tail.5s.sh.vars.json. Copying both files to another machine carries the configuration across intact.

Using this for private plugins as well as published ones pays off quickly. Adjustments happen in a preferences window instead of a text editor, and the script itself stops changing.

Turning a plugin off without uninstalling anything

Setup is easier when every step is reversible, and with xbar most of them are. Switching a plugin off does not require an uninstaller or a preferences toggle. Moving the file out of the plugin folder is enough, because the folder contents are the configuration. After a refresh, that menu bar entry disappears.

Putting the file back restores it exactly as it was. If the accompanying .vars.json file travelled with it, the stored settings come back too, with nothing to re enter. That property makes a trial period practical: anything of uncertain value can be moved to a holding folder for a couple of weeks and then either restored or discarded based on whether it was missed.

The same logic applies to the application itself. The Homebrew cask definition names the locations xbar uses, which are ~/Library/Application Support/xbar, ~/Library/Caches/com.xbarapp.app, ~/Library/Preferences/com.xbarapp.app.plist, and ~/Library/WebKit/com.xbarapp.app. The login item is registered under the name xbar, so System Settings is the place to confirm nothing relaunches after a restart.

The first of those paths is the one worth backing up. Custom plugins and their variable files all live under it, so copying that folder before a machine migration carries an entire configuration across in one step. Restoring it on the new machine, then reapplying the execute bit, reproduces the previous setup without revisiting any of the earlier steps.

When nothing appears in the menu bar

The empty menu bar has a short list of causes, best checked in order.

Confirm the file is in the plugin folder rather than somewhere that looks similar. Confirm the execute bit is set. Confirm the first line specifies an interpreter. Confirm the filename has three segments with a valid interval in the middle. Then run the script directly in a terminal and check that it prints what is expected.

That last step is the decisive one. A script that works in a terminal but produces nothing in xbar is almost always an environment problem. The environment xbar runs a plugin in does not load a shell profile, so commands installed in locations outside the default search path are not found. The guide's suggested fix is to export an explicit PATH inside the plugin itself.

Some behaviours are not the script's fault at all. The public tracker carries open reports about plugins stopping while the screen is locked, instability after many repeated refreshes, and memory growth over long sessions, with 186 issues open and the last release dating from October 2021. When something behaves oddly and the script is provably correct, searching the tracker is often faster than further debugging.

What to set up next

Place one plugin, confirm it appears, then set its interval to match how often the value really changes before adding a second. Once several are running, remember that each occupies its own menu bar slot, and decide whether to trim output or fold entries away using the approaches described on Features and compared on How it compares. If the bar is already full before xbar arrives, start there instead, with Koffret.

Frequently asked questions

Nothing shows in the menu bar after installing xbar. Is it broken?

Probably not. xbar displays nothing until a plugin exists in ~/Library/Application Support/xbar/plugins with the execute bit set. Run chmod +x on the file and confirm it starts with a shebang line. If it still does not appear, run the script in a terminal to see whether it prints anything at all.

Where is the refresh interval configured?

In the filename. The convention is {name}.{time}.{ext}, so date.1m.sh runs once a minute. Valid interval formats include 10s, 1m, 2h, and 1d. Changing the interval means renaming the file, and no other configuration step is involved.

How can an API key be kept out of the plugin script?

Declare it as a variable using an xbar.var comment tag. It then appears as an editable field in the application preferences and is passed to the script as an environment variable at run time. Types available are string, number, boolean, and select, and values are stored in a .vars.json file next to the plugin.

Which macOS versions does xbar support?

The project README states macOS Catalina, version 10.15, or newer. The shipped build is a universal binary covering Intel and Apple silicon, and it is signed with a Developer ID and notarised, so first launch is not blocked by Gatekeeper. The Homebrew cask lists supported platforms from Big Sur onward.

Back to all posts