on 12-08-2025 05:49 AM
One of the best parts of the ThousandEyes platform is the ability to integrate and communicate alerts with multiple other softwares. ThousandEyes alerts can be configured to trigger ServiceNow incidents and notify the application and/or network stakeholders in real-time when a service is down.
ServiceNow integration can be achieved in two ways:
Previously, custom webhooks were configured differently. However, with the introduction of Integrations 2.0, the integration is broken into two parts: the Connectors (providing the connection with the integration) and the Operations (the actual action being performed). This allows for multiple operations to be performed using the same connector.
For Example: Suppose I wanted to send different parameters to the ServiceNow incident for alerts regarding Network & App Synthetics, Endpoint Experience, and Devices.
Using Integrations 1.0 I would need to configure both the parameters and the integration itself for all three. Using Integrations 2.0, however, while I would need to create separate operations for each, all three could use the same connector.
If your organization has compliance requirements to use OAuth2.0, you are no doubt familiar with having to use custom webhooks. This document provides a step-by-step guide on how to configure this integration.
Note: Integrations 1.0 is still supported and can be used when you don’t have OAuth 2.0 related compliance requirements, or you do not want to customise the integration by using multiple operations with the same connector.
This document assumes that you have a working ServiceNow instance and a ThousandEyes account, with administrative rights in both, and have already configured your ThousandEyes tests and alerts.
/oath_token.dowith the client ID and client secret for testing. We do not advise that as newer versions of ServiceNow such as Xanadu will not allow this. This is because these versions enforce PKCE for all new OAuth clients by default.
{
"short_description": "ThousandEyes Alert: '{{alert.rule.name}}' for test {{alert.test.name}}",
"description": "An alert was triggered for test '{{alert.test.name}}.\nAlert Type: {{alert.test.testType}}\nSeverity: {{alert.severity.id}}\nView details in ThousandEyes: https://app.thousandeyes.com/alerts/list/?__a={{alert.rule.account.id}}",
"impact": "2",
"urgency": "2",
"state": {{#if (eq type.id 2)}}1{{else}}6{{/if}},
"caller_id": "62826bf03710200044e0bfc8bcbe5df1",
"correlation_id": "{{alert.id}}",
"correlation_display": "{{alert.id}}",
"close_code": "{{#if (eq type.id 1)}}Resolved by ThousandEyes Alert Clear{{/if}}",
"close_notes": "{{#if (eq type.id 1)}}Alert cleared automatically by ThousandEyes integration.{{/if}}"
}
Note: You do not have to use the caller_id line. However, be aware if it is set to the Client ID from the OAuth Application Registry, the Incident in ServiceNow will populate the Caller accordingly with the username or email corresponding to the caller_id mentioned here.
This step ensures that incidents are created with the State field set to New when an alert triggers, as well as Resolved when the alert clears.
(function executeBR(current, previous /*null on insert*/) {
gs.info('Alert correlation_id: ' + current.correlation_id + ', state: ' + current.state);
if (current.state == 1) {
// Trigger alert: always allow creation
gs.info('Trigger alert received → creating new incident.');
return;
}
// Clear alert: search for existing unresolved incident
var gr = new GlideRecord('incident');
gr.addQuery('correlation_id', current.correlation_id);
gr.addQuery('state', '!=', 6,7); // only unresolved incidents
gr.addQuery('caller_id', current.caller_id); // add if you want to clear incidents created by the ThousandEyes user only
gr.query();
if (gr.next()) {
gs.info('Existing unresolved incident found: ' + gr.number + ', state: ' + gr.state);
// Resolve the existing incident
gr.state = 6;
gr.close_code = 'Solved (Permanently)';
gr.close_notes = 'Automatically resolved by ThousandEyes alert clear.';
gr.update();
gs.info('Incident ' + gr.number + ' resolved automatically.');
// Prevent creating a new incident
current.setAbortAction(true);
gs.info('New incident creation aborted for clear alert.');
} else {
// No existing unresolved incident found → skip creating a resolved incident
current.setAbortAction(true);
gs.info('Clear alert received but no unresolved incident exists → abort creation.');
}
})(current, previous);
Note: What does this do?
This script checks for the current state of an alert and if it is a new alert that is triggered as indicated by the type.id from ThousandEyes being set to 1, a new incident is created, otherwise, if the type.id is 2 indicating that an earlier alert is now cleared, it will look for the correlation id to identify the correct incident and mark it as ‘Resolved’.
Testing Protocols
(function executeRule(current, previous) {
try {
gs.log("TE Business Rule fired for incident: " + current.number);
gs.log("Full incident record: " + JSON.stringify({
short_description: current.short_description,
description: current.description,
source: current.source,
event_class: current.event_class,
resource: current.resource,
node: current.node,
metric_name: current.metric_name,
u_source: current.u_source,
u_event_class: current.u_event_class,
u_resource: current.u_resource,
u_node: current.u_node,
u_metric_name: current.u_metric_name,
u_type: current.u_type,
u_severity: current.u_severity,
u_additional_info: current.u_additional_info
}));
} catch (e) {
gs.error("TE Logging Business Rule error: " + e.message);
}
})(current, previous);
If you’re able to validate that your alerts are triggering properly congratulations! You have successfully integrated ThousandEyes and ServiceNow.
Find answers to your questions by entering keywords or phrases in the Search bar above. New here? Use these resources to familiarize yourself with the community: