Skip to main content

Creating Floating Menus With JSON and AI

Floating Menus are normal BetterTouchTool triggers with the trigger class BTTTriggerTypeFloatingMenu. That means they can be created in the UI, exported as JSON, imported again, edited by scripts, and generated by AI.

This page explains the creation formats that are useful when you want to build menus programmatically or ask the BetterTouchTool AI assistant to build them for you.

Which Format Should I Use?

Use the normal BTT UI when

You want to design one menu manually, tune the visual details by eye, or create a reusable template item that scripts or AI can reference later.

Use Simple JSON when

You want a script to dynamically produce menu items. This is the easiest format for AI and for JavaScript content scripts because it focuses on titles, icons, subitems and actions instead of every internal BTT property.

See Simple JSON Format for the full syntax.

Use a bundled template when

You want one of BetterTouchTool's shipped examples as a starting point. These are stored in the app bundle under DefaultTemplates and include the same defaults shown in the template picker.

The AI assistant can import them by template id:

Template idUse when
default-menu-integratedBasic three-button menu.
context-menu-likeContext-menu style menu with submenus.
hot_corner_exampleMenu that expands from the top-left hot corner.
now-playingNow Playing widget menu.
launcher_webviewLauncher-integrated webview menu.
drawerDrawer widget menu.
appswitcherCircular app switcher example.
notchMenu positioned relative to the MacBook notch.

Use full Floating Menu JSON when

You want to import a complete menu, including its size, positioning, layout, item styles, web views, widgets, submenus, and action JSON.

This is the most powerful format, and it is the format used by BetterTouchTool's floating menu AI skill when it imports a new menu.

The AI assistant validates generated floating-menu JSON before importing it. The validator expands the short keys, checks the menu tree, catches misspelled or misplaced BTTMenuConfig properties, verifies important enum values, and reports errors with JSON paths and suggested fixes.

Use a Swift plugin widget when

The menu item should be a native custom view, for example a live timer, a CPU monitor, a mini dashboard, or a fully interactive SwiftUI component.

See Floating Menu Widget Plugins.

Runtime Model

A Floating Menu is a tree of menu objects:

  • The top-level object has BTTTriggerType: 767.
  • Every item in the menu is another object inside BTTMenuItems.
  • Menus and menu items both store most of their layout and appearance in BTTMenuConfig.
  • Submenus are items with BTTTriggerType: 774 and their own nested BTTMenuItems.
  • Menu item actions are stored in BTTMenuItemActions.

At runtime, BetterTouchTool loads enabled floating-menu triggers from Core Data, merges global and app-specific menus with the same menu identifier/name, decodes the JSON into menu models, and displays them in floating menu windows. Positioning, hover behavior, item scripts, dynamic content scripts, and runtime property updates are then handled by the Floating Menu runtime.

For users, the important part is this: generated JSON should describe the desired menu tree cleanly. BetterTouchTool handles UUID creation, window creation, positioning updates, script execution, and UI rendering after import.

Full JSON Structure

The most important fields for a full import are:

[
{
"BTTTriggerType": 767,
"BTTTriggerClass": "BTTTriggerTypeFloatingMenu",
"BTTEnabled": 1,
"BTTTriggerName": "Floating Menu: My Menu",
"BTTMenuName": "My Menu",
"BTTMenuAvailability": 0,
"BTTMenuConfig": {},
"BTTMenuItems": []
}
]

UUIDs are optional. If you omit BTTUUID and BTTTriggerParentUUID, BetterTouchTool generates and links them during import.

Short Keys

AI-generated menu JSON often uses short keys to reduce token usage. BetterTouchTool expands these during import:

Short prefixExpands toExample
©BTT©TriggerType -> BTTTriggerType
$BTTMenu$Config -> BTTMenuConfig
§BTTMenuItem§s -> BTTMenuItems

For example, this is equivalent to the full structure above:

[
{
"©TriggerType": 767,
"©TriggerClass": "©TriggerTypeFloatingMenu",
"©Enabled": 1,
"©TriggerName": "Floating Menu: My Menu",
"$Name": "My Menu",
"$Availability": 0,
"$Config": {},
"§s": []
}
]

