Application Automation
This is the most script-heavy domain. It covers Business Rules, Script Includes, GlideRecord, GlideAggregate, GlideSystem, GlideAjax, Flow Designer, Scheduled Jobs, and Events.
GlideRecord API (Server-Side)
GlideRecord is the primary server-side API for querying and manipulating records in ServiceNow. You MUST know this API thoroughly for the CAD exam.
Core GlideRecord Methods
| Method | Purpose |
|---|---|
| addQuery(field, operator, value) | Add a filter condition |
| addEncodedQuery(query) | Add a filter using encoded query string |
| query() | Execute the query |
| next() | Move to next record (returns true/false) |
| get(sysId) | Get a single record by sys_id |
| getValue(field) | Get field value as string |
| setValue(field, value) | Set a field value |
| insert() | Insert a new record, returns sys_id |
| update() | Save changes to the current record |
| deleteRecord() | Delete the current record |
| getRowCount() | Return total matching records (performance caution) |
| setLimit(n) | Limit results to n records |
| orderBy(field) / orderByDesc(field) | Sort results |
| addNotNullQuery(field) | Filter where field is not empty |
| addNullQuery(field) | Filter where field is empty |
Common Query Patterns
Query active P1 incidents assigned to a specific group:
- var gr = new GlideRecord('incident');
- gr.addQuery('active', true);
- gr.addQuery('priority', 1);
- gr.addQuery('assignment_group', groupSysId);
- gr.query();
- while (gr.next()) { /* process each record */ }
GlideRecord getValue() always returns a STRING. For Reference fields, it returns the sys_id (not the display value). Use getDisplayValue() for display values. For boolean fields, getValue returns 'true' or 'false' as strings. parseInt() or == for number comparisons.
Never use getRowCount() in production code — it queries all matching records just to count them. Use GlideAggregate instead for counting. Also avoid gr.get() inside loops — use encoded queries instead.
GlideAggregate
GlideAggregate performs database aggregation operations (COUNT, SUM, AVG, MIN, MAX) much more efficiently than GlideRecord with manual counting.
GlideAggregate Methods
- addAggregate('COUNT') — Count records.
- addAggregate('SUM', field) — Sum a numeric field.
- addAggregate('AVG', field) — Average a numeric field.
- addAggregate('MIN', field) / addAggregate('MAX', field) — Min/max values.
- groupBy(field) — Group results by a field.
- getAggregate('COUNT') — Get the aggregate result.
You need to display the count of open incidents per priority level on a dashboard widget. What's the most efficient approach?
Use GlideAggregate: var ga = new GlideAggregate('incident'); ga.addQuery('active', true); ga.addAggregate('COUNT'); ga.groupBy('priority'); ga.query(); while (ga.next()) { var priority = ga.priority; var count = ga.getAggregate('COUNT'); }. This is far more efficient than querying all incidents and counting manually.
Business Rules (Developer Focus)
For the CAD exam, you need a deeper understanding of Business Rules than the CSA exam, including scripting patterns, common pitfalls, and performance considerations.
Business Rule Best Practices
- Keep Business Rules simple — complex logic belongs in Script Includes.
- Use conditions (filter) whenever possible instead of script-based checks.
- Avoid current.update() in Business Rules on the same table — causes infinite loops unless controlled.
- Use 'before' rules to modify the current record. Use 'after' rules for side effects.
- Async rules run in background — use for non-blocking operations like notifications or integrations.
- Always check current.operation() if the rule applies to both insert and update.
The 'previous' Object
- Only available in UPDATE operations (not insert or delete).
- previous.field_name gives the value BEFORE the update.
- Use to detect changes: if (current.state != previous.state) { /* state changed */ }
- previous.state.changes() — Returns true if the field value changed.
- current.state.changesTo(value) — Returns true if field changed TO a specific value.
- current.state.changesFrom(value) — Returns true if field changed FROM a specific value.
current.field.changes() returns true if the field was modified in this transaction. current.field.changesTo(value) and changesFrom(value) are more specific. These methods are ONLY valid in Business Rules running on update events. Using them on insert always returns false.
Script Includes
Script Includes are reusable server-side JavaScript classes/functions. They are the recommended way to organize complex logic and are essential for clean, maintainable code.
Script Include Types
| Type | Use Case | Key Setting |
|---|---|---|
| Classless | Simple utility functions | No prototype pattern |
| Class-based | Object-oriented logic with methods | Uses prototype pattern |
| Client Callable | Called from Client Scripts via GlideAjax | 'Client callable' checkbox = true |
| Extension | Extends another Script Include | Uses extendsObject() |
GlideAjax Pattern (Client → Server)
- Create a Script Include with 'Client callable' checked.
- In the Script Include, create a method that reads parameters and returns a result.
- In the Client Script, create a GlideAjax object referencing the Script Include name.
- Add parameters using addParam('sysparm_name', 'parameter_name') and addParam('sysparm_value', value).
- Call getXMLAnswer() for synchronous (BAD) or getXML(callback) for asynchronous (GOOD).
- In the callback, parse the response using response.responseXML.documentElement.getAttribute('answer').
The GlideAjax pattern is one of the MOST TESTED topics on the CAD exam. Know it end-to-end: Client Script → GlideAjax → Script Include → Response. The Script Include must be marked 'Client callable'. Use addParam to pass the method name ('sysparm_name') and values ('sysparm_your_param'). Always use the async callback pattern.
GlideSystem (gs) API
The GlideSystem (gs) object provides system-level utility methods available in all server-side scripts.
Key gs Methods
| Method | Purpose |
|---|---|
| gs.getUser() | Get the current user's GlideUser object |
| gs.getUserID() | Get current user's sys_id |
| gs.getUserName() | Get current user's username |
| gs.hasRole('role') | Check if current user has a role |
| gs.log(msg) | Write to system log |
| gs.info(msg) / gs.warn(msg) / gs.error(msg) | Write to system log with level |
| gs.addInfoMessage(msg) | Display info banner on form |
| gs.addErrorMessage(msg) | Display error banner on form |
| gs.nil(value) | Check if value is null, undefined, or empty string |
| gs.getProperty('name') | Read a system property value |
| gs.eventQueue('event.name', current, parm1, parm2) | Queue a system event |
| gs.now() / gs.nowDateTime() | Get current date/time |
gs methods are SERVER-SIDE ONLY (except gs.hasRole and gs.getUserID which also work in some client contexts). gs.nil() checks for null, undefined, AND empty string — it's more comprehensive than a simple null check. gs.addInfoMessage() and gs.addErrorMessage() display messages on the form — they work in Business Rules and UI Actions.
Events & Scheduled Jobs
Events decouple triggering logic from response logic. A Business Rule queues an event, and a separate Script Action or Notification responds to it.
Event System
- Event Registration — Define event name and table (System Policy > Events > Registry).
- gs.eventQueue() — Queue an event from a Business Rule or Script Include.
- Script Actions — Server-side scripts that respond to specific events.
- Notifications — Email notifications triggered by events.
- Event Queue — Events are processed asynchronously from the sysevent table.
Scheduled Jobs
- Scheduled Jobs run scripts on a defined schedule (daily, weekly, cron expression).
- Useful for data cleanup, report generation, integrations, and maintenance tasks.
- Configured under System Definition > Scheduled Jobs.
- Can run Script Includes or inline scripts.
Events are the recommended way to trigger notifications and asynchronous processing. Instead of sending an email directly from a Business Rule, queue an event and let a Notification listen for it. This follows the event-driven architecture pattern that ServiceNow recommends.
Key Takeaways
- GlideRecord getValue() returns strings. Use getDisplayValue() for Reference field display values.
- Use GlideAggregate for COUNT/SUM/AVG operations. Never use GlideRecord.getRowCount() for counting.
- The GlideAjax pattern (Client Script → Script Include) is one of the most tested topics.
- Script Includes must be marked 'Client callable' to be invoked from GlideAjax.
- current.field.changes(), changesTo(), changesFrom() only work in update Business Rules.
- Avoid current.update() in Business Rules — it causes infinite loops without proper guards.
- gs.eventQueue() is the recommended way to trigger async processing and notifications.
- The 'previous' object is only available in update operations, not insert or delete.
Community-created study aids. Not official ServiceNow exam content.