Variables set with set_string_variable not persisting across BTT restarts

Hi @Andreas_Hegenberg , Hi All,
I'm experiencing an issue where variables set using set_string_variable do not seem to persist after BetterTouchTool is restarted.

I initially tried to save data (an array of favorite crypto IDs as a JSON string) from a Floating WebView widget using the JavaScript function await set_string_variable({ variable_name: "my_webview_variable", to: jsonString });.

To debug, I created a separate AppleScript trigger (get_string_variable "my_webview_variable") assigned to a keyboard shortcut.

Before restarting BTT:
Running the AppleScript trigger correctly returned the JSON string that was set by the WebView's JavaScript. This indicates the set_string_variable call from the WebView was received by BTT initially.

After restarting BTT: Running the same AppleScript trigger returned nothing. The variable seemed to be lost during the restart.

To rule out issues with the WebView interaction, I performed a simpler test using only AppleScript triggers:

tell application "BetterTouchTool"
    set_string_variable "test_persistence_variable" to "Test Value " & (random number from 1 to 1000)
    return "Test Variable Set!"
end tell
tell application "BetterTouchTool"
    return get_string_variable "test_persistence_variable"
end tell

runAppleScrpti 1 correctly sets the variable.
run appleScript 2 before restarting BTT correctly displays the "Test Value xxx" in the script result.
After completely restarting BetterTouchTool , pressing only appleScript 2 results in "no value being displayed"

This simplified test seems to confirm that the issue is with BTT's core ability to persist variables set via set_string_variable across restarts on my system, as the problem occurs even when using only AppleScript.

i checked in the btt doc this page Using Variables in BetterTouchTool

it describes the variable system itself. it reaffirms that the variables im using should be persistent. However, it provides no explanation or solution for the case where this persistence fails, even though the functions seem to be called correctly (as evidenced by the pre-restart tests).

Is there anything else to do to make everything persistent after restarting Better Touch Tool?

I think what you are looking for is set_persistent_string_variable

https://docs.folivora.ai/docs/1102_apple_script.html#setpersistentstringvariable

1 Like

thanks for your reply

im doing some test with applesript to really understand, and I'm experiencing issues with the AppleScript cmd get_persistent_string_variable,

The set_persistent_string_variable command seems to execute without error. The primary issue is reading the variable / ensuring persistence.

get_persistent_string_variable "varname" --> Fails syntax check ("Expected end of line but found “"”.)

what im doing wrong ?

to read the variables you always use get_string_variable (or get_number_variable)

The different functions are only needed when setting a variable to determine whether they should be persistent when btt quits

1 Like

thanks you so much :slight_smile:

now im trying on my project but my webView console logs clearly show the Named Trigger WebView_Save_Persistent_Var is being called successfully by the JavaScript. but, the data supposedly saved by the appleScript action within that trigger still fails to persist after restarting BTT.

i tried to made many script, but i always have an error syntax, and i dont undersatnd why?

Why would the "set_persistent_string_variable" command, which works fine in direct AppleScript tests, fail to actually persist the data when executed via a Named Trigger called from JavaScript, even though the trigger fires and the script seems to run (at least partially, based on JS logs)? Is there a limitation, a known bug, or perhaps an issue with reading the temporary variables within the triggered script's context?
Thanks for looking into this!

on run
	tell application "BetterTouchTool"
		try
			-- Get name and value passed from JS via temp variables
			set theVariableName to get_string_variable "temp_js_var_name"
			set theVariableValue to get_string_variable "temp_js_var_value"
			
			-- Check if temp vars were retrieved
			if theVariableName is not missing value and theVariableName is not "" and theVariableValue is not missing value then
				log message "Trigger AS: Variables OK. Name = " & theVariableName 
				
				-- Use the persistent AS command
				set_persistent_string_variable theVariableName to theVariableValue 
				
				log message "Trigger AS: Set Persistent Executed pour " & theVariableName 
				return "OK: Sauvegarde tentée pour " & theVariableName
			else
				log message "Trigger AS: ERREUR - Variables temps non trouvées."
				return "Erreur: miss data"
			end if
			
		on error errMsg number errNum
			log message "Trigger AS: ERREUR GLO - " & errMsg & " (" & errNum & ")" 
			return "Erreur: Script AS échoué"
		end try
	end tell
end run

Are you using this exact script?

In Apple Script there is no "log message", it's just called "log"