Both formats are valid. Humans often find the full BTT... keys easier to read. AI imports often use the short keys.

Minimal Working Example

This creates a centered horizontal menu with three buttons. It uses full key names for readability.

[
{
"BTTTriggerType": 767,
"BTTTriggerClass": "BTTTriggerTypeFloatingMenu",
"BTTEnabled": 1,
"BTTTriggerName": "Floating Menu: Quick Work",
"BTTMenuName": "Quick Work",
"BTTMenuAvailability": 0,
"BTTMenuConfig": {
"BTTMenuPositioningType": 1,
"BTTMenuPositionRelativeTo": 3,
"BTTMenuAnchorMenu": 4,
"BTTMenuAnchorRelation": 4,
"BTTMenuSizingBehavior": 1,
"BTTMenuFrameWidth": 360,
"BTTMenuFrameHeight": 96,
"BTTMenuLayoutDirection": 7,
"BTTMenuHorizontalSpacing": 8,
"BTTMenuVerticalSpacing": 8,
"BTTMenuWindowLevel": 3,
"BTTMenuCloseAfterAction": 1,
"BTTMenuItemBackgroundType": 4,
"BTTMenuItemBackgroundColor": "30, 32, 38, 230",
"BTTMenuItemBlurredBackground": 1,
"BTTMenuItemCornerRadius": 12,
"BTTMenuItemPaddingLeft": 8,
"BTTMenuItemPaddingRight": 8,
"BTTMenuItemPaddingTop": 8,
"BTTMenuItemPaddingBottom": 8
},
"BTTMenuItems": [
{
"BTTTriggerType": 773,
"BTTTriggerClass": "BTTTriggerTypeFloatingMenu",
"BTTEnabled": 1,
"BTTOrder": 0,
"BTTTriggerName": "Menu Item: Mission Control",
"BTTMenuName": "Mission Control",
"BTTMenuAvailability": 0,
"BTTMenuItemActions": [
{
"BTTPredefinedActionType": 7,
"BTTPredefinedActionName": "Mission Control",
"BTTEnabled": 1,
"BTTOrder": 0
}
],
"BTTMenuConfig": {
"BTTMenuItemVisibleWhileActive": 1,
"BTTMenuItemVisibleWhileInactive": 1,
"BTTMenuItemMinWidth": 112,
"BTTMenuItemMaxWidth": 112,
"BTTMenuItemMinHeight": 72,
"BTTMenuItemMaxHeight": 72,
"BTTMenuItemBackgroundType": 4,
"BTTMenuItemBackgroundColor": "0, 122, 255, 255",
"BTTMenuItemBackgroundColorHover": "40, 152, 255, 255",
"BTTMenuItemCornerRadius": 10,
"BTTMenuItemIconType": 2,
"BTTMenuItemSFSymbolName": "rectangle.3.group",
"BTTMenuItemIconPosition": 1,
"BTTMenuItemIconColor1": "255, 255, 255, 255",
"BTTMenuItemImageHeight": 24,
"BTTMenuAttributedText": "<html><body style=\"text-align:center;\"><span style=\"font-size:13px; color:white; font-family:-apple-system;\">Mission</span></body></html>"
}
},
{
"BTTTriggerType": 773,
"BTTTriggerClass": "BTTTriggerTypeFloatingMenu",
"BTTEnabled": 1,
"BTTOrder": 1,
"BTTTriggerName": "Menu Item: Paste Date",
"BTTMenuName": "Paste Date",
"BTTMenuAvailability": 0,
"BTTMenuConfig": {
"BTTMenuItemVisibleWhileActive": 1,
"BTTMenuItemVisibleWhileInactive": 1,
"BTTMenuItemMinWidth": 112,
"BTTMenuItemMaxWidth": 112,
"BTTMenuItemMinHeight": 72,
"BTTMenuItemMaxHeight": 72,
"BTTMenuItemBackgroundType": 4,
"BTTMenuItemBackgroundColor": "52, 199, 89, 255",
"BTTMenuItemBackgroundColorHover": "76, 217, 100, 255",
"BTTMenuItemCornerRadius": 10,
"BTTMenuItemIconType": 2,
"BTTMenuItemSFSymbolName": "calendar",
"BTTMenuItemIconPosition": 1,
"BTTMenuItemIconColor1": "255, 255, 255, 255",
"BTTMenuItemImageHeight": 24,
"BTTMenuAttributedText": "<html><body style=\"text-align:center;\"><span style=\"font-size:13px; color:white; font-family:-apple-system;\">Date</span></body></html>"
}
},
{
"BTTTriggerType": 773,
"BTTTriggerClass": "BTTTriggerTypeFloatingMenu",
"BTTEnabled": 1,
"BTTOrder": 2,
"BTTTriggerName": "Menu Item: App Expose",
"BTTMenuName": "App Expose",
"BTTMenuAvailability": 0,
"BTTMenuItemActions": [
{
"BTTPredefinedActionType": 6,
"BTTPredefinedActionName": "Application Expose",
"BTTEnabled": 1,
"BTTOrder": 0
}
],
"BTTMenuConfig": {
"BTTMenuItemVisibleWhileActive": 1,
"BTTMenuItemVisibleWhileInactive": 1,
"BTTMenuItemMinWidth": 112,
"BTTMenuItemMaxWidth": 112,
"BTTMenuItemMinHeight": 72,
"BTTMenuItemMaxHeight": 72,
"BTTMenuItemBackgroundType": 4,
"BTTMenuItemBackgroundColor": "255, 149, 0, 255",
"BTTMenuItemBackgroundColorHover": "255, 179, 64, 255",
"BTTMenuItemCornerRadius": 10,
"BTTMenuItemIconType": 2,
"BTTMenuItemSFSymbolName": "macwindow",
"BTTMenuItemIconPosition": 1,
"BTTMenuItemIconColor1": "255, 255, 255, 255",
"BTTMenuItemImageHeight": 24,
"BTTMenuAttributedText": "<html><body style=\"text-align:center;\"><span style=\"font-size:13px; color:white; font-family:-apple-system;\">Expose</span></body></html>"
}
}
]
}
]

