The CreatorCon Call for Content is officially open! Get started here.

Mike-Thompson
ServiceNow Employee
ServiceNow Employee

Looking to make your ServiceNow Recommended Actions more dynamic and context-aware? Scripted resource generators give developers the power to return tailored recommendations by executing custom Script Includes. By implementing the ScriptingGeneratorFactory template, you can fully control the logic behind what gets suggested to users—whether it's based on record data, user roles, or any other business logic. You'll learn how to build a scripted resource generator from scratch, integrate it into a context rule, and enhance your RA experience with intelligent, data-driven recommendations.

 

In this guide, we’re all about helping users manage customer promotions more easily. You’ll learn how to show the current promotions a customer has and suggest better deals they might be interested in. By the end, you’ll be able to configure your own scripted Recommended Action, and you can also install the update set to review a working scoped app for reference.

Note: This guide assumes you’re familiar with Recommended Actions and that your instance is already set up to use them.

 

Create a Context

Let's start off by first creating a context for an individual table, in this case we will be using the Accounts table. Contexts store information including the recommended actions that agents can use and the rules that determine when those actions are available.

  1. Navigate to All > Recommended Actions > Contexts and select New on the contexts list.
  2. Fill out the Form:
    • Name: Account Context
    • Table: Account [customer_account]
    • Description: This context allows users to see recommendations for accounts when certain rules are met
  3. Save the record

Screenshot 2025-07-10 at 10.16.40 AM.png

 

Create a Context Rule

Next let's create a rule for a context that determines when recommended actions are made available to agents. In this case i only want to show for Accounts that are marked as customers.

  1. Within your context record, in the Rules related list, click New.
  2. Fill out the Form:
    • Name: Customer Accounts
    • Description: All valid recommendations for accounts where customer is true
    • Condition: Customer | is | true
  3. Save the record

Screenshot 2025-07-10 at 10.24.32 AM.png

 

Now before we setup our Recommendations within the rule, we need to create all the underlying records to make things easier. So lets start with creating our various Script Includes (Helper & Script Generators) that will be used later when we create a Scripted Resource Generator for our Recommendation.

 

Create a 'Helper' Script Include

While you can write all your logic in the 'Script Generator' script include (which will be covered below), its best to create a 'helper' script include that will contain various functions.

  1. Navigate to All > System Definitions > Script Includes and select New
  2. Fill out the Form:
    • Name: CommunityGuideRecommendationsHelper
  3. Save the record

Screenshot 2025-07-10 at 11.02.31 AM.png

 

Next lets update our Script to include a function called getUpcomingPromotions that will get upcoming promotions:

var CommunityGuideRecommendationsHelper = Class.create();
CommunityGuideRecommendationsHelper.prototype = {
    initialize: function() {},

    /**
     * Retrieves up to 5 upcoming promotions sorted by most recently updated.
     * Returns an array containing only the Sys IDs of the matching promotions.
     */
    getUpcomingPromotions: function(accountGR) {
        if (accountGR) {
            var upcomingPromotionSysIds = [];
            var upcomingEQ = 'status=upcoming';
            var promotionsGR = new GlideRecord('x_snc_ra_community_promotion');
            promotionsGR.addEncodedQuery(upcomingEQ);
            promotionsGR.orderByDesc('sys_updated_on');
            promotionsGR.setLimit(5);
            promotionsGR.query();
            while (promotionsGR.next()) {
                upcomingPromotionSysIds.push(promotionsGR.getUniqueValue());
            }
            return upcomingPromotionSysIds;
        }
        return null;
    },

    type: 'CommunityGuideRecommendationsHelper'
};

Now that we have our Helper script include created, we can now create a Script Generator that will call our function we created above.

 

Create a 'Script Generator' Script Include

