The Adaptavist Group LogoDocumentation

Script Listeners

Migrating from ScriptRunner for Jira Server/DC to Cloud? Check out our ScriptRunner Migration to Cloud section.

Before you start

Visit ScriptRunner HQ to see example scripts.

ScriptRunner HQ website

Learn about event-based automating with Script Listeners.

Training videos

Note: Condition script examples

The condition script will be evaluated before your code is executed. In the case where a value other than true is returned then we get a false result, and the code will not execute. The condition is evaluated using the Jira Expression Framework.

You can refer to our Example Restrictions and Validators page for further details.

Warning: Action required!

As a result of Atlassian's Transition to Forge Events and Missing Event Properties, it's important that you review and update any Script Listeners that depend on the missing properties. There is no workaround for retrieving these properties via the Atlassian REST API. Therefore, to ensure your scripts do not break after the transition, they need to be removed from any scripts that use them.

What are Script Listeners?

A listener is an automated procedure or function in ScriptRunner that waits (or listens) for a specific event to occur in Jira and then carries out an action if the event occurs. Listeners sit on your instance and wait for a webhook event to happen before executing the listener script. Webhooks are triggered after an action has occurred in Jira, such as when a space is created or a work item is updated.

Note: Script Listeners that trigger Scripted Fields, and vice versa

Scripted Fields work items are updated after a script is executed, triggering an issue_updated webhook event in Jira. This event is sent to ScriptRunner, but does not cause the script to run again or trigger any associated script listeners configured for work item update events.

Script Listeners that update work items will trigger an issue_updated webhook event in Jira, which is then sent to ScriptRunner. If scripted fields are configured for the updated work items, they execute once, updating the work item and triggering another issue_updated webhook event without requiring any further processing.

How to use Script Listeners

You may want to use a Script Listener to:

  • Populate a space with initial work items when it is created.
  • Post a message to Slack when a work item is created.
  • Store story points of sub-tasks against the parent work item.
CAUTION: Script Listener Infinite Loop Restriction

Previously, it was important to ensure that your scripts did not inadvertently trigger events your script listener was listening for, as this risked causing an infinite loop. However, now self-triggering scripts can no longer execute after 10 runs. This restriction means that if a script creates an event that results in the same script running again, ScriptRunner will count the number of times this occurs and reject the 11th run. If this happens, you will see a log message informing you that Scriptrunner has cut off a self-triggering script loop.

Script Listeners and Post Functions

The crucial difference between Script Listeners and Post Functions is that the latter rely on a transition change, whereas the former depend on an event occurring, which can happen at any time.

Script Listeners give you more control over automated actions than you would get with a Post Function.

For example, whenever there is a Critical level priority work item in a specific space, you want a message to be sent to a Slack channel. If you use a post function to do this, the event will fire only after a transition, not when the work item is edited. Therefore, if the priority of the work item were edited to Critical, the post function would not catch it until after the work item had been transitioned. To achieve this use case, you would use a listener to catch a change in priority when it happens.

Create a Script Listener

  1. Navigate to ScriptRunner → Script Listeners.

    Depending on whether or not you have already created script listeners, you are presented with either a landing screen or a list of the previously created script listeners.

  2. Click Create Script Listener from the initial landing screen if none have been previously created. Or, if you would prefer to make use of our built-in examples, click Add Examples to add two script listener examples to your instance.

    OR

    Click Create Script Listener from the previously created list.

  3. Optional: You can modify or delete any of the script listeners listed. Click Edit or Delete via the Actions ellipsis to select the relevant script listener and delete, or refer to Edit a script listener.

    You will see the Create Script Listener screen, as shown below:

  4. Enter a name for the listener in Script Listener Called.
  5. Choose to Enable Script Listener, or turn off to disable.
  6. Select the event(s) you wish the listener script to trigger on in On These Events, for example, Work Item Updated.
  7. Select the spaces you want the listener to be active for; you can select All Spaces (default) or a number of individually selected spaces per listener.
    CAUTION: Space settings apply only to events related to work items, spaces, work item links, versions, and comments. If you need to filter issuelinks for both the source and destination work items, be sure to include both spaces in the filter.

    The location of the outward link in the work item defines the mapping that is required, for example: If Space A is mapped, and ITEM-1 in Space A is assigned a " blocks " link to another work item, this means ITEM-1 is the outward link that fires the Script Listener. If Space A is mapped, and ITEM-1 in Space A is assigned an " is blocked by " link, this means ITEM-1 is the inward link, which would not fire the Script Listener since it is not mapped.

  8. Enter a condition on which the code will run. Note that the ScriptRunner Add-on user always runs the condition , but you can choose who runs the script.

    The condition script will be evaluated before your code is executed. If a value other than true is returned, the code will not execute. The condition is evaluated using the Jira Expression Framework. Event-specific Script Context parameters and variables are listed here for each event. The work item property is not an available Context variable for work item link created events.

  9. Choose from either ScriptRunner Add-On User or Current User as the user you wish to run the listener from the Run code as: drop-down options. Script Listeners can make requests to Jira using either user.
    Note: When using the Initiating User, any action resulting from the function is registered as performed by them. For example, if a work item is commented on, the comment comes from the Initiating User rather than the ScriptRunner Add-on User, who may have nothing to do with the work item/space affected. Permissions are considered when executing actions. The user selected in the Run code as: field must have the required permissions to perform the specified action. Typically, the ScriptRunner Add-on User has space admin permissions; however, this can be restricted. The Initiating User may have higher permissions than the ScriptRunner Add-on User.
  10. Write your script in the code editor. This code is executed when the Evaluate Condition is true.
    Tip: You also have the option to click Load and reuse a script you previously saved in Script Manager. Details on how to do this can be found in Reuse scripts in the UI.

    OR

    Alternatively, you can click the Example scripts button to view a list of example scripts related to this feature.

    So, rather than writing your own script, you can reuse one of the many examples provided, as follows:

    1. Choose an example script from the list provided, and the code automatically appears. You also have the option to search for a particular script.
    2. Click Copy Code and then Close.
    3. Paste the copied code in the code editor.
  11. Optional: Click Script context to view an information modal highlighting parameters/code variables.
    Note: Script context

    The Script Context is a set of parameters/code variables automatically available in your script to provide contextual data for the script listeners. The parameters and variables in the Script Context are different for each Listener Event. Event-specific Script Context parameters and variables are listed here for each event.

    Common parameters in the Script Context for all the events are:

    • baseUrl - Base url to make API requests against. This is the URL used for relative request paths e.g. if you make a request to /rest/api/2/issue we use the baseUrl to create a full request path.
    • logger - Logger to use for debugging purposes. Check the methods available org.slf4j.Logger
    • timestamp - The timestamp of the event in milliseconds e.g. 1491562297883
    • webhookEvent - The webhook event type. Atlassian Connect Webhook Documentation

    For further information on referencing Script Context values, refer to Example Script Variables.

  12. Click Save. You can test your script using the Run Now button, which will execute the script and return the results.

Edit a Script Listener

  1. Navigate to ScriptRunner > Script Listeners.
    A list of all previously created listeners is shown.

    You can check which event triggers have been chosen for each listener by clicking the relevant Event from the list.

  2. Click Edit from the Action ellipsis on the listener you wish to edit.

    Similarly, you can also choose the listener you wish to delete by clicking Delete from the Action ellipsis.

  3. Edit the fields, as required, from within the Edit Script Listener screen.
  4. Click Save when all changes have been made.

Script Listener behavior change on Forge events

Atlassian is retiring Connect, so ScriptRunner for Jira Cloud is moving to Forge. With that move, the script context variables in your Script Listeners, Perform Actions, and background syncing Scripted Fields such as issue, user, and changelog, are changing too. These variables now get their data from Atlassian's Forge events, which contain much less data than the events from the previous Connect platform.

Your scripts will continue to work without needing a rewrite. The variables keep their names and structure. When your script reads a property that is no longer included, ScriptRunner fetches it from Jira for you.

Note: What's new for your scripts?

A line that only reads a value, such as issue.fields.priority, can now trigger an API call to Jira. If Jira rate-limits that call, ScriptRunner waits and retries once. If that second attempt also fails, the script stops with an error. This failure mode did not occur on Connect.

Script context changes

Script context variables such as issue, user, and changelog now derive their values from Atlassian Forge events instead of Connect. Because Forge events include less data, ScriptRunner may need to fetch missing values from Jira when your script accesses them.

In Atlassian's Forge platform, only a few properties are readily available, such as issue.key, issue.fields.summary, and a user's accountId. Others, such as issue.fields.priority, a custom field, or user.displayName, arrive when your script first reads them. Some properties are no longer available, and ScriptRunner cannot fetch them. You will need to change any scripts that use those properties; for details, refer to Atlassian's Transition to Forge Events and Missing Event Properties.

