How to Build a Customer Sentiment Analysis for Tickets
Analyze ticket sentiment to prioritize frustrated customers automatically.
Jay Banlasan
The AI Systems Guy
Customer sentiment analysis on support tickets using ai catches frustrated customers before they churn. I build these as a layer on top of the ticket classification system. Every incoming message gets a sentiment score, and anything trending negative gets flagged for immediate attention.
The real value is tracking sentiment across a conversation, not just one message. A customer who starts calm and gets angrier with each reply is a different problem than someone who opens angry but calms down.
What You Need Before Starting
- A ticketing system with conversation history
- Python 3.8+ with the Anthropic SDK
- A database for sentiment tracking
- Slack or alerting system for escalations
Step 1: Score Individual Messages
import anthropic
import json
client = anthropic.Anthropic()
def analyze_sentiment(text):
response = client.messages.create(
model="claude-sonnet-4-20250514",
max_tokens=100,
messages=[{
"role": "user",
"content": f"""Analyze the sentiment of this customer support message.
Message: {text}
Respond with ONLY this JSON:
{{"score": 0.0, "label": "neutral", "indicators": ["specific phrases that indicate sentiment"]}}
Score range: -1.0 (very negative) to 1.0 (very positive).
Labels: very_negative, negative, neutral, positive, very_positive"""
}]
)
return json.loads(response.content[0].text)
Step 2: Track Sentiment Over a Conversation
import sqlite3
def track_conversation_sentiment(ticket_id, message_text, message_number):
sentiment = analyze_sentiment(message_text)
conn = sqlite3.connect("sentiment.db")
conn.execute("""
INSERT INTO sentiment_log (ticket_id, message_number, score, label, indicators, analyzed_at)
VALUES (?, ?, ?, ?, ?, datetime('now'))
""", (ticket_id, message_number, sentiment["score"], sentiment["label"], json.dumps(sentiment["indicators"])))
conn.commit()
return sentiment
Step 3: Detect Sentiment Trends
The trend matters more than any single score:
def get_sentiment_trend(ticket_id):
conn = sqlite3.connect("sentiment.db")
scores = conn.execute(
"SELECT score FROM sentiment_log WHERE ticket_id = ? ORDER BY message_number",
(ticket_id,)
).fetchall()
if len(scores) < 2:
return {"trend": "stable", "direction": 0}
recent = [s[0] for s in scores[-3:]]
earlier = [s[0] for s in scores[:3]]
avg_recent = sum(recent) / len(recent)
avg_earlier = sum(earlier) / len(earlier)
direction = avg_recent - avg_earlier
if direction < -0.3:
trend = "declining"
elif direction > 0.3:
trend = "improving"
else:
trend = "stable"
return {"trend": trend, "direction": round(direction, 2), "current_avg": round(avg_recent, 2)}
Step 4: Trigger Escalation on Negative Trends
def check_escalation_needed(ticket_id):
trend = get_sentiment_trend(ticket_id)
if trend["trend"] == "declining" and trend["current_avg"] < -0.5:
escalate_ticket(ticket_id, reason="sentiment_declining")
return True
conn = sqlite3.connect("sentiment.db")
last_score = conn.execute(
"SELECT score FROM sentiment_log WHERE ticket_id = ? ORDER BY message_number DESC LIMIT 1",
(ticket_id,)
).fetchone()
if last_score and last_score[0] < -0.7:
escalate_ticket(ticket_id, reason="very_negative_message")
return True
return False
Step 5: Build a Sentiment Dashboard
Aggregate sentiment data for team-level insights:
def get_sentiment_dashboard(days=7):
conn = sqlite3.connect("sentiment.db")
from datetime import datetime, timedelta
start = (datetime.now() - timedelta(days=days)).isoformat()
avg = conn.execute(
"SELECT AVG(score) FROM sentiment_log WHERE analyzed_at > ?", (start,)
).fetchone()[0]
negative_count = conn.execute(
"SELECT COUNT(DISTINCT ticket_id) FROM sentiment_log WHERE score < -0.5 AND analyzed_at > ?", (start,)
).fetchone()[0]
declining = conn.execute("""
SELECT ticket_id FROM sentiment_log WHERE analyzed_at > ?
GROUP BY ticket_id HAVING COUNT(*) > 2
AND AVG(CASE WHEN message_number > 2 THEN score END) < AVG(CASE WHEN message_number <= 2 THEN score END) - 0.3
""", (start,)).fetchall()
return {
"avg_sentiment": round(avg or 0, 2),
"negative_tickets": negative_count,
"declining_conversations": len(declining)
}
What to Build Next
Correlate sentiment data with resolution outcomes. Find out which agent responses improve sentiment and which make it worse. That data becomes training material for your support team.
Related Reading
- AI in Customer Service - sentiment analysis as a support intelligence layer
- The Feedback Loop That Powers Everything - how sentiment data feeds back into support quality
- The Measurement Framework That Actually Works - measuring customer happiness beyond CSAT scores
Want this system built for your business?
Get a free assessment. We will map every system your business needs and show you the ROI.
Get Your Free Assessment