Exalate was built around flexibility, and that flexibility is what makes it a strong fit for advanced integration use cases like synchronizing Insight (Assets) objects between Jira instances.
In this article, we’ll walk you through how Exalate’s Groovy scripting engine can be used to synchronize Insight objects. You’ll learn:
- How to retrieve object attributes, including references
- How to search for objects using IQL (Insight Query Language)
- How to create new objects on the destination side
Whether you’re syncing asset data between internal teams or sharing configuration items with external partners, this guide covers the scripting approach step by step.

The Scenario
Team Blue uses Jira Service Management to manage all the details for getting Game of Thrones out the door. Team Blue works with Team Green for all costume-related requests. Team Green is an external team using Jira to manage requests from multiple customers.
Since each customer manages information differently, a mapping is required between the two environments. Both companies use Insight Asset Management to track their assets.
Note: This is a purely fictional scenario.
Team Blue
- Jira Service Management with one service desk project to track all the details of the Game of Thrones series
- Insight asset management
- Top-level object: GOT House
- One child: Character
The character has one attribute, “House.”

The work item has an Insight object custom field that allows selection from a drop-down.
Team Green
- One Jira Software project
- One Insight Object Schema, “Directory”
- One Object type, “Person”
Next to standard fields, one extra field has been added (“ExternalRef”), which is used to track the source of the person.
And It Works!
Here is a video to demonstrate how the integration works:
What Are Insight Objects in Jira?
Insight (now called Assets in Jira Service Management Cloud) is a built-in asset management feature that lets you create, store, and link configuration items or assets directly inside Jira. Objects can represent anything: hardware, software, employees, contracts, or custom entities.
Each object belongs to an object type (for example, “Laptop” or “Employee”), lives inside an object schema, and has attributes like serial number, owner, or status. Objects can also reference other objects, creating relationships between assets.
When you sync Insight objects between Jira instances using Exalate, you’re essentially reading these attributes on one side, passing them through the replica (Exalate’s data payload), and applying them on the other side using Groovy scripts.
Technical Details
Background Information
Most of the background information has been extracted from the Groovy Script Examples.
The key point is that Exalate allows you to instantiate any Jira Service, even when it is delivered by an add-on such as Insight.
An example of how you can access Tempo Worklog attributes is available here. It boils down to:
// get the class of the service you would like to instantiate
def IOFacadeClass = ComponentAccessor.pluginAccessor.classLoader.findClass
("com.riadalabs.jira.plugins.insight.channel.external.api.facade.ObjectFacade")
// get the service
def IOFacade = ComponentAccessor.getOSGiComponentInstanceOfType(IOFacadeClass)Code language: JavaScript (javascript)Overview of the Implementation
The approach for configuring an integration is always the same:
- On the source side (Blue), ensure that all required information is sent.
- On the destination side (Green), apply the information.
For this use case:
On Blue: Send the character name, character key, house name, and house key to the other side. The character key is used to find the character in the directory by querying the ExternalRef.
On Green:
- Try to find the character using the character key.
- If not found, create a new person.
- Assign the target person to the custom field.
Details of the Implementation
Accessing the Insight App Services
// do not forget to import the ComponentAccessor
import com.atlassian.jira.component.ComponentAccessor
// Get the Insight Object Facade
def IOFacadeClass = ComponentAccessor.pluginAccessor.classLoader.findClass("com.riadalabs.jira.plugins.insight.channel.external.api.facade.ObjectFacade")
def IOFacade = ComponentAccessor.getOSGiComponentInstanceOfType(IOFacadeClass)
// Get the Insight Query Language for doing searches
def IQLFacadeClass = ComponentAccessor.pluginAccessor.classLoader.findClass("com.riadalabs.jira.plugins.insight.channel.external.api.facade.IQLFacade")
def IQLFacade = ComponentAccessor.getOSGiComponentInstanceOfType(IQLFacadeClass)
// Get Insight Object Type Facade from plugin accessor
Class IOTypeClass = ComponentAccessor.getPluginAccessor().getClassLoader().findClass("com.riadalabs.jira.plugins.insight.channel.external.api.facade.ObjectTypeFacade");
def IOType = ComponentAccessor.getOSGiComponentInstanceOfType(IOTypeClass);
// Get Insight Object Attribute Facade from plugin accessor
Class IOTypeAttClass = ComponentAccessor.getPluginAccessor().getClassLoader().findClass("com.riadalabs.jira.plugins.insight.channel.external.api.facade.ObjectTypeAttributeFacade");
def IOTypeAtt = ComponentAccessor.getOSGiComponentInstanceOfType(IOTypeAttClass);
// Get Insight Object Attribute Bean Factory
Class IOAttBeanClass = ComponentAccessor.getPluginAccessor().getClassLoader().findClass("com.riadalabs.jira.plugins.insight.services.model.factory.ObjectAttributeBeanFactory");
def IOAttBean = ComponentAccessor.getOSGiComponentInstanceOfType(IOAttBeanClass);Code language: JavaScript (javascript)On Source: Extract Attributes from a Specific Object and Add to the Replica
// This code section goes into your outgoing sync processor of the connection
// Character is the Insight Object custom field, and we assume that the character has been provided
def CHARACTERNAME=824 // this id can be looked up in the Object Schema configuration
def CHARACTERHOUSE=827
def character = issue.customFields.Character?.value?.get(0)
def characterName = insightObjectFacade.loadObjectAttributeBean(character.getId(), CHARACTERNAME).getObjectAttributeValueBeans()[0];
// dereference the house attribute
def characterHouse = insightObjectFacade.loadObjectAttributeBean(character.getId(),CHARACTERHOUSE).getObjectAttributeValueBeans()[0]
def refHouse = insightObjectFacade.loadObjectBean(characterHouse.getValue() as Integer) // characterHouse.value is a Long, while an Integer is expected
// add the attributes to the replica.customKeys such that these values are included in the message from Blue to Green
replica.customKeys.characterName = character?.name
replica.customKeys.characterKey = character?.objectKey
replica.customKeys.houseName = refHouse?.name
replica.customKeys.houseKey = refHouse?.objectKeyCode language: JavaScript (javascript)On Target: Search for the Directory Entry Using the Character Key
Note: Searching and creating Insight objects requires an authenticated environment, which can be set up as documented here.
// some constants
def DIRECTORYSCHEMA=1
def PERSONOBJECTTYPE=2
def PERSONNAMEATTRIBUTE=8
def PERSONCOMPANYATTRIBUTE=11
def PERSONEXTREFATTRIBUTE=12
// this goes in the incoming processor on Green
def authContext = ComponentAccessor.getJiraAuthenticationContext()
def currentUser = authContext.getLoggedInUser()
def userKeyToSet = "admin"
def targetPerson
...
try {
// ensure that the processor is run under a user permitted to search / create Insight objects
// The try/catch will ensure that the user is returned to the current user
authContext.setLoggedInUser(ComponentAccessor.getUserManager().getUserByKey(userKeyToSet));
// Search for the person using an IQL which looks like 'ExternalRef in ("CUS-12345")'
def iqlQuery = "\"ExternalRef\" IN (\"${replica.customKeys.characterKey}\")"
def persons = IQLFacade.findObjects(DIRECTORYSCHEMA, iqlQuery)
if (persons[0] == null) {
// create the person
...
} else {
targetPerson = persons[0]
}
} finally {
authContext.setLoggedInUser(currentUser);
}Code language: PHP (php)On Target: Create the Object If Not Found
if (persons[0] == null) {
// found no record, so let's add it
def IOTypePerson = IOType.loadObjectTypeBean(PERSONOBJECTTYPE);
/* Create a new person object */
targetPerson = IOTypePerson.createMutableObjectBean();
/* Set up the attribute list */
def IOAttBeans = new ArrayList();
/* Set the name of the person */
def nameBean = IOTypeAtt.loadObjectTypeAttributeBean(PERSONNAMEATTRIBUTE);
IOAttBeans.add(IOAttBean.createObjectAttributeBeanForObject(targetPerson,
nameBean, replica.customKeys.characterName));
/* Set the company of the person */
def companyBean = IOTypeAtt.loadObjectTypeAttributeBean(PERSONCOMPANYATTRIBUTE);
IOAttBeans.add(IOAttBean.createObjectAttributeBeanForObject(targetPerson,
companyBean, replica.customKeys.houseName));
/* Set the external reference of the customer */
def extRefBean = IOTypeAtt.loadObjectTypeAttributeBean(PERSONEXTREFATTRIBUTE);
IOAttBeans.add(IOAttBean.createObjectAttributeBeanForObject(targetPerson,
extRefBean, replica.customKeys.characterKey));
/* Set all object attributes to the object */
targetPerson.setObjectAttributeBeans(IOAttBeans);
/* Store the object into Insight. The targetPerson will be updated with a unique ID */
try {
targetPerson = IOFacade.storeObjectBean(targetPerson);
log.warn("targetPerson: " + targetPerson);
} catch (Exception e) {
log.warn("Could not create object due to: " + e.getMessage());
}
} else {
targetPerson = persons[0]
}Code language: PHP (php)On Target: Apply the Found or Created Person to the Custom Field
// The customField expects a collection
issue.customFields.Person.value = [targetPerson]Code language: PHP (php)
Exalate Features That Help with Insight Object Sync
While the scripting above handles the Insight-specific logic, Exalate provides several features that make the overall process smoother:
- Groovy scripting engine: Full control over how Insight attributes are read, mapped, and applied. If you can access it via the Jira API, Exalate can sync it.
- Aida (AI-assisted configuration): If you’re unsure how to structure your sync scripts, Aida can help generate and troubleshoot Groovy scripts for Insight object sync scenarios.
- Test Run: Validate your Insight sync scripts against real data before deploying to production. This is especially useful for complex object creation logic, where a mistake could create duplicate or incorrect assets.
- Script versioning: Every time you publish a script change, Exalate saves a version. You can roll back to a previous version if an update breaks your Insight sync.
- Unified console: Manage all your Jira-to-Jira connections (and connections to ServiceNow, Azure DevOps, Zendesk, Salesforce, and more) from a single interface at exalate.app.
- Bulk Sync: Sync existing work items in bulk when setting up a new Insight object sync, so you don’t have to wait for updates to trigger individually.
Additional Functions That Could Be Implemented
- If the character changes the name, update the corresponding person.
- If the character changes the house or the house changes the name, update the corresponding company name.
- If the character is deleted, mark the person as deleted on the other side.
- Sync object references (parent-child relationships) by including reference keys in the replica.
- Handle multi-value Insight fields by iterating over the collection in the outgoing script.
Recommended Reading:
- How to Sync Comment Threads and User Mentions in Comments between Jira and Salesforce
- How to Sync Tempo Worklogs Between Two Jira Cloud Instances
- Advanced Integration Use Cases
- How to Append the Jira Issue Key to a Private Comment in Zendesk When the Issue is Closed
- How to Sync Issue Types and Select Lists (Dropdown) Between Jira On-premise and Jira Cloud



