Service Catalog Variables
API reference and patterns for Service Catalog variables, variable sets, UI policies, and client scripts. For catalog items and record producers, see service-catalog-guide.md. Requires SDK 4.3.0 or higher.
Catalog Variables API Reference
Common Variable Properties
| Property | Type | Description |
|---|---|---|
question | string | Required. Label text displayed to user. |
order | number | Display order (use increments of 100). |
mandatory | boolean | Whether field is required. Default: false. |
readOnly | boolean | Whether field is editable. Default: false. |
hidden | boolean | Whether field is visible. Default: false. |
tooltip | string | Hover help text. |
exampleText | string | Placeholder text. |
instructions | string | Inline help text. |
defaultValue | string | Pre-filled value. |
width | 25 | 50 | 75 | 100 | Field width percentage. |
readRoles | string[] | Roles that can read the variable. |
writeRoles | string[] | Roles that can write to the variable. |
mapToField | boolean | Map to target table field (Record Producers). |
field | string | Target field name when mapToField is true. |
Variable Types
Text Variables
- SingleLineTextVariable -- Single line text input
- MultiLineTextVariable -- Multi-line text area
- WideSingleLineTextVariable -- Full-width single line
- EmailVariable -- Email address input
- UrlVariable -- URL input
- IpAddressVariable -- IPv4/IPv6 input
- MaskedVariable -- Masked/password input (supports
useEncryption,useConfirmation)
Choice Variables
- SelectBoxVariable -- Dropdown choice list. Requires
choicesobject with{ label, sequence }. - MultipleChoiceVariable -- Radio buttons. Supports
choiceDirection: 'down'or'across'. - YesNoVariable -- Yes/No choice list.
- CheckboxVariable -- Checkbox. Use
selectionRequired: truefor mandatory. - NumericScaleVariable -- Likert scale radio buttons.
Lookup Variables
- LookupSelectBoxVariable -- Dropdown from table data.
- LookupMultipleChoiceVariable -- Radio buttons from table data.
Reference Variables
- ReferenceVariable -- References a record in another table. Key properties:
referenceTable,referenceQualCondition,useReferenceQualifier. - RequestedForVariable -- Specifies who the request is for.
- ListCollectorVariable -- Select multiple records from a table.
Date/Time Variables
- DateVariable -- Date picker.
- DateTimeVariable -- Date and time picker.
- DurationVariable -- Duration input.
Layout Variables
- ContainerStartVariable / ContainerSplitVariable / ContainerEndVariable -- Multi-column layout containers. Must be properly paired.
- LabelVariable -- Display-only label.
- BreakVariable -- Horizontal line separator.
Special Variables
- AttachmentVariable -- File upload.
- HtmlVariable -- Rich content display.
- RichTextLabelVariable -- Formatted label.
- CustomVariable / CustomWithLabelVariable -- UI macro insertion.
- UIPageVariable -- UI page insertion.
Variable Set API Reference
Properties
| Property | Type | Description |
|---|---|---|
$id | Now.ID[string] | Required. Unique identifier. |
title | string | Required. Display title. |
internalName | string | Internal name. Auto-generated from title if not provided. |
description | string | Description of the variable set. |
type | 'singleRow' | 'multiRow' | Default: 'singleRow'. |
layout | 'normal' | '2down' | '2across' | Default: 'normal'. |
order | number | Display order. Default: 100. |
displayTitle | boolean | Show collapsible section header. Default: false. |
setAttributes | string | Additional config (e.g., "max_rows=10,collapsible=true"). |
readRoles | string[] | Roles that can view the variable set. |
writeRoles | string[] | Roles that can modify values. |
createRoles | string[] | Roles that can create instances (for multiRow). |
variables | object | Variable definitions for the set. |
Attaching to Catalog Items
Attach variable sets via variableSets: [{ variableSet, order }] on a Catalog Item or Record Producer. Item-specific variables can be added alongside variable sets.
Multi-Row Variable Set (MRVS)
Use type: "multiRow" for grid/table data entry (e.g., multiple team members). Configure with setAttributes for row limits and collapsibility.
MRVS Unsupported Variable Types
- AttachmentVariable
- ContainerStartVariable / ContainerEndVariable / ContainerSplitVariable
- HtmlVariable
- CustomVariable / CustomWithLabelVariable
- RichTextLabelVariable
- UIPageVariable
MRVS Limitations
- "Assign to Field" not supported
- Cannot add variables with read roles
- Set row limits using
max_rowsattribute - Will not display if added to a container
Role-Based Access
readRoles: Roles that can view the variable setwriteRoles: Roles that can modify valuescreateRoles: Roles that can create instances (multiRow)
Set-level permissions override variable-level permissions when access is denied at the set level.
Catalog UI Policy API Reference
Properties
| Property | Type | Description |
|---|---|---|
$id | Now.ID[string] | Required. Unique identifier. |
shortDescription | string | Required. Description of what the policy does. |
catalogItem | ref | Required if not using variableSet. |
variableSet | ref | Required if not using catalogItem. |
appliesTo | 'item' | 'set' | Required if using variableSet. Default: 'item'. |
active | boolean | Whether the policy is active. Default: true. |
onLoad | boolean | Run on form load. Default: true. |
reverseIfFalse | boolean | Reverse actions when condition is false. Default: true. |
catalogCondition | string | Condition using encoded query syntax. |
appliesOnCatalogItemView | boolean | Applies to catalog item view. Default: true. |
appliesOnTargetRecord | boolean | Applies to target record. Default: false. |
appliesOnCatalogTasks | boolean | Applies to catalog tasks. Default: false. |
appliesOnRequestedItems | boolean | Applies to requested items. Default: false. |
runScripts | boolean | Execute client scripts. Default: false. |
executeIfTrue | string | Script when condition is true. |
executeIfFalse | string | Script when condition is false. |
runScriptsInUiType | 'desktop' | 'mobileOrServicePortal' | 'all' | Default: 'desktop'. |
actions | array | List of variable actions. |
Action Properties
| Property | Type | Description |
|---|---|---|
variableName | ref | Required. Variable reference. |
visible | boolean | Show/hide the variable. |
mandatory | boolean | Make variable required. |
readOnly | boolean | Make variable read-only. |
value | string | Value to set. |
valueAction | 'clearValue' | 'setValue' | How to apply the value. |
order | number | Execution order. Default: 100. |
variableMessage | string | Message to display on the field. |
variableMessageType | 'info' | 'warning' | 'error' | Message severity. |
Condition Syntax
// Simple condition
catalogCondition: `${catalogItem.variables.priority}=high^EQ`;
// Multiple conditions with AND
catalogCondition: `${catalogItem.variables.env}=prod^${catalogItem.variables.critical}=true^EQ`;
// Multiple conditions with OR
catalogCondition: `${catalogItem.variables.env}=prod^OR${catalogItem.variables.critical}=true^EQ`;
// Not empty check
catalogCondition: `${catalogItem.variables.reference}ISNOTEMPTY^EQ`;
Priority Rules
- Mandatory has highest priority
- If a variable is mandatory and has no value, readonly/hide actions do not work
- If a variable set/container has a mandatory variable without value, the entire set cannot be hidden
- "Clear value" action does not work on variable sets and containers
Variable Type Limitations
| Policy Type | Not Applicable To |
|---|---|
| Mandatory | Fraction, Container Split, Container End, UI Macro, Label, UI Page |
| Read-only | Fraction, Container Split, Container End, UI Macro, Label, UI Page |
| Visibility | Fraction, Container Split, Container End |
Policy with Client Scripts
Set runScripts: true and provide executeIfTrue / executeIfFalse scripts via Now.include(...). These scripts run client-side in the browser where modules are not available, so Now.include() is the correct approach. Scripts must be wrapped in function onCondition() {}.
Catalog Client Script API Reference
Properties
| Property | Type | Description |
|---|---|---|
$id | Now.ID[string] | Required. Unique identifier. |
name | string | Required. Name of the script. |
script | string | Inline script or Now.include() reference. These are client-side scripts — modules are not available. |
type | 'onLoad' | 'onChange' | 'onSubmit' | Script trigger type. |
uiType | 'desktop' | 'mobileOrServicePortal' | 'all' | Default: 'desktop'. |
active | boolean | Whether the script is enabled. Default: true. |
catalogItem | ref | Required if not using variableSet. |
variableSet | ref | Required if not using catalogItem. |
appliesTo | 'item' | 'set' | Required if using variableSet. Default: 'item'. |
variableName | ref | Required for onChange. The variable that triggers the script. |
appliesOnCatalogItemView | boolean | Applies on catalog item view. Default: true. |
appliesOnRequestedItems | boolean | Applies on requested items. Default: false. |
appliesOnCatalogTasks | boolean | Applies on catalog tasks. Default: false. |
appliesOnTargetRecord | boolean | Applies on target record. Default: false. |
Script Types
onLoad -- Runs when the form loads. Use for initial setup (field states, defaults, visibility).
onChange -- Runs when a specific variable changes. Always guard with if (isLoading) return; to prevent execution during form load.
onSubmit -- Runs on form submission. Return false to block submission. Avoid GlideAjax here -- async calls will not complete before the form submits.
g_form API Reference
| Method | Description |
|---|---|
getValue(fieldName) | Get variable value |
setValue(fieldName, value) | Set variable value |
setDisplay(fieldName, display) | Show/hide variable |
setMandatory(fieldName, mandatory) | Set mandatory state |
setReadOnly(fieldName, readOnly) | Set read-only state |
clearValue(fieldName) | Clear variable value |
hasField(fieldName) | Check if field exists |
showFieldMsg(fieldName, message, type, scrollForm) | Show field message |
hideFieldMsg(fieldName, clearAll) | Hide field message |
addErrorMessage(message) | Add banner error message |
clearOptions(fieldName) | Clear all select options |
addOption(fieldName, value, label) | Add a select option |
getReference(fieldName, callback) | Get referenced record (legacy) |
Note on getReference: Legacy convenience method. Works for simple lookups but GlideAjax is preferred for complex server-side logic. May make synchronous calls in some versions, which can freeze the UI.
Catalog Client Script vs Standard Client Script
| Aspect | Catalog Client Script | Standard Client Script |
|---|---|---|
| Scope | Catalog item or variable set | Table (e.g., Incident) |
| onChange target | Links to a variable | Links to a field |
| Context | Catalog ordering, RITM, Catalog Task forms | Table forms |
| Variable access | Direct by variable name | Use variables.variable_name prefix |
| Applies to | item or set | Specific table |
Scripts on Variable Sets
Scope scripts to a variable set using variableSet and appliesTo: 'set' so they apply to all catalog items using that set. Always use hasField() checks since the variable may not exist on every item that includes the set.
When multiple variable sets are attached to a catalog item, scripts execute in the order the variable sets are listed on the item. If both a variable set script and an item-level script target the same variable, the item-level script runs last and takes precedence.
GlideAjax
Use GlideAjax to call server-side Script Includes from client scripts. The client sends a request, the Script Include processes it, and returns a result via a callback.
Method comparison:
| Method | Execution | Use When | Avoid When |
|---|---|---|---|
getXMLAnswer() | Async | Simple lookups, returning a single value/string | You need the full XML response object |
getXML() | Async | Need full XML response, complex response parsing | Simple value returns (use getXMLAnswer) |
getXMLWait() | Sync | Almost never -- legacy/global scope only | Scoped apps, any production code |
Parameter rules: All custom parameters must start with sysparm_. The first addParam call must always be sysparm_name with the method name.
ga.addParam("sysparm_name", "methodName"); // REQUIRED: always first
ga.addParam("sysparm_user_id", userSysId); // Custom param: prefix with sysparm_
Script Include (Server-Side Companion)
Every GlideAjax call requires a corresponding Script Include on the server. The Script Include must extend AbstractAjaxProcessor and be marked Client Callable.
| Property | Value |
|---|---|
| Name | Must match the string in new GlideAjax('ClassName') |
| Client callable | Checked (required for GlideAjax access) |
| Extends | global.AbstractAjaxProcessor |
| Retrieve params | Use this.getParameter('sysparm_param_name') |
| Return data | Use return (simple string) or return JSON.stringify(obj) for objects |
Security: Client callable Script Includes run in the logged-in user's session context. ACLs still apply to GlideRecord queries. Always validate parameters from this.getParameter(). Never trust client-side input.
Examples
Variable Examples
Text variables:
SingleLineTextVariable({ question: "Employee Name", order: 100, mandatory: true, exampleText: "John Smith" });
MultiLineTextVariable({ question: "Description", order: 200, mandatory: true, width: 100 });
EmailVariable({ question: "Email Address", order: 300, mandatory: true });
MaskedVariable({ question: "Enter Password", order: 400, useEncryption: true });
Choice variables:
SelectBoxVariable({
question: "Priority Level",
order: 100,
choices: {
high: { label: "High", sequence: 1 },
medium: { label: "Medium", sequence: 2 },
low: { label: "Low", sequence: 3 }
},
includeNone: true
});
MultipleChoiceVariable({
question: "Services Required",
choiceDirection: "down",
choices: {
install: { label: "Installation", sequence: 1 },
config: { label: "Configuration", sequence: 2 },
training: { label: "Training", sequence: 3 }
},
order: 200
});
CheckboxVariable({ question: "I agree to the terms", order: 400, selectionRequired: true });
Reference variables:
ReferenceVariable({
question: "Point of Contact",
referenceTable: "sys_user",
referenceQualCondition: "active=true",
order: 100
});
ListCollectorVariable({
question: "Team Members",
listTable: "sys_user",
referenceQual: "active=true",
order: 300,
mandatory: true
});
Container layout (multi-column):
variables: {
contact_container_start: ContainerStartVariable({
question: "Contact Information",
layout: "2across",
displayTitle: true,
order: 100
}),
first_name: SingleLineTextVariable({
question: "First Name",
mandatory: true,
order: 110
}),
contact_split: ContainerSplitVariable({ order: 200 }),
email: EmailVariable({
question: "Email Address",
mandatory: true,
order: 210
}),
contact_container_end: ContainerEndVariable({ order: 300 })
}
Variables with pricing:
premiumSupport: CheckboxVariable({
question: "Premium Support (+$150)",
pricingDetails: [
{ amount: 150, currencyType: "USD", field: "price_if_checked" },
{ amount: 30, currencyType: "USD", field: "rec_price_if_checked" }
],
order: 500
});
hardwareType: SelectBoxVariable({
question: "Hardware Type",
choices: {
laptop: {
label: "Business Laptop (Base)",
sequence: 1,
pricingDetails: [{ amount: 0, currencyType: "USD", field: "misc" }]
},
workstation: {
label: "Developer Workstation (+$800)",
sequence: 2,
pricingDetails: [{ amount: 800, currencyType: "USD", field: "misc" }]
}
},
mandatory: true,
order: 600
});
Single-Row Variable Set
import { VariableSet, EmailVariable, SingleLineTextVariable, ReferenceVariable } from "@servicenow/sdk/core";
export const contactInfoSet = VariableSet({
$id: Now.ID["contact_info_set"],
title: "Contact Information",
description: "Standard contact information fields",
type: "singleRow",
layout: "2across",
order: 100,
displayTitle: true,
variables: {
email: EmailVariable({ question: "Email Address", mandatory: true, order: 100 }),
phone: SingleLineTextVariable({ question: "Phone Number", mandatory: true, order: 200 }),
department: ReferenceVariable({
question: "Department",
referenceTable: "cmn_department",
referenceQualCondition: "active=true",
order: 300
})
}
});
Multi-Row Variable Set (MRVS)
export const teamMembersSet = VariableSet({
$id: Now.ID["team_members_set"],
title: "Team Members",
description: "Add multiple team members who need access",
type: "multiRow",
layout: "2across",
displayTitle: true,
setAttributes: "max_rows=10,collapsible=true",
readRoles: ["admin", "manager"],
writeRoles: ["admin"],
variables: {
user: ReferenceVariable({
question: "User",
referenceTable: "sys_user",
referenceQualCondition: "active=true",
mandatory: true,
order: 100
}),
accessLevel: SelectBoxVariable({
question: "Access Level",
choices: {
read: { label: "Read Only", sequence: 1 },
write: { label: "Write", sequence: 2 },
admin: { label: "Admin", sequence: 3 }
},
mandatory: true,
order: 200
}),
startDate: DateVariable({ question: "Access Start Date", mandatory: true, order: 300 })
}
});
Attaching Variable Sets to a Catalog Item
export const accessRequest = CatalogItem({
$id: Now.ID["access_request"],
name: "Team Access Request",
shortDescription: "Request access for team members",
catalogs: [serviceCatalog],
categories: [itServicesCategory],
variableSets: [
{ variableSet: contactInfoSet, order: 100 },
{ variableSet: teamMembersSet, order: 200 }
],
variables: {
notes: MultiLineTextVariable({ question: "Additional Notes", order: 100 })
},
flow: "523da512c611228900811a37c97c2014"
});
Catalog UI Policy -- Show/Hide Based on Condition
import { CatalogUiPolicy } from "@servicenow/sdk/core";
import { hardwareRequestItem } from "./catalog-items/HardwareRequest.now";
export const managerApprovalPolicy = CatalogUiPolicy({
$id: Now.ID["manager_approval_policy"],
shortDescription: "Show manager approval when high priority selected",
catalogItem: hardwareRequestItem,
catalogCondition: `${hardwareRequestItem.variables.priority}=high^EQ`,
actions: [
{
variableName: hardwareRequestItem.variables.manager_approval,
visible: true,
mandatory: true
}
]
});
Catalog UI Policy -- Read-Only with Value
export const readOnlyPolicy = CatalogUiPolicy({
$id: Now.ID["readonly_license_policy"],
shortDescription: "Make license type read-only for standard software",
catalogItem: softwareRequestItem,
catalogCondition: `${softwareRequestItem.variables.software_type}=standard^EQ`,
actions: [
{
variableName: softwareRequestItem.variables.license_type,
readOnly: true,
value: "standard_license",
valueAction: "setValue"
}
]
});