This is the Script Include that will get called when you create the Scripted Resource Generator later and is an implementation of the ScriptingGeneratorFactory template that is talked about in the ServiceNow documentation.

  1. Navigate to All > System Definitions > Script Includes and select New
  2. Fill out the Form:
    • Name: UpcomingPromotionsScriptGenerator
    • Description: Implements extension point sn_nb_action.ScriptingGeneratorFactory
      Use this interface to implement a script include for a generator using Scripting resource generator type
    • Script
      var UpcomingPromotionsScriptGenerator = Class.create();
      UpcomingPromotionsScriptGenerator.prototype = Object.extendsObject(sn_nb_action.ScriptingGeneratorHandlerBase, {
          category: 'ra_scripting_generator', // DO NOT REMOVE THIS LINE!
      
          getId: function() {
              //Update this with the full API Name of your Script Include
              return "x_snc_ra_community.UpcomingPromotionsScriptGenerator";
          },
      
          getOutputSchema: function() {
              var schema = [{
                  'name': 'predictedRecord',
                  'label': 'Predicted Record',
                  'type': 'reference',
                  'referenceTable': 'x_snc_ra_community_promotion' // Update Reference Table
              }];
              return {
                  'status': 'success',
                  'schema': schema,
              };
          },
      
          getOutputs: function(param) {
              try {
                  var recommendationsHelper = new x_snc_ra_community.CommunityGuideRecommendationsHelper(); //Update with your Helper Script Include
                  var upcomingPromotionsSysIds = recommendationsHelper.getUpcomingPromotions(param.contextRecord); //Update with your Function
                  var response = {
                      'status': 'success',
                      outputs: []
                  };
                  upcomingPromotionsSysIds.forEach(function(upcomingPromotionsSysId) {
                      response.outputs.push({
                          predictedRecord: upcomingPromotionsSysId
                      });
                  });
                  return response;
              } catch (e) {
                  return {
                      'status': 'error',
                      'errorCode': 40001,
                      'errorMessage': 'Failed to get recommendations for Upcoming Promotion records' // this will be logged
                  };
              }
          },
      
          type: 'UpcomingPromotionsScriptGenerator'
      });

      Note: If you are copying the above script as a template, make sure to update the Class name to match your script include name (normally the first 2 lines and type found at the end).

Linking your 'Script Generator' to ScriptingGeneratorFactory

This is the most important part to get your Scripted Resource Generator to work!! For a long time i was struggling to get my recommended actions to work, after running script debugger I walked through various calls and found that a record on the Extensions Instances (sys_extension_instance) needed to be created to link my 'Script Generator' to ScriptingGeneratorFactory.

  1. Navigate to All > Type 'sys_extension_instance.LIST' and select New
  2. Fill out the Form:
    • Point: sn_nb_action.ScriptingGeneratorFactory
    • Class: UpcomingPromotionsScriptGenerator (Script Include created above)

Screenshot 2025-07-10 at 1.44.23 PM.png

 

Note: You will need to create an Extension Instance record for each Script Generator you create.

 

Create Resource Generator

Next let's create our Resource Generator which we will reference in our recommended action later.

  1. Navigate to All > Recommended Actions > Resource Generators and select New
  2. Fill out the Form:
    • Name: Upcoming Promotions Resource Generator
    • Context: Account Context (Reference to Context we created above)
    • Generator Type: Scripting
  3. Click Save
  4. Once saved, you will see a section called Generator input where you will select the script include 'UpcomingPromotionsScriptGenerator' we created above.
  5. Click Save

Screenshot 2025-07-10 at 2.06.54 PM.png

 

Create Guidance

