SuperAPI AI Directory

survey-analysis

General & other

View repository

Updated 10-15 22:12

About this skill

Survey Analysis

Overview

This skill provides structured analysis of survey and assessment responses in ServiceNow. It covers:

  • Aggregating survey scores from asmt_assessment_instance and asmt_assessment_instance_question
  • Analyzing individual response data from survey_response for detailed breakdowns
  • Identifying trends across time periods by comparing assessment results
  • Segmenting responses by department, location, group, or custom dimensions
  • Generating statistical summaries (mean, median, distribution) for each question
  • Producing actionable improvement recommendations based on score patterns

When to use: When analyzing customer satisfaction (CSAT), employee engagement, service quality surveys, or any assessment data collected through ServiceNow Performance Analytics assessments or surveys.

Value proposition: Transforms raw survey data into actionable insights, identifies areas needing attention before they become systemic issues, and provides data-driven recommendations for improvement initiatives.

Prerequisites

  • Plugins: com.snc.assessment (Assessment and Survey), com.snc.pa (Performance Analytics, optional)
  • Roles: assessment_admin, survey_admin, pa_admin, or admin
  • Access: Read access to asmt_assessment_instance, asmt_assessment_instance_question, survey_response, and related metric tables
  • Knowledge: Understanding of survey structure, scoring scales, and organizational hierarchy

Procedure

Step 1: Identify the Survey or Assessment

Find the survey definition and understand its structure.

Using MCP (Claude Code/Desktop):

Tool: SN-Query-Table
Parameters:
  table_name: asmt_metric_definition
  query: active=true^typeLIKEsurvey^ORtypeLIKEassessment
  fields: sys_id,name,description,type,category,state,evaluation_method,scale,number_of_responses
  limit: 20
  order_by: name

Using REST API:

GET /api/now/table/asmt_metric_definition?sysparm_query=active=true&sysparm_fields=sys_id,name,description,type,category,state,evaluation_method,scale,number_of_responses&sysparm_limit=20&sysparm_display_value=true

Get the survey questions/metrics:

Tool: SN-Query-Table
Parameters:
  table_name: asmt_metric
  query: metric_definition=[definition_sys_id]^active=true
  fields: sys_id,name,question,datatype,weight,scale,min_value,max_value,order,category
  limit: 50
  order_by: order

Step 2: Retrieve Assessment Instances

Pull completed survey instances for analysis.

Using MCP:

Tool: SN-Query-Table
Parameters:
  table_name: asmt_assessment_instance
  query: metric_type=[definition_sys_id]^state=complete^taken_on>=javascript:gs.monthsAgoStart(3)
  fields: sys_id,number,metric_type,user,taken_on,percent,state,group,department,trigger_id
  limit: 100
  order_by: -taken_on

Using REST API:

GET /api/now/table/asmt_assessment_instance?sysparm_query=metric_type=[definition_sys_id]^state=complete^taken_on>=javascript:gs.monthsAgoStart(3)&sysparm_fields=sys_id,number,metric_type,user,taken_on,percent,state,group,department&sysparm_limit=100&sysparm_display_value=true

Step 3: Aggregate Scores by Question

Analyze response distributions for each survey question.

Using MCP:

Tool: SN-Execute-Background-Script
Parameters:
  description: Aggregate survey scores by question
  script: |
    var definitionId = '[definition_sys_id]';
    var startDate = gs.monthsAgoStart(3);
    var results = { survey: '', period: 'Last 3 months', total_responses: 0, questions: [] };

    var def = new GlideRecord('asmt_metric_definition');
    def.get(definitionId);
    results.survey = def.name.toString();

    // Count total responses
    var countGa = new GlideAggregate('asmt_assessment_instance');
    countGa.addQuery('metric_type', definitionId);
    countGa.addQuery('state', 'complete');
    countGa.addQuery('taken_on', '>=', startDate);
    countGa.addAggregate('COUNT');
    countGa.query();
    if (countGa.next()) results.total_responses = parseInt(countGa.getAggregate('COUNT'));

    // Get questions
    var metrics = new GlideRecord('asmt_metric');
    metrics.addQuery('metric_definition', definitionId);
    metrics.addQuery('active', true);
    metrics.orderBy('order');
    metrics.query();

    while (metrics.next()) {
      var question = {
        name: metrics.name.toString(),
        question_text: metrics.question.toString(),
        responses: 0,
        avg_score: 0,
        min_score: 999,
        max_score: 0,
        distribution: {}
      };

      var qa = new GlideAggregate('asmt_assessment_instance_question');
      qa.addQuery('metric', metrics.sys_id);
      qa.addQuery('instance.state', 'complete');
      qa.addQuery('instance.taken_on', '>=', startDate);
      qa.addAggregate('AVG', 'value');
      qa.addAggregate('MIN', 'value');
      qa.addAggregate('MAX', 'value');
      qa.addAggregate('COUNT');
      qa.query();

      if (qa.next()) {
        question.responses = parseInt(qa.getAggregate('COUNT'));
        question.avg_score = parseFloat(qa.getAggregate('AVG', 'value')).toFixed(2);
        question.min_score = parseFloat(qa.getAggregate('MIN', 'value'));
        question.max_score = parseFloat(qa.getAggregate('MAX', 'value'));
      }

      // Score distribution
      var dist = new GlideAggregate('asmt_assessment_instance_question');
      dist.addQuery('metric', metrics.sys_id);
      dist.addQuery('instance.state', 'complete');
      dist.addQuery('instance.taken_on', '>=', startDate);
      dist.addAggregate('COUNT');
      dist.groupBy('value');
      dist.query();

      while (dist.next()) {
        question.distribution[dist.value.toString()] = parseInt(dist.getAggregate('COUNT'));
      }

      results.questions.push(question);
    }

    gs.info(JSON.stringify(results, null, 2));