When you create real action JSON, copy it from BetterTouchTool or look it up in the action definitions. Do not rely on guessed action IDs.

Important Item Types

BTTTriggerTypeItem typeNotes
767Floating MenuTop-level container.
773Standard itemButton-like item with text, icon, scripts and actions.
774SubmenuContains nested BTTMenuItems.
775SliderHas a value from 0 to 1; value change scripts can update labels or trigger actions.
776Text fieldUser-entered value is available through scripting.
777Back buttonUseful inside submenus.
778Web viewDisplays HTML or URL from BTTMenuItemText.
801Row breakerForces following items onto the next row.
802Column breakerForces following items into the next column.
810Text areaMultiline text input.
811Floating menu referenceEmbeds/references another floating menu.
813Folder widgetDisplays a folder.
821App widgetApp-related built-in widget.
829Now Playing widgetBuilt-in media widget.
830Weather widgetBuilt-in weather widget.
835Custom Swift widgetNative plugin widget; set BTTMenuWidgetCustomPluginID.
836Drawer widgetFile drawer/drop-zone style widget.

Positioning

Use BTTMenuPositioningType to choose how the menu finds its position.

ValueMeaningBest for
0Free moveUser manually drags the menu somewhere.
1Fixed positionPredictable generated menus. Uses reference, anchors and offsets.
2Menubar status itemStatus-item style menus.
3Center on focused screenSimple centered menus.
4Fixed initial positionPlace once, then behave like a free-moving menu.

For AI-created menus, 1 is usually best because it produces deterministic results.

BTTMenuPositionRelativeTo selects the reference frame:

ValueReference
0Focused window
1Screen with mouse
2Specific screen
3Focused screen
7Mouse position
8Built-in display
9Dynamic variable in active-window coordinates
10Dynamic variable in screen coordinates
11MacBook notch
12Focused screen menubar
16Mouse screen menubar
19Screen with Dock
20Green window button
21Hovered item of another floating menu
22Specific floating menu
23Dock
24All windows
25Specific window

Anchors decide which point of the menu is placed at which point of the reference frame:

ValueAnchor
0Top left
1Top right
2Bottom left
3Bottom right
4Center
5Top edge center
6Right edge center
7Bottom edge center
8Left edge center