Now lets work on creating a Guidance which is how cards appear in the contextual side panel in a workspace.

  1. Navigate to All > Recommended Actions > Action Types > Guidances and select New
  2. Fill out the form:
    • Name: Upcoming Promotions
    • Description: View details of upcoming promotions
    • Guidance Input
      Label Type Reference Order Is form field
      Promotion Reference Promotion 100 false
      Account Reference Account 100 false
  3. Save the form, as we will now update the Preview Experience (since we can now reference the above inputs.
  4. Click on the Preview Experience Tab and Set the Title, Fields To Display, Message (optional) and then save.

Screenshot 2025-07-10 at 3.08.02 PM.png

 

Create Recommendation

We are on the home stretch and all that is left is to create the recommendation which ties everything together.

  1. Navigate to All > Recommended Actions > Contexts and select the context we created.
  2. Navigate to the rule we created in the Rules related list.
  3. Click New in the Recommendations related list and when prompted select the 'A specific action to take or information to review' option.
  4. Fill out the form:
    • Name: Upcoming Promotions
    • Action: Upcoming Promotions (click the magnifying glass, in Document select the guidance we created above)
    • Resource generator: Upcoming Promotions Resource Generator
    • Recommendation hint: Upcoming Promotions
  5. Click Save (you may have noticed that when setting the action and resource generator, a field info message lets you know you will need to save in order to set inputs and such)
  6. Once saved, you should now see some Action inputs that need to be set via the Pill Picker.
    • Account: Click the Pill picker icon and Select 'Context: Account' reference
    • Promotion: Click the Pill picker icon and you will see an option for Resource generator, click the > icon to select our Predicted Record: Promotion reference.(Note: if you do not see the > icon than you missed a step above, such as creating the extension instance record).

Screenshot 2025-07-10 at 3.10.44 PM.png

 

 

Let's head over to the CSM/FSM Configurable Workspace -> List -> Customer -> Accounts and open up any account record. Open Recommended Actions in the side panel, and you should now see Upcoming Promotions!!!

Screenshot 2025-07-10 at 3.13.09 PM.png

 

 

BONUS Content

While I could wrap up this guide here, I thought it’d be more valuable—and a bit more fun—to take things a step further with a few cool enhancements to what we’ve already built. These additions include creating a Script Generator Script Include that accepts a reference to a promotion record and incorporates a rating scale. We’ll also add an Action to the recommended action that takes user input and triggers a subflow to create a new record.

 

I won’t walk through every step like before, but I’ll share key code snippets and show you what the final files look like so you can follow along and adapt as needed.

To make things even easier, you’ll find a complete Update Set containing everything we’ve covered included at the end. 

 

Now let’s take a look at these upgrades in action. This time, I’m showcasing active promotions that include a rating scale and aren’t yet tied to an account. You’ll also see how to apply a promotion by setting the desired start date, giving users full control over when it begins.

 

Here is our 'Script Generator called ActivePromotionsScriptGenerator.  You can see in the getOutputSchema we have added a string type called scale, which we will be able to see in the pill picker when setting up a recommendation.

var ActivePromotionsScriptGenerator = Class.create();
ActivePromotionsScriptGenerator.prototype = Object.extendsObject(sn_nb_action.ScriptingGeneratorHandlerBase, {
    category: 'ra_scripting_generator', // DO NOT REMOVE THIS LINE!

    getId: function() {
        //Update this with the full API Name of your Script Include
        return "x_snc_ra_community.ActivePromotionsScriptGenerator";
    },

    getOutputSchema: function() {
        var schema = [{
                'name': 'predictedRecord',
                'label': 'Predicted Record',
                'type': 'reference',
                'referenceTable': 'x_snc_ra_community_promotion' // Update Reference Table
            },
            /* 
             * Adding a 'Rating Scale' field to allow users to rate or categorize the promotion.
             * This will be included as a string value in the generated script.
             */
            {
                'name': 'scale',
                'label': 'Rating Scale',
                'type': 'string'
            }
        ];
        return {
            'status': 'success',
            'schema': schema,
        };
    },

    getOutputs: function(param) {
        try {
            var recommendationsHelper = new x_snc_ra_community.CommunityGuideRecommendationsHelper(); //Update with your Helper Script Include
            var activePromotions = recommendationsHelper.getActivePromotions(param.contextRecord); //Update with your Function
            var response = {
                'status': 'success',
                outputs: []
            };
            /*
             * Loop through each active promotion and add its data to the response outputs.
             * Each activePromotion object contains:
             * - sysid: The unique identifier of the promotion.
             * - scale: The rating scale associated with the promotion.
             *
             * The response.outputs array follows a predefined schema, where each entry
             * includes the predictedRecord (promotion sysid) and its scale.
             */
            activePromotions.forEach(function(activePromotion) {
                response.outputs.push({
                    predictedRecord: activePromotion.sysid,
                    scale: activePromotion.scale
                });
            });
            return response;
        } catch (e) {
            return {
                'status': 'error',
                'errorCode': 40001,
                'errorMessage': 'Failed to get recommendations for Active Promotion records' // this will be logged
            };
        }
    },

    type: 'ActivePromotionsScriptGenerator'
});

Here is the function that was added to our 'Helper' script include

getActivePromotions: function(accountGR) {
        if (accountGR) {
            var livePromotion = [];
            var liveEQ = 'status=live';
            var livePromotionsGR = new GlideRecord('x_snc_ra_community_promotion');
            livePromotionsGR.addEncodedQuery(liveEQ);
            livePromotionsGR.orderByDesc('sys_updated_on');
            livePromotionsGR.query();
            while (livePromotionsGR.next()) {
                var appliedPromotionsEQ = 'customer_account=' + accountGR.getUniqueValue() + '^x_snc_ra_community_promotion=' + livePromotionsGR.getUniqueValue();
                var accountCurrentPromotionsGR = new GlideRecord('x_snc_ra_community_m2m_customer_acc_x_snc_ra_com');
                accountCurrentPromotionsGR.addEncodedQuery(appliedPromotionsEQ);
                accountCurrentPromotionsGR.query();
                if (!accountCurrentPromotionsGR.next()) {
					//randomly assign a rating of Good, Better, Best for Demo Purposes
					var scale = ["Good", "Better", "Best"];
					var randomIndex = Math.floor(Math.random() * scale.length);
                    livePromotion.push({'sysid': livePromotionsGR.getUniqueValue(), 'scale': scale[randomIndex]});
                }
            }
            return livePromotion;
        }
        return null;
    },

 

Now before I show the Recommendation, I want to show the Guidance created and talk about some new changes made compared to before.

 

I have added a few extras to the Guidance Input, one that will be set later and holds the rating scale that was returned from our script and the other being the Start Promotion On which the user will set when performing the apply promotion action. So how do we get that input to display?? We do this by setting the Is form field to true.

Screenshot 2025-07-11 at 11.06.04 AM.png

 

The Detail Experience is what will show when a Guidance Action is configured. This is also where the date input that we created above will show along with our Guidance Message.

Screenshot 2025-07-11 at 11.06.52 AM.png

 

Here is an overview of what a Guidance Action looks like. We begin by defining the labels for the buttons that users will see and interact with. Next, we specify the type of behavior the action will perform, such as responding to a single click, opening in the side panel, or launching to a sub-tab. After that, we configure the automation by linking it to a subflow. Once the subflow is connected, you can view and configure its input parameters to customize how the action behaves.

Screenshot 2025-07-11 at 11.07.18 AM.png

 

Now that we have covered the Guidance record, let’s turn our attention to the Recommendation that ties everything together. Much of the setup will look familiar, but I want to highlight that the Rating Scale now appears within the Pill Picker of our Resource Generator.

Screenshot 2025-07-11 at 11.32.29 AM.png

 

It’s time for the big reveal. Let’s see how everything comes together in action — from the dynamic Rating Scale to the interactive Guidance Actions and seamless Recommendations. This is where all the setup pays off, delivering a smooth, intuitive experience that empowers users to engage with promotions like never before.

 

Along with Upcoming Promotions, we now see a new recommendation that shows up as 'This might be a good promotion!' and you can see a button Apply Promotion.

Screenshot 2025-07-11 at 11.45.10 AM.png

 

When clicking on the Apply Promotion, the side panel is updated with our 'detail experience' along with the input for date, upon clicking Apply Promotion again, it will trigger the automation which is a subflow that creates a record in a Many-to-Many table.Screenshot 2025-07-11 at 11.48.15 AM.png

 

Lastly, I also created another recommendation that shows promotions applied to the account.

Screenshot 2025-07-11 at 11.52.43 AM.png

 

 

 

FAQ's

Recommended Actions does not display on the Accounts form in CSM/FSM Configurable Workspace

When creating a Recommendation, the Resource Generator in the Pill Selector is not selectable

  • Ensure you created a record on the Extensions Instances (sys_extension_instance) found in the Linking your 'Script Generator' to ScriptingGeneratorFactory section above.
  • If the extensions instance record is created, check the logs to see if there is an issue with the script includes.

 

Comments
alan_gross
Tera Contributor

@Mike-Thompson 

The article is great - thank you very much for all your efforts.

We are currently looking for a way to display the confidence score within Field Recommendations e.g. 

 

alan_gross_0-1753475874426.png

The ScriptingGeneratorFactory suggests to include the metaData object with a "confidence" property:

"name of field which will have the confidence score for the recommendation"

 

It's not clear to me how does is meant and how it would work.

Do you know if that is possible somehow?

 

I also noticed that the recommendations do not follow the attributes configured for the corresponding field e.g. ref_ac_columns attribute is not working.  Is this maybe a known issue?

 

Thank you very much once more and best regards

Alan

 

 

Mike-Thompson
ServiceNow Employee
ServiceNow Employee

@alan_gross I have not yet configured any field recommendations, but if it works the same as other recommendations, the suggested 'confidence' property is most likely just how i added a rating scale to the getOutputSchema (see bonus content).

Version history
Last update:
‎07-11-2025 12:33 PM
Updated by:
Contributors