Execute your own JavaScript in a native mobile app and get real Bubble values back: numbers, dates, lists and objects, not just strings. Async/await support, automatic type conversion both ways, a configurable timeout for async code, and rock-solid error handling that never crashes your app. The native alternative to web Toolbox.
Your code runs in the app's own JavaScript engine, so there is no WebView and no slow load.
-> See it in action in our demo app:
https://betternotcode-plugins.bubbleapps.io/version-test/api/1.1/mobile/preview?debug_mode=true&preview_view=custom_js_runner-> See in editor:
https://bubble.io/page?id=betternotcode-plugins&app_type=mobile&tab=Design&name=custom_js_runner&type=page&version=test&elements=bTSdM-> User documentation:
https://betternotcode.notion.site/Toolbox-Custom-JS-runner-native-mobile-for-Bubble-io-User-Documentation-3824240d2e28801e9511c6e80fe66632How it works
Drop one invisible element on the page.
Call the Run JavaScript action with your code.
Return any value and the plugin detects its type for you. A number lands in result_number, a date in result_date as a real Bubble date, a list in the matching list state, an object in result_json. A result_type state tells you what came back, and result_text is always a readable version.
Coming from the web Toolbox?
The migration is mostly about dropping the workarounds you no longer need:
-> The action and the typed states now live in one element, instead of a Run javascript action paired with a JavascriptToBubble element.
-> You publish a result with return value, instead of bubble_fn_suffix(value).
-> The output type is detected for you, instead of declared by hand.
-> Numbers and dates pass through typed, so the "format as text" tricks and the date re-parsing are gone.
-> List inputs are real arrays, with no proxy gymnastics.
async/await also works better than on web: it is real promise support, not a fire-and-forget call.
Why there is no "write the whole function" field
You might expect a single field where you type a whole function and drop Bubble dynamic expressions straight into the code. We left that out on purpose, because inserting a dynamic value into a text field turns it into a string, so your numbers and dates would lose their type. A stray quote or line break would break the code outright.
Plus, any value coming from an end user would be concatenated into your code, which is an open door to injection.
Typed parameters avoid all of this: a value is always data, never code. So you write your code once, reference the parameters by name, and bind your Bubble expressions to them.
If you need more parameters than the built-in ones, you can always put a JSON string in a text parameter and parse it in your code.
Elegant error handling
Every run is wrapped so nothing reaches your page uncaught. Syntax errors, runtime exceptions, rejected promises, timeouts and unsupported values all come back as a readable error_message with a stable code you can branch on (NO_CODE, SYNTAX_ERROR, RUNTIME_ERROR, PROMISE_REJECTED, TIMEOUT, etc.).
If two runs overlap, only the newest one publishes (button-mashing won't leave a stale result on screen).
Documentation and AI support
We built the user documentation we wish every plugin had.
The plugin also ships with a context document you can paste into any AI assistant. Once pasted, it knows every action, field, state and common pitfall, so it can write your Bubble expressions or diagnose an error for you. It is downloadable from the documentation link.
This plugin only works in native apps
It will not work for web apps or WebView-wrapped apps. BDK, Natively and similar wrappers do not use the React Native runtime the plugin relies on.
Try risk-free
The monthly subscription is prorated by the day. Try the plugin for a few days; if it is not the right fit, cancel and pay only for the days you used.