Example: center a menu on the focused screen:

{
"BTTMenuPositioningType": 1,
"BTTMenuPositionRelativeTo": 3,
"BTTMenuAnchorMenu": 4,
"BTTMenuAnchorRelation": 4,
"BTTMenuOffsetX": 0,
"BTTMenuOffsetY": 0
}

Example: show a menu above the current mouse location:

{
"BTTMenuPositioningType": 1,
"BTTMenuPositionRelativeTo": 7,
"BTTMenuAnchorMenu": 7,
"BTTMenuAnchorRelation": 4,
"BTTMenuOffsetY": 16
}

Sizing

BTTMenuSizingBehavior controls how the menu gets its size:

ValueBehavior
1Fixed. Use BTTMenuFrameWidth and BTTMenuFrameHeight.
2Variable. Width/height come from BTT variables.
3Content. Menu resizes to fit its content.
4Min/max. Uses frame min/max constraints.

For generated menus, fixed sizing is the most predictable. Content sizing is convenient when item count changes dynamically.

{
"BTTMenuSizingBehavior": 1,
"BTTMenuFrameWidth": 320,
"BTTMenuFrameHeight": 220
}

For variable sizing:

{
"BTTMenuSizingBehavior": 2,
"BTTMenuFrameWidthVariable": "my_menu_width",
"BTTMenuFrameHeightVariable": "my_menu_height"
}

Layout

BTTMenuLayoutDirection controls item placement:

ValueLayout
0Fill row, then continue with next row
1Fill column, then continue with next column
2Fill row with fixed wrapping
3Fill column with fixed wrapping
4Absolute, scrollable
5Absolute, fixed
6Vertical one column
7Horizontal one row
8Circular

For most generated menus:

  • Use 7 for a toolbar.
  • Use 6 for a vertical command list.
  • Use 0 for a grid.
  • Use 8 for radial menus shown near the mouse.
  • Use 5 only when you explicitly set each item's BTTMenuItemX and BTTMenuItemY.

Visibility and Window Behavior

Useful menu-level properties:

PropertyMeaning
BTTMenuVisibility0 show on launch, 1 show via action, 2 restore via app activation.
BTTMenuWindowLevelWindow level. 3 floats above normal windows, 0 behaves like a normal window.
BTTMenuWindowResizable1 lets the user resize the menu.
BTTMenuCloseOnOutsideClick1 closes when clicking elsewhere.
BTTMenuCloseAfterAction1 closes after an item action.
BTTMenuCloseOnKeyboardInput1 closes after keyboard input.
BTTMenuCloseOnMoveMouseAway1 closes when the mouse leaves.
BTTMenuDisableDrag1 prevents dragging.
BTTMenuStealKeyboardFocusOnShow1 asks the menu to take keyboard focus when shown.
BTTMenuClickThroughEmptyParts1 sends clicks on empty menu areas to the app behind it.
BTTMenuClickThroughEverywhere1 makes all clicks pass through.

For keyboard-driven menus shown by a shortcut, set BTTMenuVisibility to 1, then use the Show/Hide/Toggle Floating Menu actions.

Item Visibility

Most normal items should include:

{
"BTTMenuItemVisibleWhileActive": 1,
"BTTMenuItemVisibleWhileInactive": 1
}

If you omit these on hand-written JSON, items may not appear in the states you expect.

You can also conditionally show items based on variables:

{
"BTTMenuItemVisibleIfVariableIsTrue": "show_work_tools",
"BTTMenuItemVisibleIfVariableIsFalse": "hide_work_tools"
}

Styling

Colors use R, G, B, A strings with 0-255 values:

{
"BTTMenuItemBackgroundType": 4,
"BTTMenuItemBackgroundColor": "40, 44, 52, 230",
"BTTMenuItemBackgroundColorHover": "70, 76, 90, 255"
}

Common item style properties:

