---
updatedAt: 2025-09-12T00:26:45.000Z
agentTools:
  projectIndex: https://developers.asana.com/llms.txt
---

# How to write a Script Action script

> 📘 Examples: [asana-examples/script-actions-examples](https://github.com/asana-examples/script-actions-examples)

## 1. Installing the Scripts by Asana application

In order to start using Script Actions, you must first install the **Scripts by Asana** app:

1. Open up any project
2. Navigate to **Customize** > **Rules** > **Create custom rule**. This will take you to the project's rule builder page
3. Navigate to **+ Do this…** > **External actions** > **Run script** > **Connect to Scripts by Asana**
4. A new tab will open, displaying the Grant Permission page for the app. Click on **Allow**
5. You have successfully installed Scripts by Asana and are now ready to start creating automation rules with Script Actions

<Image align="center" src="https://files.readme.io/0a3459b-installing_scripts_by_asana.gif" />

## 2. Setting up a Script Action rule

1. Open the project where you would like to setup a Script Actions rule
2. Navigate to **Customize** > **Rules** > **Create custom rule**. This will take you to the rule builder page where you can setup your rule
3. For the purpose of this guide, let's create a simple rule. Go ahead and select the **+ When…** card
4. Select **Task is assigned** trigger
5. Click on the **x** button on the **Check if…** card
6. Select the **Do this…** card
7. Navigate to the **External actions** tab > **Run script**. This will open the script editor, where you can begin writing your script
8. For now, let’s leave the default script content and publish the rule. Click on the **Publish rule** button

<Image align="center" src="https://files.readme.io/656a0b3-setting_up_a_script_action_rule.gif" />

## 3. Writing a Script

In the previous section, we published a rule using the default script provided by Scripts by Asana. In this section, we will write our own script to replace the default one.

Scripts written for Script Actions use the [node-asana (v3.X.X)](https://www.npmjs.com/package/asana) client library to make API calls to Asana. While writing your scripts, you can reference the [node-asana (v3.X.X)](https://www.npmjs.com/package/asana) sample code of an endpoint by going to **Node** > **node-sdk-v3**

<Image align="center" src="https://files.readme.io/8d1ad81-node_sdk_sample_code.png" />

> 📘 Provided Variables
>
> By default, Script Actions provides the following variables to your script on each run: `project_gid`, `task_gid`, `workspace_gid`. This means that you can simply reference these variables in your script without needing to define them.

In this guide, we’ll write a script to **“validate that the task name is an email address and add a comment to the task with the result”**

<HTMLBlock>{`
<iframe src="https://player.vimeo.com/video/989793943?h=20c0a8ebc2" width="640" height="400" frameborder="0" allow="autoplay; fullscreen; picture-in-picture" allowfullscreen></iframe>
`}</HTMLBlock>

### A: Planning process

Let's outline our implementation plan. First, we'll identify the necessary API endpoints. In this scenario, we need to make two API calls:

1. [Get a task (GET /tasks/\{task\_gid})](/reference/gettask) - We'll need this to retrieve information about the task
2. [Create a story on a task (POST /tasks/\{task\_gid}/stories)](/reference/createstoryfortask) - We’ll need this to add a comment on the task with the validation result

Next, let's outline the steps needed to achieve our script's objective. The following actions can help us accomplish this goal:

1. Make an API call to get the name of the task that the rule ran on
2. Write a function to check if the provided string is in an email format
3. Make an API call to add a comment on the task with the result

### B: Developing and testing your script locally on your computer

> 📘 Character Limit
>
> The script editor has a character limit of 100,000. Please ensure your script does not exceed this limit.

**Prerequisite**: ensure you have [Node.js](https://nodejs.org/en/download/package-manager/current) installed on your computer

1. Open your preferred code editor and create a new file named `validateTaskName.js`
2. In your terminal, change directory to where you have your `validateTaskName.js`file stored
3. Run`npm init` and go through the prompts
4. Run `npm install asana`. This will install the latest version of the [node-asana](https://github.com/Asana/node-asana) client library for your project
5. Copy the following template code into your code editor

```javascript
const Asana = require('asana');

let client = Asana.ApiClient.instance;
let token = client.authentications['token'];
// TODO: Replace <YOUR_PERSONAL_ACCESS_TOKEN> with your Personal Access Token (PAT)
// NOTE: This is only used for testing your script locally
token.accessToken = "<YOUR_PERSONAL_ACCESS_TOKEN>";

const log = console.log;

// Set your project, task and workspace gid here
// These values will be provided to you when your script gets executed
// We want to emulate that so we set those values here
//
// TODO: Set these values
const project_gid = "123";
const task_gid = "456";
const workspace_gid = "789";

// Set up the resource instances that you plan on using for your script here
// Script actions will make these available for you in the script editor
//
// TODO: instantiate the Asana resources that you plan on using in your script
// EX: If you want to make API calls to the tasks endpoint, uncomment the line below
// let tasksApiInstance = new Asana.TasksApi();

/*
----------------------------------------------------------------------------------------
Write your script below, then COPY and PASTE your script into the script editor
----------------------------------------------------------------------------------------
*/

/**
 * What's in scope?
 * 1. (string) project_gid, workspace_gid, task_gid (only if triggered on a task)
 * 2. (function) log - this behaves like console.log and takes any number of parameters
 * 3. (object) *ApiInstance - for each group of APIs, an object containing functions to call the APIs; for example:
 *    tasksApiInstance.getTask(...)
 *    goalsApiInstance.addFollowers(...)
 * For more info, see https://github.com/Asana/node-asana
 */

const run = async () => {
  // TODO: Write your script here
};

run();

```

6. Before you begin writing your script, carefully review each of the `TODO`s provided in the template code and ensure all required information is filled in. Doing this will closely replicate what is given to you by the script editor
   1. Replace `<YOUR_PERSONAL_ACCESS_TOKEN>`
   2. Replace `project_gid`, `task_gid`, and `workspace_gid`
   3. Add the Asana API resources that you will use in your script. For this script, we will need the `tasksApiInstance`and `storiesApiInstance`

```javascript
// Instantiate Asana API resources
// TODO: instantiate the Asana resources that you plan on using in your script
// EX: If you want to make API calls to the tasks endpoint, uncomment the line below
let tasksApiInstance = new Asana.TasksApi();
let storiesApiInstance = new Asana.StoriesApi();
```

> 📘 Tip
>
> To get `<YOUR_PERSONAL_ACCESS_TOKEN>`, `project_gid`, `task_gid`, and `workspace_gid` for the above script template you can:
>
> * **\<YOUR\_PERSONAL\_ACCESS\_TOKEN>**: can be generated from the [developer console](https://app.asana.com/0/my-apps)
>
> <details>
>
> <summary><b>project_gid</b>: reference the <b>gid</b> from the project URL</summary>
>
> <Image align="center" src="https://files.readme.io/c9331e5-project_gid.png" />
>
> </details>
>
> <details>
> <summary><b>task_gid</b>: reference the <b>gid</b> from the task URL</summary>
>
> <Image align="center" src="https://files.readme.io/aeae76b-task_gid.png" />
>
> </details>
>
> * **workspace\_gid**: from <https://app.asana.com/api/1.0/workspaces>

7. Navigate to the documentation for [Get a task (GET /tasks/\{task\_gid})](/reference/gettask) and reference the **Node** > **node-sdk-v3** sample code

```javascript
const task = await tasksApiInstance.getTask(task_gid, { 'opt_fields': "name" });
```

8. Write a function called `isEmailText` to check if the name of the task is an email and return a boolean value as the result

```javascript
const isEmailText = (text) => {
    const emailRegex = /^[\w\.-]+@[a-zA-Z\d\.-]+\.[a-zA-Z]{2,}$/;
    return emailRegex.test(text);
};
```

9. Navigate to the documentation for [Create a story on a task (POST /tasks/\{task\_gid}/stories)](/reference/createstoryfortask) and reference **Node** > **node-sdk-v3** sample code

```javascript
let storyRequestBody = {
  "data": {
    "text": `<SUCCESS_MESSAGE/FAIL_MESSAGE>`
  }
};
storiesApiInstance.createStoryForTask(storyRequestBody, task_gid);
```

10. Putting it all together we get:

```javascript
// Checks if the provided text is in email format
const isEmailText = (text) => {
    const emailRegex = /^[\w\.-]+@[a-zA-Z\d\.-]+\.[a-zA-Z]{2,}$/;
    return emailRegex.test(text);
};

const run = async () => {
  // 1. Get information about the triggered task
  const task = await tasksApiInstance.getTask(task_gid, { 'opt_fields': "name" });
  const taskName = task.data.name;

  // 2. Check if the task name is an email and set the result in the storyRequestBody
  let storyRequestBody = {
    "data": {
      "text": ""
    }
  };
  if(isEmailText(taskName)) {
    // 2a: The task name is in email format
    // Set the comment message
    storyRequestBody['data']['text'] = `SUCCESS: the task name "${taskName}" is in email format (EX: username@example.com)`
  } else {
    // 2a: The task name is NOT in email format
    // Set the comment message
    storyRequestBody['data']['text'] = `FAIL: the task name "${taskName}" is NOT in email format (EX: username@example.com)`
  }
  
  // 3. Add a comment to the task with the result
  storiesApiInstance.createStoryForTask(storyRequestBody, task_gid);
};

run();

```

11. Test the script locally on your computer by running `node validateTaskName.js`

### C: Replacing the default script

1. Navigate to the project where you setup the rule with a Script Action from section [2: Setting up a Script Action rule](/docs/how-to-write-a-script-actions-script#2-setting-up-a-script-action-rule)
2. Navigate to **Customize** > under the **Edit** section, click on **Rules** > Select the previous rule you created (assuming you did not name the rule, it should be called **When Task is assigned**)
3. Select the **Run script** card > this should open up the script editor view
4. Copy and paste your script from step [B: Developing and testing your script locally on your computer](/docs/how-to-write-a-script-actions-script#b-developing-and-testing-your-script-locally-on-your-computer). **NOTE:** Only copy the contents after:

```javascript
/*
----------------------------------------------------------------------------------------
Write your script below, then COPY and PASTE your script into the script editor
----------------------------------------------------------------------------------------
*/
```

i.e., Copy the following over

```javascript
// Checks if the provided text is in email format
const isEmailText = (text) => {
    const emailRegex = /^[\w\.-]+@[a-zA-Z\d\.-]+\.[a-zA-Z]{2,}$/;
    return emailRegex.test(text);
};

const run = async () => {
  // 1. Get information about the triggered task
  const task = await tasksApiInstance.getTask(task_gid, { 'opt_fields': "name" });
  const taskName = task.data.name;

  // 2. Check if the task name is an email and set the result in the storyRequestBody
  let storyRequestBody = {
    "data": {
      "text": ""
    }
  };
  if(isEmailText(taskName)) {
    // 2a: The task name is in email format
    // Set the comment message
    storyRequestBody['data']['text'] = `SUCCESS: the task name "${taskName}" is in email format (EX: username@example.com)`
  } else {
    // 2a: The task name is NOT in email format
    // Set the comment message
    storyRequestBody['data']['text'] = `FAIL: the task name "${taskName}" is NOT in email format (EX: username@example.com)`
  }
  
  // 3. Add a comment to the task with the result
  storiesApiInstance.createStoryForTask(storyRequestBody, task_gid);
};

run();

```

5. Click on the **Save** button

## 4. Test your script

In section [2: Setting up a Script Action rule](/docs/how-to-write-a-script-actions-script#2-setting-up-a-script-action-rule) we set our rule to trigger **when a task is assigned to someone**. Let's  go ahead and test the following scenarios.

> 🚧 Script Actor
>
> Actions performed by the script are treated as if they were done by the user. Additionally, scripts can do anything the user has access to do.

### Scenario 1: Task name is in email format

Add a new task to the project and give it a name that is an email address (e.g., <user@example.com>) then assign it to a user

* Expected Result = Rule to run and the following comment to be added to the task: `SUCCESS: the task name "user@example.com" is in email format (EX: [username@example.com](mailto:username@example.com))`

<Image align="center" src="https://files.readme.io/a6d37b4-valid_task_name_email_demo.gif" />

### Scenario 2: Task name is NOT in email format

Add a new task to the project and give it a non-email address name (e.g., Test Task) then assign it to a user

* Expected Result = Rule to run and the following comment to be added to the task: `FAIL: the task name "Test Task" is NOT in email format (EX: [username@example.com](mailto:username@example.com))`

<Image align="center" src="https://files.readme.io/d237319-valid_task_name_email_demo_fail.gif" />

### Manually triggering a rule

To further help you test your script action, you can use a **manual trigger** to manually re-execute a rule. To do so, select the **Rule is run manually** trigger when setting up a script action:

<Image align="center" className="border" border={true} src="https://files.readme.io/30f92f493528d001b40f3a6b847771c7960c5e5fe1420c398f9f7c111cbe2e33-Screenshot_2025-02-12_at_1.46.42_PM.png" />

In the above example, after selecting that additional trigger, the script will be set to run when either a **Task is assigned** in that project, or when triggered manually.

Once the rule is saved, right click in the project and select your trigger label under **Run a rule**. In the following example, the trigger name **Example** is shown:

<Image align="center" className="border" border={true} src="https://files.readme.io/27ff58b322458fa282c2a805583f1c14801c20f722ec26d0af7059e59e3428dd-Screenshot_2025-02-12_at_1.34.36_PM.png" />

By re-triggering a rule in this manner, you can manually run a script as needed, such as in situations where you need to re-attempt a failed execution.

If you encounter any errors, please refer to the below section [5. Debugging/Errors/Logging](/docs/how-to-write-a-script-actions-script#5-debuggingerrorslogging) on tips on how you can debug your issue.

## 5. Debugging/Errors/Logging

Script Actions offers a function called `log` which is equivalent to `console.log`that serves as a debugging tool, allowing you to print your script's output to the run history. Furthermore, if your script encounters an error, you can review the run history logs to assist in debugging the issue.

<Image align="center" src="https://files.readme.io/e8a5fdf-logs_in_run_history.png" />

To access your run history logs:

1. Navigate to **Customize** > under the **Edit** section and click on **Rules** > Select your rule
2. Select the **Run script** card > **Run history** tab

> 📘 Log Limit
>
> Logs have a character limit of 5,000 and will be truncated if they exceed this limit.

> 📘 try...catch
>
> Script action scripts are enclosed in their own `try...catch` statement. If your script also contains a try...catch statement, errors may not appear as errors but may instead be [displayed as logs](/docs/how-to-write-a-script-actions-script#scenario-1-logs) in the **"Run history"** tab.

### Scenario 1: Logs

```javascript
async function run() {
    const task = await tasksApiInstance.getTask(task_gid);
    log("task's current name: " + task.data.name);
}

run();

```

<Image align="center" src="https://files.readme.io/a36e10e-scenario_1_log.gif" />

### Scenario 2: Errors

```javascript
async function run() {
    // Provide a fake gid to trigger error
    const task = await tasksApiInstance.getTask("RANDOM_GID");
}
  
run();
  
```

<Image align="center" src="https://files.readme.io/b6e9fd1-scenario_2_error.gif" />

## 6. Next steps

See our [**Script action examples**](/docs/script-actions-examples) page and [**script-actions-examples GitHub**](https://github.com/asana-examples/script-actions-examples) page for more examples and use cases.