- Post History
- Subscribe to RSS Feed
- Mark as New
- Mark as Read
- Bookmark
- Subscribe
- Printer Friendly Page
- Report Inappropriate Content
05-01-2025 04:12 AM - edited 05-28-2025 01:31 AM
A common requirement is to redirect users to specific portals dependent on the roles that they have. For example, if you have an internal Employee Center portal, and an external Customer Service Management portal, you might want your users to be redirected to the correct experience.
In this example, I’ll be referring to the following personas and the experience they should be directed to:
Persona |
Role |
Desired Outcome |
System Administrator |
admin |
Should always login to the standard Next Experience interface |
ITSM User |
itil |
Redirect to the Service Operations Workspace |
External User |
snc_external |
Redirect to Customer Service Management portal |
Internal User |
snc_internal |
Redirected to Employee Center |
Note that workspace redirections already happen out of the box (for example, users with the itil role are redirected to the Service Operations Workspace on a new instance), however, the solution we're discussing can override that workspace redirects.
Portal redirects can be achieved in your ServiceNow instance using a Script Include and a couple of system properties. There is an example Script Include called SPEntryPage out of the box that you can use as a starting point.
Before we go further, this requires some customisation which is out of scope for support. The Script Include in question is provided as an example script which you can copy. Leading practice for customisation is to avoid copying objects unless they are reusable objects. With the original SPEntryPage being being described as an example and flagged as a high risk customisation, I'd be inclined to treat it is a reusable object that you can copy or extend to suit your needs.
The script requires two system properties to enable it for use:
Property |
Type |
Value |
glide.entry.first.page.script |
String |
new NAME_OF_SCRIPT().getFirstPageURL(); |
glide.entry.page.script |
String |
new NAME_OF_SCRIPT().getLoginURL(); |
These two system properties do not exist in an out of the box instance. You will need to create them to use your version of SPEntryPage.
When doing this on my Personal Developer Instance, I chose to Extend the Script Include to one called MultiSPEntryPage. In my Extended Script Include, I’ve added two functions (initialize & getFirstPageURL). The getLoginURL() function is inherited from the original script.
My extended script include is below.
Disclaimer: This script is provided 'as is' without any warranties, support, or guarantees. You are responsible for reviewing and adapting this script to your specific use case. It must be validated in a safe, non-production environment before use.
/**
* Portal login script to redirect users to correct portal based on hard coded role
* Extended from out of the box SPEntryPage
*
* =============================================================================
* DISCLAIMER: This script is provided to assist with specific tasks but is
* offered "AS IS" without any warranties, support, or guarantees.
*
* You are responsible for reviewing and adapting the script to fit your specific
* use case. It must be validated in a safe, non-production environment before
* use. Improper use may result in loss of access or service disruption.
* Always test thoroughly before applying to production systems.
* =============================================================================
*
* Configure by setting the following properties:
*
* PROPERTY VALUE
* glide.entry.page.script new MultiSPEntryPage().getLoginURL();
* glide.entry.first.page.script new MultiSPEntryPage().getFirstPageURL();
* MultiSPEntry.Debug true/false
*
* functions can return a path or null if no overrides are necessary
*
**/
var MultiSPEntryPage = Class.create();
MultiSPEntryPage.prototype = Object.extendsObject(SPEntryPage,{
initialize: function() {
this.EMPLOYEE_PORTAL = "/esc";
this.CUSTOMER_PORTAL = "/csm";
this.CLASSICEXP = "/?.do";
this.SOW = "/now/sow/home";
},
getFirstPageURL: function() {
var session = gs.getSession();
this.logProperties('before', session);
// has roles and is not a Service Portal page - go to Classic Experience
var nt = session.getProperty("nav_to");
var isServicePortalURL = new GlideSPScriptable().isServicePortalURL(nt);
var redirectURL = session.getProperty("login_redirect");
// Start of Customisation
if(user.hasRole('admin')) {
// ALWAYS check for admin first to prevent your admin account being directed to a portal
gs.log('MultiSPEntry: Admin login');
return this.CLASSICEXP;
} else if (user.hasRole('itil')) {
// Redirect to Service Operations Workspace
gs.log('MultSPEntry: SOW Login');
return this.SOW;
} else if (user.hasRole("snc_external") && !redirectURL && !isServicePortalURL) {
// External role - redirect to Customer Service Portal
gs.log("MultiSPEntry: /csm Redirect");
return this.CUSTOMER_PORTAL;
} else if (user.hasRoles() && !redirectURL && !isServicePortalURL) {
// This is a catch-all to cover all remaining users with a role and re-direct to UI16 - check for specific roles before getting to this part.
gs.log("MultiSPEntry: Classic Experience Login");
return this.CLASSICEXP;
}
/*
* Including this else if will redirect users to the /esc before login
else if (!user.hasRoles() && !redirectURL && !isServicePortalURL) {
// For users with no roles and not meeting other criteria, redirect to Employee Center
return "/esc";
}
*/
// END of Customisation
// user may have logged in from a frame, the /login_redirect.do page will bust out of it
if (!redirectURL) {
// redirectURL is nav_to
// if nav_to == "welcome.do" then use starting_page
var sPage = session.getProperty("starting_page");
if (sPage && nt == "welcome.do")
nt = sPage;
// Avoid a redirect loop to the home page
var ep = gs.getProperty("glide.login.home");
if (nt) {
if (ep == nt)
nt = null;
}
// PRB726860: if page is still welcome.do, go to glide.login.home preserving frameset
if (nt == "welcome.do") {
session.putProperty("nav_to", ep);
return;
}
session.putProperty("login_redirect", nt || "true");
return "/login_redirect.do?sysparm_stack=no";
}
session.clearProperty("login_redirect");
session.clearProperty("nav_to");
if (redirectURL && redirectURL.indexOf("sys_attachment.do") > -1)
return redirectURL;
var returnUrl = this.portal;
if (redirectURL && redirectURL != "true") {
var spUrl = new GlideSPScriptable().mapUrlToSPUrl(redirectURL);
returnUrl = spUrl ? this.portal + "?" + spUrl : redirectURL;
if (!user.hasRoles() && !spUrl && redirectURL.indexOf("home_splash.do") > -1)
returnUrl = this.portal;
}
this.logProperties('after', session);
if (!this.logVariables) {
gs.log('redirectURL: ' + redirectURL);
gs.log('User: ' + user.getName());
gs.log('is internal: ' + (!user.hasRoles()));
gs.log('returnUrl: ' + returnUrl);
}
return returnUrl;
},
type: 'MultiSPEntryPage'
});
Important: The If statement starting on line 46 (if(user.hasRole("admin)) }) in the above script should always check for admin first. This will prevent your admin user from being redirected to a portal and struggling to get to the standard interface.
The first match found in this if, else if statement will be returned - the order of your else if statements is very important and needs some careful consideration. You should also avoid a general ‘else’ clause at the end of this if, else if as that will make some of the later code unreachable.
In my Script I’ve set some constants in the initialize function for the different URI’s we’ll be redirecting to. It’s good practice to put these here, particularly if we are likely to use these more than once within the script. If your destination paths that you redirect users to might need to be updated outwith a production release, or need to differ from one instance to another, you should store these values in a system property and retrieve them using gs.getProperty.
Once I saved this script as MultiSPEntryPage, I set the system properties as follows:
Property |
Value |
glide.entry.first.page.script |
new MultiSPEntryPage().getFirstPageURL(); |
glide.entry.page.script |
new MultiSPEntryPage().getLoginURL(); |
Note: I've not added the getLoginURL method in my Extended Script Include - this will be inherited from the original script include that I've extended. For the second system property above (glide.entry.page.script), you could theoretically set this to point to the original Script Include. I've used the Extended Script Include in both for consistency.
Testing
Important: Using this script include has the potential to prevent your admin users getting to the standard interface. I would recommend staying logged in as an Admin and then conducting testing in a separate browser or browser profile. Doing this will allow you to roll back your changes should the script not function as intended.
As a minimum, you should also conduct full UAT testing of this change in a sub production environment. For myself, I have 4 personas that I considered. For each persona, I did the following:
- Logged in as a user created for that persona before making changes and noted the outcome
- Logged in as the same user after making the change to confirm that the new behaviour was working as expected.
Final thoughts
If you’re thinking about making a similar change on redirects, ensure you plan. I'd suggest the following
- What personas are using your instance?
- What testing needs to be done?
- What stakeholders you should involve for testing?
- Where will you develop the change? (Tip: PDIs are free and easily reset).
Additional Resources
KB0969846 - How to setup portal redirection based on different roles
KB0747432 - Redirection with Service Portal | Frequently Asked Questions
- 2,711 Views
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
Why can't I see these 2 properties in my PDI?
If I want to create these 2 properties, then there is no such type as "script" to call the script include in "value".
Can you please help with this?
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
Hi @anandvk222
The two properties don't exist out of the box and you'll need to create them using the type "string".
Thanks
Stuart
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
Great write up Stuart.
I wanted to ask if you have experience with redirecting non-roled users who have manually navigated to the Next Experience home page through URL manipulation, by appending now/nav/ui/home or through ?.do to the base URL?
Given the SPEntryPage script include is designed to work upon login, it does not redirect users after they have logged in. To address this in the past, we have used a Global UI Script which KB0687717 has suggested. This no longer works when hitting the Next Experience landing page.
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
for this statement , Note that workspace redirections already happen out of the box (for example, users with the itil role are redirected to the Service Operations Workspace on a new instance), however, the solution we're discussing can override that workspace redirects.
in my pdi , at least it does not happen. what is the best method to have some group be redirected to SOW ?