- Post History
- Subscribe to RSS Feed
- Mark as New
- Mark as Read
- Bookmark
- Subscribe
- Printer Friendly Page
- Report Inappropriate Content
33m ago - edited 26m ago
Problem
In ServiceNow Workplace Visitor Management, external visitors typically receive an email containing a link to complete their required pre-check-in activities, such as:
- entering visitor details,
- uploading a visitor picture,
- reading and acknowledging workplace policies.
At reception, however, visitors may not have completed these activities and may not have access to their mailbox. By default, the visitor-specific registration URL is not displayed in the WSD Receptionist Portal. As a result, receptionists cannot easily open the registration journey for the visitor.
Solution
I implemented an additive customization that exposes the visitor-specific registration URL in the receptionist portal as a clickable Visitor Registration link.
The receptionist opens the link in a private/incognito browser window and lets the visitor complete the outstanding requirements.
The implementation consists of:
- A custom field on the visitor record to store the URL
- Logic to populate the URL
- A Visit Requirements Item to surface the field in the portal data
- A custom Service Portal widget that converts the displayed raw URL into a labelled hyperlink
- An instance of that widget added to the receptionist portal page
1. Custom visitor field and URL generation
Create a custom field on the Visitor table:
Setting Value
| Table | sn_wsd_visitor_visitor |
| Field | u_visitor_registration_url |
| Type | URL / String, depending on local standards |
Use a Script Include and a before Insert/Update Business Rule to generate and populate the visitor-specific registration URL.
Script Include
Name: DBORUtil
Application: Workplace Visitor Management
Accessible from: All application scopes
Client callable: false (unchecked)
var DBORUtil = Class.create();
DBORUtil.prototype = {
initialize: function() {},
getVisitorURL: function(gr) {
return gs.getProperty('glide.servlet.uri')
+ 'esc?id=vis_exp'
+ '&email=' + gr.email.replace('@', '%40')
+ '&userNumber=' + gr.number
+ '&sysId=' + gr.getUniqueValue();
},
type: 'DBORUtil'
};
Generated URL:
https://<instance>.service-now.com/esc?id=vis_exp&email=visitor_email_%40_encoded>&userNumber=<visitor_number>&sysId=<visitor_sys_id>Business Rule:
Name: DBOR update Visitor URL
Table: Visitor [sn_wsd_visitor_visitor]
Application: Workplace Visitor Management
Active: true (checked)
Advanced: true (checked)
When: before
Insert: true (checked)
Update: true (checked)
Delete: false (unchecked)
Query: false (unchecked)
Set the condition to: Email is not empty
(function executeRule(current, previous /*null when async*/) {
current.u_visitor_registration_url = new DBORUtil().getVisitorURL(current);
})(current, previous);
2. Surface the URL through Visit Requirements
Create a Visit Requirements Item so the custom field is made available as part of the existing external-visitor information in Workplace Receptionist Portal.
Setting Value
| Name | u_visitor_registration_url |
| Target table | Visitor [sn_wsd_visitor_visitor] |
| Target field | u_visitor_registration_url |
| Requirement type | Information |
| Filled by | Host |
| Mandatory for | None |
| Requires signature | False |
| Visit requirements | External visitor information |
| Active | True |
This allows the URL field to be included in the requirement values rendered in the receptionist portal.
3. Create the custom Service Portal widget
Create a new widget under Service Portal → Widgets → New.
Widget header
Field Value
| Name | WSD URL Link Injector |
| ID | wsd-url-link-injector |
| Application | Workplace Visitor Management |
| Public | False |
| Active | True |
This is intentionally a background widget: it has no visual UI of its own. Instead, it observes the receptionist portal’s detail panel and replaces a raw URL with a labelled hyperlink.
HTML Template
<div>
<!-- WSD URL Link Injector - no visible output -->
</div>CSS:
Leave empty.
Server Script:
Leave empty.
Client Controller:
api.controller = function($timeout) {
var c = this;
function makeLinksClickable() {
var spans = document.querySelectorAll(
'.visitor-card .detail-row span, ' +
'.visitor-detail-panel .info-row-label span, ' +
'.visitor-detail-panel .info-row span'
);
Array.prototype.forEach.call(spans, function(span) {
if (span.querySelector('a')) {
return;
}
if (span.getAttribute('ng-bind-html')) {
return;
}
var text = span.textContent || '';
var urlMatch = text.match(/(https?:\/\/[^\s]+)/);
if (!urlMatch) {
return;
}
var url = urlMatch[1];
var anchor = document.createElement('a');
anchor.href = url;
anchor.target = '_blank';
anchor.rel = 'noopener noreferrer';
anchor.textContent = 'Visitor Registration';
anchor.style.fontSize = '18px';
anchor.style.wordBreak = 'break-all';
anchor.style.display = 'block';
anchor.addEventListener('click', function(e) {
e.stopPropagation();
});
span.textContent = '';
span.appendChild(anchor);
});
}
var observer = new MutationObserver(function() {
clearTimeout(observer._timer);
observer._timer = setTimeout(makeLinksClickable, 300);
});
function waitForPortal() {
var target = document.querySelector('.wsd-receptionist-portal');
if (target) {
observer.observe(target, {
childList: true,
subtree: true
});
makeLinksClickable();
} else {
$timeout(waitForPortal, 500);
}
}
c.$onInit = function() {
$timeout(waitForPortal, 500);
};
};Link Function
Leave empty
4. Add the widget to the receptionist portal page
Creating the widget record is not sufficient. The widget must be added to the page as an sp_instance; otherwise, its client controller never executes.
Open the receptionist portal and identify the page ID in the URL:
https://<instance>.service-now.com/<portal>?id=<page_id>For example, the page ID may be wsd_receptionist.
Append &sp_debug=true to the page URL:
https://<instance>.service-now.com/<portal>?id=<page_id>&sp_debug=true- Reload the page and select the pencil icon in the debug toolbar to open Service Portal Designer.
In the page layout:
- scroll to the bottom,
- add a new row,
- select a single 12-column layout,
- add the WSD URL Link Injector widget to that column,
- save the page.
The widget produces no visible content, so its location on the page is not important. It only needs to be present on the receptionist portal page.
5. Result
When a receptionist selects an external visitor, the detail panel displays a clickable Visitor Registration link instead of the raw URL .
The receptionist can open this link in a private/incognito browser window and let the visitor complete outstanding pre-check-in tasks directly at reception.
The only open point is, how the visitor gets the Onetime-Password for login. But with some creativity where are lot's of options.
6. Security consideration
The registration URL should be treated as sensitive because it enables access to a visitor-specific workflow. Reception devices should be controlled, the private browser session should be closed after use, and access to the receptionist portal should be restricted appropriately.