Step 4: Identify Trends Across Periods

Compare survey results across time periods to detect improvements or degradation.

Using MCP:

Tool: SN-Execute-Background-Script
Parameters:
  description: Compare survey scores across monthly periods
  script: |
    var definitionId = '[definition_sys_id]';
    var trends = { survey: '', monthly_scores: [] };

    var def = new GlideRecord('asmt_metric_definition');
    def.get(definitionId);
    trends.survey = def.name.toString();

    for (var i = 5; i >= 0; i--) {
      var monthStart = gs.monthsAgoStart(i);
      var monthEnd = gs.monthsAgoEnd(i);

      var ga = new GlideAggregate('asmt_assessment_instance');
      ga.addQuery('metric_type', definitionId);
      ga.addQuery('state', 'complete');
      ga.addQuery('taken_on', '>=', monthStart);
      ga.addQuery('taken_on', '<=', monthEnd);
      ga.addAggregate('AVG', 'percent');
      ga.addAggregate('COUNT');
      ga.query();

      var monthData = {
        period: new GlideDateTime(monthStart).getMonthLocalTime() + '/' + new GlideDateTime(monthStart).getYearLocalTime(),
        avg_score: 0,
        response_count: 0
      };

      if (ga.next()) {
        monthData.avg_score = parseFloat(ga.getAggregate('AVG', 'percent')).toFixed(1);
        monthData.response_count = parseInt(ga.getAggregate('COUNT'));
      }

      trends.monthly_scores.push(monthData);
    }

    // Calculate trend direction
    var scores = trends.monthly_scores.filter(function(m) { return m.response_count > 0; });
    if (scores.length >= 2) {
      var latest = parseFloat(scores[scores.length - 1].avg_score);
      var previous = parseFloat(scores[scores.length - 2].avg_score);
      trends.trend_direction = latest > previous ? 'Improving' : latest < previous ? 'Declining' : 'Stable';
      trends.change_percentage = ((latest - previous) / previous * 100).toFixed(1) + '%';
    }

    gs.info(JSON.stringify(trends, null, 2));

Step 5: Segment by Department or Group

Break down results by organizational dimension for targeted insights.

Using MCP:

Tool: SN-Execute-Background-Script
Parameters:
  description: Segment survey results by department
  script: |
    var definitionId = '[definition_sys_id]';
    var segments = [];

    var ga = new GlideAggregate('asmt_assessment_instance');
    ga.addQuery('metric_type', definitionId);
    ga.addQuery('state', 'complete');
    ga.addQuery('taken_on', '>=', gs.monthsAgoStart(3));
    ga.addAggregate('AVG', 'percent');
    ga.addAggregate('COUNT');
    ga.groupBy('user.department');
    ga.orderByAggregate('AVG', 'percent');
    ga.query();

    while (ga.next()) {
      segments.push({
        department: ga.user.department.getDisplayValue() || 'Unknown',
        avg_score: parseFloat(ga.getAggregate('AVG', 'percent')).toFixed(1),
        response_count: parseInt(ga.getAggregate('COUNT'))
      });
    }

    gs.info(JSON.stringify(segments, null, 2));

Step 6: Analyze Free-Text Responses

Extract themes from open-ended survey responses.

Using MCP:

Tool: SN-Query-Table
Parameters:
  table_name: asmt_assessment_instance_question
  query: instance.metric_type=[definition_sys_id]^metric.datatype=string^string_valueISNOTEMPTY^instance.taken_on>=javascript:gs.monthsAgoStart(3)
  fields: string_value,metric.name,instance.taken_on,instance.user.department
  limit: 100
  order_by: -instance.taken_on

Using REST API:

GET /api/now/table/asmt_assessment_instance_question?sysparm_query=instance.metric_type=[definition_sys_id]^metric.datatype=string^string_valueISNOTEMPTY^instance.taken_on>=javascript:gs.monthsAgoStart(3)&sysparm_fields=string_value,metric.name,instance.taken_on,instance.user.department&sysparm_limit=100&sysparm_display_value=true

Step 7: Generate Recommendations Report

Compile findings into an actionable report.

Using MCP:

Tool: SN-Add-Work-Notes
Parameters:
  table_name: asmt_metric_definition
  sys_id: [definition_sys_id]
  work_notes: |
    === SURVEY ANALYSIS REPORT ===
    Survey: IT Service Satisfaction Q1 2026
    Period: January - March 2026
    Total Responses: 342

    OVERALL SCORE: 78.4% (Previous quarter: 74.2%, +5.7%)

    QUESTION BREAKDOWN:
    1. Response Time Satisfaction: 72.3% (Low - needs attention)
    2. Resolution Quality: 85.1% (Good)
    3. Communication Clarity: 81.7% (Good)
    4. Overall Experience: 74.5% (Below target of 80%)

    DEPARTMENT SEGMENTS:
    - Engineering: 82.1% (Highest)
    - Sales: 71.3% (Lowest - declined 8% from Q4)
    - Marketing: 78.9% (Stable)
    - Finance: 76.2% (Improved +4%)

    KEY THEMES FROM COMMENTS:
    - Positive: Knowledge base improvements noted (23 mentions)
    - Negative: Long wait times for priority 3 tickets (31 mentions)
    - Negative: Inconsistent updates during resolution (18 mentions)

    RECOMMENDATIONS:
    1. Focus on P3 response times for Sales department (dedicated queue recommended)
    2. Implement automated status updates every 4 hours for open tickets
    3. Continue knowledge base investment (showing positive ROI)
    4. Schedule targeted follow-up survey for Sales department

    TREND: Improving (+5.7% QoQ)
    RISK: Sales department declining - escalate to VP Sales

Tool Usage

MCP Tools Reference

Tool When to Use
SN-Query-Table Query survey definitions, instances, questions, and responses
SN-Get-Record Retrieve specific survey or assessment details
SN-Natural-Language-Search Find surveys by keyword or description
SN-Execute-Background-Script Complex aggregations, trend analysis, segmentation
SN-Add-Work-Notes Post analysis reports to survey or assessment records

REST API Reference

Endpoint Method Purpose
/api/now/table/asmt_metric_definition GET Query survey/assessment definitions
/api/now/table/asmt_metric GET Retrieve survey questions and metrics
/api/now/table/asmt_assessment_instance GET Query completed survey instances
/api/now/table/asmt_assessment_instance_question GET Get individual question responses
/api/now/table/survey_response GET Access legacy survey response data
/api/now/table/asmt_metric_result GET Query pre-aggregated metric results

Best Practices

  • Set minimum response thresholds: Do not draw conclusions from segments with fewer than 10 responses
  • Use percentage scores for comparison: Raw scores vary by scale; normalize to percentages for cross-survey comparison
  • Include response rates: Low response rates may indicate survey fatigue or distribution issues
  • Segment meaningfully: Break down by dimensions that align with organizational accountability (department, region, support group)
  • Track trends over 3+ periods: Single-period analysis is less reliable than multi-period trend data
  • Weight questions appropriately: Not all questions are equally important; consider weighted averages for composite scores
  • Act on results: Every analysis should produce at least one actionable recommendation with a clear owner
  • Close the loop: Follow up on previous recommendations in subsequent survey analyses to track improvement

Troubleshooting

No Assessment Instances Found

Cause: Assessment definition sys_id is incorrect, or no instances are in "complete" state Solution: Query asmt_assessment_instance without the state filter to see all instances. Check if the definition uses a different state value (e.g., "closed" vs "complete").

Question Scores Showing Zero

Cause: The value field in asmt_assessment_instance_question may not be populated; some assessments store results in string_value or scaled_value Solution: Check the question datatype field and query the appropriate value column. For scaled questions, use scaled_value instead of value.

Department Segmentation Returns "Unknown"

Cause: Survey respondents' user records do not have the department field populated Solution: Try alternative grouping fields such as user.company, user.location, or user.cost_center.

Historical Data Missing for Trend Analysis

Cause: Assessment instances may be archived or the survey was recently created Solution: Extend the date range or check if the instance uses table rotation. For new surveys, note that trends require at least 2-3 periods of data.

Examples

Example 1: CSAT Score Dashboard

Input: "Analyze customer satisfaction survey results for Q1 2026"

Process: Query assessment instances for the CSAT survey, aggregate by question, segment by support group, compare with Q4 2025, and generate a dashboard-ready summary.

Example 2: Employee Engagement Trend

Input: "Show me the trend for employee engagement scores over the last 6 months"

# Run the trend analysis from Step 4 with definitionId for employee engagement survey
# Output: Monthly scores with trend direction and percentage change

Example 3: Low-Score Investigation

Input: "Why did satisfaction scores drop in the Sales department?"

# 1. Segment by department (Step 5) to confirm the drop
# 2. Drill into question-level scores for Sales respondents
# 3. Extract free-text responses from Sales (Step 6)
# 4. Cross-reference with incident/request data for Sales during the period
# 5. Generate targeted recommendations

Related Skills

  • reporting/trend-analysis - General trend analysis across ServiceNow data
  • reporting/executive-dashboard - Build executive summary dashboards
  • reporting/sla-analysis - Correlate survey scores with SLA performance
  • csm/sentiment-analysis - Sentiment analysis for customer feedback
  • hrsd/sentiment-analysis - Employee sentiment analysis