Why ScriptRunner fetches your data

When a property is missing from the Forge event, the only place to retrieve it is the Jira REST API. Previously, Atlassian included this data in the event, and ScriptRunner exposed it directly to your scripts, so you did not need additional API calls.

As we move to Forge, ScriptRunner fills in missing data only when your script first reads it. This on-demand fetching avoids unnecessary REST calls for properties your scripts never use and helps reduce load on Atlassian's systems.

Details of ScriptRunner fetches

ScriptRunner fetches each missing property at most once per script run, no matter how many times your script reads it. Each listener run is independent, so two listeners on the same event each make their own calls.
When your script readsScriptRunner fetches
The whole issue or user variable, for example when you log it, turn it into JSON, send it in a request, or return it from the script.All missing properties, including those your script never uses.
A field of issue that is not included, such as description, priority, labels, or a custom field.The work item.
The parent's summary, status, priority, or work type.The parent work item.
A user's displayName, avatarUrls, timeZone, or active.The user, once per person, unless the user was already included with a work item that ScriptRunner fetched earlier. When Jira makes the change itself, shown as Anonymous user, there is no user to fetch, and these values remain null.
fromString or toString on a changelog item, where it is missing.The changelog entry.
Space, work type, or version details on those events.The space, work type, or version.
transitionInput.from_status in a workflow post-function.The status.
To see what a run fetched, follow these steps:
  1. Open Script Listeners.
  2. Click Run in the listener's History column.
  3. Open the Logs tab.
Each REST call made while your script runs appears in its log, including the calls ScriptRunner makes for you:
2026-09-28 12:24:52.445 INFO - Serializing object into 'interface java.util.Map' 2026-09-28 12:24:52.461 INFO - GET /rest/api/2/issue/BACKFILL-2 asObject Request Duration: 1360ms
In the example below, you can see the Logs tab of a listener run where the GET line is the fetch ScriptRunner made to fill in issue.fields.priority.

A user fetch appears as GET /rest/api/2/user?accountId= followed by the account ID. Any request that your script did not make itself is a fetch that ScriptRunner used to fill in the Script Context. Fetches that occur after your script finishes, for example, while ScriptRunner serializes a returned issue, do not appear in the log.

The fetched value is the work item as it exists when your script reads it. Previously, issue held the work item as it was when the event occurred. If someone changes the work item again in between, your script now sees the newer value.

What happens when a fetch fails

Atlassian limits how many API calls ScriptRunner can make to your site in a given period. Every call counts toward that limit: your scripts' own calls, these fetches, and ScriptRunner's internal checks, such as listener conditions. Bulk edits and imports fire one event per work item, so calls arrive in bursts, which is when your site is most likely to reach its limit.

When Jira rate-limits a call, ScriptRunner waits as long as Jira asks and tries once more. The log shows a line like this:
GET request to /rest/api/2/issue/TEST-1 returned an error code: 429, retrying in 1s...
Jira answersWhat your script gets
Not found (HTTP 404), or ScriptRunner may not see the data (HTTP 401 or 403) null, with two warnings in the log. The run still succeeds.
Rate limited (HTTP 429) again after that retry, a server error, or no answer The script stops with an error.
For a work item deleted before the script read it, the log showed:
2026-09-28 12:32:17.347 WARN - GET request to /rest/api/2/issue/BACKFILL-59 returned an error code: status: 404 - body: {errorMessages=[Issue does not exist or you do not have permission to see it.], errors={}} 2026-09-28 12:32:17.349 WARN - Enrichment of MappedIssueFieldsProperty via GET /rest/api/2/issue/{issueIdOrKey} found nothing (HTTP 404): the entity does not exist or is not visible to the app user, the field stays unset. 2026-09-28 12:32:17.350 INFO - Priority: nul
When the script stops, its log shows this error:
Could not load the event data missing from the Forge payload (MappedIssueFieldsProperty via GET /rest/api/2/issue/{issueIdOrKey}): the Atlassian API responded with HTTP 429. The script was unable to continue due to an incomplete event
A property that is empty because Jira was busy looks the same to your script as a property that is genuinely empty in Jira. If the script continued, it could follow the wrong branch and still report success. For this reason, ScriptRunner does not rerun the script after this error.

What changed for Workflow Perform Actions

Workflow Perform Actions switched to Forge events on September 29, 2026, on every site simultaneously. They no longer receive the Connect version of the event.