PropertyMeaning
BTTMenuItemBackgroundType4 for color, 5 linear gradient, 6 radial gradient, 1 image data, 7 preset file.
BTTMenuItemBackgroundColorMain background color.
BTTMenuItemBackgroundColor2 to 4Additional gradient colors.
BTTMenuItemBackgroundColorHoverBackground while hovered.
BTTMenuItemBlurredBackground1 enables blur.
BTTMenuItemGlassEffectEnables the newer glass style when supported.
BTTMenuItemBorderWidthBorder width.
BTTMenuItemBorderColorBorder color.
BTTMenuItemCornerRadiusCorner radius.
BTTMenuItemShadowEnabled1 enables shadow.
BTTMenuItemShadowRadiusShadow radius.

Dark mode variants usually use the Dark suffix, for example BTTMenuItemBackgroundColorDark.

Text

For standard items, use BTTMenuAttributedText. It can contain RTF or HTML.

HTML is often easiest for generated menus:

{
"BTTMenuAttributedText": "<html><body style=\"text-align:center;\"><span style=\"font-size:16px; color:white; font-family:-apple-system;\">Open Calendar</span></body></html>"
}

For web view items, use BTTMenuItemText for the HTML or URL:

{
"BTTMenuItemText": "https://folivora.ai"
}

For scripts that update existing item text, BTTMenuItemText is useful because BetterTouchTool applies the existing configured text style to the new string.

Icons and SF Symbols

For SF Symbol icons:

{
"BTTMenuItemIconType": 2,
"BTTMenuItemSFSymbolName": "star.fill",
"BTTMenuItemSFSymbolStyle": 1,
"BTTMenuItemIconColor1": "255, 255, 255, 255",
"BTTMenuItemIconPosition": 4,
"BTTMenuItemImageHeight": 32
}

Useful icon values:

PropertyValues
BTTMenuItemIconType0 none, 1 image data, 2 SF Symbol, 3 file, 7 preset file, 8 internal image.
BTTMenuItemIconPosition0 left, 1 top, 2 right, 3 bottom, 4 center, 5 none.
BTTMenuItemSFSymbolStyle0 monochrome, 1 hierarchical, 2 palette, 3 multicolor.

For image files, use BTTMenuItemIconType: 3 and BTTMenuItemIconPresetPath or the relevant file/preset path property.

A submenu is an item with BTTTriggerType: 774.

{
"BTTTriggerType": 774,
"BTTTriggerClass": "BTTTriggerTypeFloatingMenu",
"BTTEnabled": 1,
"BTTMenuName": "More",
"BTTMenuConfig": {
"BTTMenuItemVisibleWhileActive": 1,
"BTTMenuItemVisibleWhileInactive": 1,
"BTTMenuUseStyleForSubmenu": 0,
"BTTMenuAttributedText": "<html><body><span style=\"font-size:14px; color:white;\">More</span></body></html>"
},
"BTTMenuItems": [
{
"BTTTriggerType": 777,
"BTTTriggerClass": "BTTTriggerTypeFloatingMenu",
"BTTEnabled": 1,
"BTTMenuName": "Back",
"BTTMenuConfig": {
"BTTMenuItemVisibleWhileActive": 1,
"BTTMenuItemVisibleWhileInactive": 1,
"BTTMenuAttributedText": "<html><body><span style=\"font-size:14px; color:white;\">Back</span></body></html>"
}
}
]
}

Use a back button (777) when the submenu replaces the current menu content. If the submenu appears beside or over the menu, a back button may not be needed.

Web View Items

Use BTTTriggerType: 778.

{
"BTTTriggerType": 778,
"BTTTriggerClass": "BTTTriggerTypeFloatingMenu",
"BTTEnabled": 1,
"BTTMenuName": "Mini Web",
"BTTMenuConfig": {
"BTTMenuItemVisibleWhileActive": 1,
"BTTMenuItemVisibleWhileInactive": 1,
"BTTMenuItemMinWidth": 420,
"BTTMenuItemMinHeight": 280,
"BTTMenuItemText": "<html><body style=\"font-family:-apple-system;\">Hello</body></html>",
"BTTMenuItemWebViewPlain": 0,
"BTTMenuItemKeepActiveInBackground": 1
}
}

Useful web view properties:

PropertyMeaning
BTTMenuItemTextHTML string or URL.
BTTMenuItemWebViewPlain1 disables BTT scripting support inside the web view.
BTTMenuItemUserAgentCustom user agent.
BTTMenuItemUserScriptScript run on load.
BTTMenuItemUserScriptOnvisibleScript run when visible.
BTTMenuItemWebViewFocusTextField1 auto-focuses an input.
BTTMenuItemKeepActiveInBackground1 keeps the web view active while hidden/backgrounded.
BTTMenuItemSystemBrowserPrefixURL prefixes that should open in the system browser.

You can later update the web view with the Floating Menu Load HTML action or with webview_menu_item_load_html_url_js.

Built-In Widgets

Some item types expose widget-specific BTTMenuConfig properties.

Custom Swift Widget

Use BTTTriggerType: 835 and set BTTMenuWidgetCustomPluginID:

{
"BTTTriggerType": 835,
"BTTTriggerClass": "BTTTriggerTypeFloatingMenu",
"BTTEnabled": 1,
"BTTMenuName": "CPU Widget",
"BTTMenuConfig": {
"BTTMenuItemMinWidth": 220,
"BTTMenuItemMinHeight": 120,
"BTTMenuWidgetCustomPluginID": "com.bttuserplugin.swift.cpu-widget"
}
}

Compile/install the widget plugin first, then import the menu that references it.

Now Playing Widget

Use BTTTriggerType: 829. Useful properties include:

PropertyMeaning
BTTMenuWidgetNowPlayingHideCover0 album cover, 1 app icon, 2 hidden.
BTTMenuWidgetNowPlayingShowAlbum1 shows album text.
BTTMenuWidgetNowPlayingLayout0 horizontal, 1 vertical.
BTTMenuWidgetNowPlayingShowProgress1 shows progress.
BTTMenuWidgetNowPlayingAllowedAppsComma-separated bundle IDs, empty for all.

Weather Widget

Use BTTTriggerType: 830. Useful properties include:

PropertyMeaning
BTTMenuWidgetWeatherUnit0 Celsius, 1 Fahrenheit, 2 system.
BTTMenuWidgetWeatherAutoLocation1 auto, 0 manual.
BTTMenuWidgetWeatherLatLonManual "lat,lon".
BTTMenuWidgetWeatherForecastDay-1 current, 0 to 7 forecast.

Actions

Floating menu item actions are stored in BTTMenuItemActions.

{
"BTTMenuItemActions": [
{
"BTTPredefinedActionType": 7,
"BTTPredefinedActionName": "Mission Control",
"BTTEnabled": 1,
"BTTOrder": 0
}
]
}

If you use the short-key format, this becomes §Actions.

Action JSON can be nested and action-specific. For reliable imports, copy action JSON from BetterTouchTool or use the action definition lookup in the AI assistant before generating the final menu.

Dynamic Menus With Simple JSON

For dynamically generated contents, configure a floating menu content script and return Simple JSON.

async function retrieveJSON() {
return JSON.stringify([
{
title: "Open Safari",
icon: "sfsymbol::safari::color@@#0A84FF",
width: 120,
height: 64,
action: {
js: "runShellScript({script: 'open -a Safari'})"
}
},
{
title: "More",
icon: "sfsymbol::ellipsis.circle",
subitems: [
{
title: "Say Hello",
icon: "sfsymbol::speaker.wave.2",
action: "js::runShellScript({script: `say hello`})"
}
]
}
]);
}

Useful Simple JSON item properties:

PropertyMeaning
titleText, optionally with ::size@@18::color@@#ffffff.
iconsfsymbol::name, path::~/file.png, or base64::....
backgroundHex or rgba color.
width / heightFloating menu item size.
templateItemUUIDUse an existing item as style template.
subitemsStatic submenu items.
actionOne action string/object or an array of actions.
actionsAction categories such as standard, rightclick, hover, hoverend, appear, disappear, ondrop.

For floating menus, a Simple JSON container can also include any full floating-menu config properties to override the template:

async function retrieveJSON() {
return JSON.stringify({
type: "floatingmenu",
BTTMenuSizingBehavior: 3,
BTTMenuLayoutDirection: 7,
BTTMenuItemBackgroundColor: "20, 22, 28, 230",
items: [
{
title: "Template Based",
templateItemUUID: "PASTE-A-MENU-ITEM-UUID-HERE",
icon: "sfsymbol::sparkles"
}
]
});
}

