Getting CSAT survey responses
Customer Satisfaction (CSAT) surveys offer insights into your end users’ support experiences by encouraging them to quickly rate their resolved tickets, helping you gather feedback to improve your service.
This article describes how to retrieve CSAT survey responses using the List Survey Responses endpoint.
If you are using the legacy CSAT option, you must deactivate the legacy CSAT and manually deactivate any custom CSAT automations and triggers before you can activate the updated CSAT option. You can have only one CSAT option activated at a time.
Note: CSAT survey responses are available on the Support Professional plan and above, and the Zendesk Suite Growth plan and above.
Using the List Survey Responses endpoint
The List Survey Responses endpoint retrieves information about all customer survey responses. It is not limited to any specific ticket as described in Getting the CSAT ratings of tickets. Example:
{
"survey_responses": [
{
"id": "01JH6AK11ZG44KKFNZ3B07T6A5",
"expires_at": "2025-02-06T20:02:45.439Z",
"responder_id": "28431426615831",
"subject_zrns": [
"zen:ticket:362",
"zen:request:362"
],
"subjects": [
{
"id": "362",
"type": "ticket",
"zrn": "zen:ticket:362"
},
{
"id": "362",
"type": "request",
"zrn": "zen:request:362"
}
],
"survey": {
"id": "01J9SGDYMNQ6JP4PS1VJDQAKM6",
"version": 4,
"state": "enabled"
},
"answers": [
{
"type": "rating_scale",
"rating": 1,
"rating_category": "bad",
"question": {
"type": "rating_scale_numeric",
"sub_type": "customer_satisfaction",
"id": "01J9SGDW8FWZD5Z2CRZBZJRP2E"
},
"created_at": "2025-01-09T20:30:08.609Z",
"updated_at": "2025-01-09T20:30:08.609Z"
}
]
},
...
],
"meta": {
"has_more": false,
"after_cursor": "01JH6AK0V64VDDAF8S65G4AEV7",
"before_cursor": "01JH6AK11ZG44KKFNZ3B07T6A5"
}
}
Example list survey responses script
The following Python script retrieves CSAT survey responses by performing the following steps:
- Fetch all survey responses submitted since a specified date.
- Extract and group survey answers based on their rating categories, such as "bad", "neutral", or "good".
- Display the total number of survey responses and detailed ratings for each category.
Requirements
Disclamer
Zendesk provides this example script for instructional purposes only. Zendesk doesn't provide support for the example code. Zendesk doesn't support third-party technologies such as Python or command-line tools.
Sample script
Run python get_survey_responses.py
on the command line.
File name: get_survey_responses.py
import os
import requests
import arrow
# Load Zendesk API credentials and subdomain from environment variables
ZENDESK_API_TOKEN = os.getenv('ZENDESK_API_TOKEN')
ZENDESK_USER_EMAIL = os.getenv('ZENDESK_USER_EMAIL')
ZENDESK_SUBDOMAIN = os.getenv('ZENDESK_SUBDOMAIN')
# Exit if required environment variables are missing
if not all([ZENDESK_API_TOKEN, ZENDESK_USER_EMAIL, ZENDESK_SUBDOMAIN]):
print('Error: Missing required environment variables.')
exit(1)
# Base URL for fetching survey responses
API_URL = f'https://{ZENDESK_SUBDOMAIN}.zendesk.com/api/v2/guide/survey_responses'
# Set up HTTP Basic Authentication
AUTH = f'{ZENDESK_USER_EMAIL}/token', ZENDESK_API_TOKEN
def fetch_survey_responses(start_date=None):
"""
Fetch survey responses filtered from start_date onward, translating start_date into epoch time.
"""
params = {}
if start_date:
epoch_start = arrow.get(start_date, 'MM-DD-YYYY').timestamp()
if epoch_start is None:
return None
params['filter[created_at_start]'] = int(epoch_start)
try:
response = requests.get(API_URL, auth=AUTH, params=params)
response.raise_for_status() # Raise error for bad responses
return response.json()
except requests.RequestException as e:
print(f"Error fetching data: {e}")
return None
def find_all_ratings_grouped_by_category(survey_responses):
"""
Parse survey response and group ratings by their category.
"""
grouped = {}
for response in survey_responses:
survey_id = response['survey']['id']
ticket_id = None
for subj in response['subjects']:
# Look for the ticket id associated with the response
if subj['type'] == 'ticket':
ticket_id = subj['id']
break
for answer in response['answers']:
rating_category = answer['rating_category'].lower() or "undefined"
rating = answer['rating']
question_type = answer['question']['type']
entry = {
"rating": rating,
"rating_category": rating_category,
"question_type": question_type,
"survey_id": survey_id,
"ticket_id": ticket_id,
}
if rating_category not in grouped:
grouped[rating_category] = [entry]
else:
grouped[rating_category].append(entry)
return grouped
def main():
# Define the start date for filtering survey responses (MM-DD-YYYY)
start_date = "01-01-2024"
# Fetch responses starting at the specified date
data = fetch_survey_responses(start_date)
if data is None:
print("No data fetched.")
return
survey_responses = data['survey_responses']
if not survey_responses:
print("No survey responses found.")
return
# Print total number of survey responses found
print(f"Total survey responses found since {start_date}: {len(survey_responses)}")
# Group ratings by category
grouped_ratings = find_all_ratings_grouped_by_category(survey_responses)
# Display grouped results or message if no ratings found
if grouped_ratings:
for category, entries in grouped_ratings.items():
print(f"\nRating category: '{category}' ({len(entries)} entries)")
for item in entries:
print(item)
else:
print("No rating answers found in survey responses.")
if __name__ == "__main__":
main()
Example output
Total survey responses found since 01-01-2024: 4
Rating category: 'bad' (3 entries)
{'rating': 1, 'rating_category': 'bad', 'question_type': 'rating_scale_numeric', 'survey_id': '01J9SGDYMNQ6JP4PS1VJDQAKM6', 'ticket_id': '362'}
{'rating': 1, 'rating_category': 'bad', 'question_type': 'rating_scale_numeric', 'survey_id': '01J9SGDYMNQ6JP4PS1VJDQAKM6', 'ticket_id': '370'}
{'rating': 1, 'rating_category': 'bad', 'question_type': 'rating_scale_numeric', 'survey_id': '01J9SGDYMNQ6JP4PS1VJDQAKM6', 'ticket_id': '396'}
Rating category: 'neutral' (1 entries)
{'rating': 2, 'rating_category': 'neutral', 'question_type': 'rating_scale_numeric', 'survey_id': '01J9SGDYMNQ6JP4PS1VJDQAKM6', 'ticket_id': '365'}