Also this is a lot of indirection (webview => js => named trigger => apple script => js ), could you just set the variable in Java Script? (await set_persistent_string_variable({variableName: "someVar", to: "someValue"})

1 Like

Thanks so much for the clarifications regarding "log" "log message" in AppleScript, and especially about the existence of "set_persistent_string_variable"in JavaScript!

You asked why I was using the complex JS => Named Trigger => AppleScript workaround. The reason i ended up there is that I couldnt seem to call any BTT JavaScript bridge functions directly from my WebView

When I try to use your suggestion "await set_persistent_string_variable(...)" or even the initial "await get_string_variable" calls during the widget "initializeApp" function, my WebView Developer Console consistently shows:

"[Warning] BTT func 'get_string_variable' missing"

This indicates the BTT JavaScript bridge isn't providing the necessary functions "get_string_variable", "set_string_variable', "set_persistent_string_variable" to the WebView environment.

The AppleScript workaround via the Named Trigger "WebView_Save_Persistent_Var" was an attempt to bypass this "missing functions" problem, not a preferred method. Even then, while the JS successfully called the Named Trigger, the BTT logs showed the associated AppleScript wasn't actually executing its log commands

The core problem seems to be the JavaScript bridge not initializing or injecting functions into the WebView.

Do you have any idea why the JS bridge functions "get_string_variable", "set_persistent_string_variable" etc... might not be available in the WebView, even with "Use Plain Webview..." unchecked?

it takes a few milliseconds until the BTT functions are initialized on a new webview, you can either use the lifecycle functions or just use a small timeout to solve that

https://docs.folivora.ai/docs/10_4_webview_lifecycle.html

Thanks again for your help and for suggesting the direct use of "set_persistent_string_variable" from JavaScript. my head is boiling :slight_smile:

Ive implemented that, and I also used the "bttWebViewDidFinishLoad" lifecycle function to ensure the JS bridge is ready (I no longer get the "BTT func missing" errors).

When I try to save data from the WebView (e.g., saving a favorite), my console logs show that the call to "await set_persistent_string_variable({ variableName: name, to: value });" seems to execute successfully without throwing any JavaScript error:

"[Log] > Saving PERSISTENT variable via JS (using camelCase "variableName"): btt_crypto_user_favorites" "[Log] < Variable btt_crypto_user_favorites sauvegardée (persistante via JS - camelCase)"

However, despite this successful call logged in the console, the variable still does not persist after I restart BTT. When the widget reloads, "get_string_variable" (which you confirmed is the correct function for reading) returns null for "btt_crypto_user_favorites".

I know persistence can work on my system, because separate tests using the AppleScript command "set_persistent_string_variable name to value" do successfully persist data across restarts.

I feel likr I must be missing something or misunderstanding the correct usage for the JavaScript version of "set_persistent_string_variable". Could you perhaps clarify if there are specific conditions, timing considerations, or prerequisites needed for the JS function to reliably ensure the variable state is saved before BTT quits, differently from the AppleScript command?

Sorry to bother you again with this, but I'm stuck on this last step for my code. Any further advice would be greatly appreciated.

Thanks so much,

Mhm I could only imagine some other script clearing these variables. There are no restrictions.

You can always check the temp/persistent variables here (I'm currently creating a new UI for that):

Is it listed under "Persistent Variables" after running your script?

1 Like

Just wanted to follow up and say thank you.

it's finally working correctly now! Your advice regarding the correct JavaScript functions and the potential timing issue was key

Initialization Timing: The crucial part was handling the initialization timing. The "bttWebViewDidFinishLoad" lifecycle function didn't seem to fire reliably or early enough before needing the variables. The solution was:

to call my main initialization function (initializeApp) from the standard DOMContentLoaded event listener.
Place an await new Promise(resolve > setTimeout(resolve, 1500)); delay at the very beginning of initializeApp, before any calls to get_string_variable (like getFavorites).

This delay seems to give the BTT JavaScript bridge enough time to fully initialize and load the persistent variables after a BTT restart, allowing get_string_variable to read them successfully. Without the delay (or when using the lifecycle function), the initial get_string_variable calls returned "null" even though the JS bridge functions themselves were no longer reported as "missing".

Thanks again for your essential help and for making BTT!

Mhh where did you get that one from?
The function that is called after the basic initialization has happened is

function BTTInitialize() {

}

Once that is called any scripting capabilities should be available

While I was troubleshooting the initialization timing issue and digging all over online for solutions and examples, I think I must’ve accidentally copied or just remembered the wrong function name from somewhere when I got stuck.

That’s probably why my initialization wasn’t firing properly after a restart.

I'm so happy it's working, it's like a release! I plan to post my crypto widget in the 'Setup & Preset Sharing' section later for others.

thinking about sharing presets made me think: it would be really cool to have something like a built-in preset 'store' or gallery inside BTT, with a nice interface, where we could easily discover, download, and maybe share everything the community creates, perhaps as an alternative or addition to the current Preset forum tab. Just an idea!

2 Likes