A Perform Actions issue variable now behaves like a listener’s. It holds the key and nine fields: summary, work type, status, space, creator, reporter, assignee, created, and updated. ScriptRunner fetches any other field when your script reads it, as described above.

Whose permissions apply. ScriptRunner fetches data as the user the Perform Action runs as. A Perform Action set to run as the Initiating User fetches with that user's permissions. If that user cannot see the data, the script gets null, with two warnings in the log.

Status names in transitionInput.transitionInput.from_status and transitionInput.to_status still hold status names. The new status comes with the event. ScriptRunner looks up the previous status when your script first reads it. That lookup does not need Jira administrator rights, so it works for any user the Perform Action runs as. If the lookup fails, the Perform Action stops with an error.

Before this fix, a Perform Action running as a non–Jira administrator could see a status ID, such as 10001, instead of the name. A condition such as transitionInput.to_status == 'Done' then evaluated to false, so the Perform Action skipped its work.

Conditions. A Perform Action's condition can read fields that require a fetch. If that fetch fails, the Perform Action now stops with an error. Previously, the condition evaluated as false and the Perform Action did nothing without reporting an error.

Clone Issue. The built-in Clone Issue Perform Action reads the work item once and copies it as it exists at that moment. The copy includes changes that earlier post-functions on the same transition made. Its additional code sees the same values.

When a Perform Action fails. A Perform Action runs after the transition, so a failed Perform Action does not undo the transition. Only the Perform Action's own work is missing, and ScriptRunner does not run it again.

Listeners don't run for restricted comments

If a listener uses the Comment created or Comment updated event, it might not run when the comment is restricted to a group or space role. It still runs as expected for comments that everyone can see.

Why this happens

Jira only sends a comment event to an app if the app can see that comment. ScriptRunner follows the same comment visibility rules as any other Jira user. If it isn't in the group or space role the comment is restricted to, Jira sends no event, and ScriptRunner never knows the comment was added or edited. Nothing appears in Execution History, because the listener was never triggered.

Note: Admin permissions don't override comment visibility in Jira Cloud. Even a site admin can't see a comment restricted to a group or role they don't belong to, and the same applies to ScriptRunner.

Atlassian sometimes tightens how webhooks are sent for restricted content to meet data privacy standards. So a listener that previously ran for restricted comments can stop running even though you haven't changed anything. Also, moving ScriptRunner from Connect to Forge can change the app user's internal ID so role memberships may no longer apply.

How to fix it

  1. Find the group or project role your restricted comments use, such as Administrators or Developers.
  2. Go to Project settings > People in each affected space, and add the ScriptRunner app user to that project role.
  3. If the restriction uses a group, add the ScriptRunner app user to that group.
  4. Add a restricted comment to test, and check that the run shows up in the listener's Execution History.
Tip: Tip: Changing Run code as to the Initiating User doesn't fix this. Jira decides whether to send the event before your script runs.

How to write scripts that handle failed fetches

Fetch the data yourself when the script must decide what happens

Your own REST call gives your script the HTTP status, so the script can skip the run, log a clear message, or take another path. This listener reads the priority and skips the run if Jira does not return it:
def response = get("/rest/api/2/issue/${issue.key}") .queryString("fields", "priority") .asObject(Map) if (response.status != 200) { logger.warn("Could not read ${issue.key} (HTTP ${response.status}), skipping this run") return } logger.info("Priority: ${response.body.fields.priority?.name}")
Read everything the script needs from that response. If the script also reads a missing property from issue, ScriptRunner fetches the work item a second time.

Do not retry by reading the property again

After a failed fetch, ScriptRunner does not fetch the same data again in that run. A script that catches the error and reads the property again gets null:
def priority try { priority = issue.fields.priority?.name } catch (Exception e) { priority = issue.fields.priority?.name // null: ScriptRunner does not fetch again in this run 
Check changelog values before you branch on them

If a decision depends on fromString or toString, fetch the changelog yourself and check the response status.

Keep the number of calls down

  • Use the properties that are readily available when they are enough.

  • Read the properties you need, instead of logging or serialising the whole issue or user.

  • Limit each listener to the spaces and events it needs.

Check Execution History after bulk changes

After a bulk edit or import, open Execution History from the ScriptRunner menu and check for failed Script Listener and Perform Action runs. The longest interval is 72 hours, so review the history within three days.

Search documentation

Start typing to search the docs.