Docs Examples FAQ Discussion Thanks

Run Javascript

Expression

Javascript to Bubble

List of Numbers

List Item Expression

Server Script

Properties
Workflow step
Async Function
Keys and values
Params - Bubble
Params - Vanilla
Ignore error
Multiple outputs
Timing
Limitations
Security

Examples

FAQ


News

Version history

Server script

Runs javascript on the server. The script runs as a Node.js AWS Lambda micro-service.

Server script properties Server script properties Server script properties

V4 plugin API

This page describes the plugin after the upgrade to plugin API V4, which includes Node.js version 18.

Setting properties

Node script Will be evaluated as a Node.js script. Can include dynamic data.

Script is Async Function Allows use of await at top-level. Expects the script to contain a return statement.

Ignore errors Wraps the script in a try/catch, and discards errors caught.

Log errors Log ignored error in the app server logs. (May need a paid plan for logs to show)

Inputs

Data A text-only parameter, available to the script as data

Keys and values An arbitrary number of text key-value pairs can be set. Available to the script as properties.keyvalues, in Bubble's default list form, or in an improved object form as properties.keyvaluesobj

Thing 1 to Thing 3 Parameters of any type. Available to the script as properties.thing1, etc.

Thing list 1 to Thing list3 Similar to thing1, but in list form. Available to the script as properties.thinglist1, etc.

Outputs

Return type usually you will want a "vanilla" type such as text, number, date, yes/no. Can return Bubble data types, API return types.

Returns a list to produce list of texts, for example.

Multiple Outputs allows returning multiple data types. The return value of the script needs to be an object with properties matching the output names.

output1 type to output4 type the type of output.

outputlist1 type to outputlist4 type the type of list output.

Workflow step

The server script is an action, it runs server-side, the same way a database or API action does. It can be run on a page workflow, which can be triggered by a button or other event on the page.

page workflow

Or it can be run on a backend workflow, which can be triggered by an incoming external API call, or by a database trigger, or by a Schedule API Workflow action.

backend workflow

Script is Async Function

Normally the script is evaluated as a code block, and the last statements value will be used as a return value.

Eval block example

Using promises

fetch('https://api.thecatapi.com/v1/images/search')
.then(response => response.json())
.then(body => body[0].url)

Async function example

Turn on Async Function allows use of await at top-level.

Expects the script to contain a return statement.

const response = await fetch('https://api.thecatapi.com/v1/images/search')
const body = await response.json()
const cat_image = body[0].url
return cat_image

Keys and values

Say for example the following key-value pairs are set: "apple": "A spherical fruit" "banana": "A long finger-like fruit"

To access the values in the script, use either of:

desc = properties.keyvalues.find(x => x.key == "apple")?.value
desc = properties.keyvaluesobj["banana"]

Bubble data types as parameters

A parameter set to a Bubble data type appears as an object with functions listProperties(), get(propertyname)

Example with thing1 set to: Search for Fruits:first item

Eval block example

JSON.stringify(properties.thing1.listProperties());
// ['name_text', 'overripe_color_option_color', 'ripe_color_option_color', 'unripe_color_option_color', 'Created By', 'Slug', 'Created Date', 'Modified Date', '_id']

properties.thing1.get('name_text').then(nam => nam);
// 'Banana'

properties.thing1.get('overripe_color_option_color').then(color => color)
// 'Black'

Async function example

return JSON.stringify(properties.thing1.listProperties());
// ['name_text', 'overripe_color_option_color', 'ripe_color_option_color', 'unripe_color_option_color', 'Created By', 'Slug', 'Created Date', 'Modified Date', '_id']

return await properties.thing1.get('name_text');
// 'Banana'

return await properties.thing1.get('overripe_color_option_color');
// 'Black'

A parameter list set to a list of Bubble data types does not appear in javascript as an array, but instead as an iteratable object.

Example with thinglist1 set to: Search for Fruits

Eval block example

properties.thinglist1
  .length()
  .then(len => properties.thinglist1.get(0, len))
  .then(arr => Promise.all(arr.map((item) => item.get("name_text"))))
  .then(arrtexts => arrtexts); // array of names

Async function example

// var len = await properties.thinglist1.length();
var result = [];
for await (const item of properties.thinglist1) {
  // result.push(item.listProperties());
  result.push(await item.get("name_text"));
}
return result; // array of names

An extended example of reading properties of nested objects: showing book titles and their associated category names

Example with thinglist1 set to: Search for Books

var len = await properties.thinglist1.length();
var result = [];
for await (const item of properties.thinglist1) {
    // result.push(item.listProperties());
    result.push(await item.get("title_text"));
    var cat = await item.get("category_custom_category");
    // result.push(cat.listProperties());
    var catname = await cat.get("name_text");
    result.push(catname);
}
return result; // list of text

Some examples are in this app editor

Vanilla data types as parameters

A parameter set to a vanilla data type (text, number, etc)

Example with thing1 set to: Search for Fruits:count

Eval block example

var result = properties.thing1;

Async function example

var result = properties.thing1;
return result;

A parameter list set to a list of vanilla data types

Example with thinglist1 set to: Search for Fruits:each items name

Eval block example

properties.thinglist1
  .length()
  .then(len => properties.thinglist1.get(0, len))
  .then(arr => Promise.all(arr.map(item => item)))
  .then(arrtexts => arrtexts) // this line to show where to add more processing

Async func example

// var len = properties.thinglist1.length();
var result = [];
for await (const item of properties.thinglist1) {
  result.push(item);
}
return result;

Ignore error

Wraps the script in a try/catch, and ignores or logs the errors.

Multiple outputs

Enabling this allows returning multiple data types. For example, set output1 type to text and output2 type to number:

return {output1: "apple", output2: 69};

Timing

Bubble then spins up an AWS Lambda (micro-function) instance to run the Node.js script. Typical start timings are:

The results of the Node.js script are made available on the workflow step to be used in other workflow steps, such as writing to database.

Limitations

The script has no access to the Bubble app's database or other workflow step results etc. It only knows the data it is passed as parameters, and can only return results through the workflow step. It does have internet access, so could be made to access the app via API calls, but that is an even more indirect approach.

Toolbox does not know in advance which npm package you may want to use, so it does not load any. The packages that come built-in to Node are available.

There is a script size limit of 2 million chars.

Server script is a plugin server action, which runs the code on AWS Lambda, with the default configuration of 30 seconds. If exceeded, there is an error thrown and the workflow is terminated.

Workarounds for the 30 second limit:

Security

As server script evaluates an arbitrary Node.j script, there is the potential for a Bubble app to run a script entered by an untrusted end user. Be cautious, as you the Bubble app owner are responsible for any action the script takes (such as API calls to anywhere).

A recommended approach is to send user-entered data into the script via one of the supplied parameters. Within the script ensure the data is escaped appropriately if using it in, for example, your own eval function.