Templates are very useful for AI-generated dynamic menus: design one good-looking item in the BTT UI, copy its UUID, and let the script or AI reuse it for many generated items.

Updating Menus at Runtime

You can update item properties without re-importing the whole menu.

Item script return value

An item script can return JSON5:

async function itemScript(itemUUID) {
return "{BTTMenuItemBackgroundColor: '20, 200, 20, 255', BTTMenuItemText: 'Ready'}";
}

JavaScript function

async function updateItem() {
await update_menu_item({
menu_name: "Quick Work",
item_name: "Status",
json: JSON.stringify({
BTTMenuItemText: "Done",
BTTMenuItemBackgroundColor: "52, 199, 89, 255"
}),
persist: false
});
returnToBTT("updated");
}

AppleScript

tell application "BetterTouchTool"
update_menu_item menu_name "Quick Work" item_name "Status" json "{BTTMenuItemText: 'Done'}" persist false
end tell

Use persist: true only when the runtime update should become the saved default.

Showing and Hiding Generated Menus

Generated menus can be shown with the normal predefined actions:

ActionType
Show Floating Menu386
Hide Floating Menu387
Toggle Floating Menu388
Open Floating Menu Submenu472
Close Floating Menu Submenu445
Floating Menu Load HTML397
Floating Menu Execute JavaScript398
Re-evaluate Position390
Run Floating Menu Content Scripts469

When the menu should be shown only by a shortcut, gesture, Stream Deck button, or other trigger, set:

{
"BTTMenuVisibility": 1
}

Then configure the trigger to run Show, Hide, or Toggle Floating Menu and target the menu by name or UUID.

AI Creation Checklist

When asking AI to create a floating menu, include:

  • The purpose of the menu.
  • Whether it should be always visible or shown by an action.
  • Where it should appear: focused screen, mouse position, focused window, desktop, notch, menubar, etc.
  • Expected size or layout: toolbar, vertical list, grid, circular menu, dashboard.
  • Item list with labels, icons and actions.
  • Whether the menu should close after clicking an item.
  • Whether keyboard focus is needed.
  • Whether any item should be dynamic, scripted, a web view, or a Swift widget.

Before importing generated JSON, check:

  • The top-level value is a JSON array, unless importing a preset wrapper.
  • The menu has BTTTriggerType: 767 and BTTTriggerClass: "BTTTriggerTypeFloatingMenu".
  • Every item has BTTTriggerClass: "BTTTriggerTypeFloatingMenu".
  • Items that should appear have BTTMenuItemVisibleWhileActive: 1 and BTTMenuItemVisibleWhileInactive: 1.
  • Fixed-position menus have positioning type, reference, menu anchor and relation anchor.
  • Fixed-size menus have frame width and height.
  • Standard item text uses BTTMenuAttributedText; web views use BTTMenuItemText.
  • Action JSON was copied or looked up, not guessed.
  • UUIDs are either omitted or unique.

Common Problems

The menu imports but no items are visible

Add BTTMenuItemVisibleWhileActive: 1 and BTTMenuItemVisibleWhileInactive: 1 to the item configs. Also confirm the items are inside BTTMenuItems.

The menu is off-screen

Use fixed positioning relative to the focused screen while developing:

{
"BTTMenuPositioningType": 1,
"BTTMenuPositionRelativeTo": 3,
"BTTMenuAnchorMenu": 4,
"BTTMenuAnchorRelation": 4
}

If it is a free-moving menu, use the action that brings free-moving floating menus to the current screen.

The text does not render as expected

For standard items, prefer BTTMenuAttributedText. Use BTTMenuItemText mainly for web view content and runtime text updates.

The menu opens but steals focus unexpectedly

Set BTTMenuStealKeyboardFocusOnShow to 0, or use the Show/Toggle Floating Menu action's keyboard focus option.

A generated action does the wrong thing

Regenerate only the action JSON after looking up the exact action definition or copying the action from BetterTouchTool. Floating menu item layout JSON and action JSON are separate concerns.

A dynamic script is slow

Use content scripts for dynamic items, but cache expensive results where possible. For visual style, use templateItemUUID so the script only needs to return content and actions.