Systems Library / Customer Service / How to Build a Review Sentiment Analysis Dashboard
Customer Service review management

How to Build a Review Sentiment Analysis Dashboard

Analyze review sentiment trends to identify improvement areas.

Jay Banlasan

Jay Banlasan

The AI Systems Guy

A review sentiment analysis dashboard for your business shows you exactly what customers love and hate, broken down by topic. I build these because star ratings alone are useless for improvement. A 3-star review could mean "great food, terrible service" or "great service, terrible food." Sentiment analysis breaks it apart.

The dashboard tracks sentiment by category over time so you can see if changes you make actually move the needle.

What You Need Before Starting

Step 1: Analyze Review Sentiment by Category

import anthropic
import json

client = anthropic.Anthropic()

def analyze_review(review_text):
    response = client.messages.create(
        model="claude-sonnet-4-20250514",
        max_tokens=200,
        messages=[{
            "role": "user",
            "content": f"""Analyze this review. Extract sentiment for each mentioned category.

Review: {review_text}

Respond with ONLY this JSON:
{{
  "overall_sentiment": 0.7,
  "categories": [
    {{"name": "category name", "sentiment": 0.8, "keywords": ["specific", "phrases"]}},
  ]
}}

Sentiment scale: -1.0 (very negative) to 1.0 (very positive).
Common categories: product quality, customer service, pricing, shipping, ease of use, atmosphere."""
        }]
    )
    return json.loads(response.content[0].text)

Step 2: Store Analyzed Data

import sqlite3

def store_analysis(review_id, analysis):
    conn = sqlite3.connect("sentiment_dashboard.db")

    conn.execute("""
        INSERT OR REPLACE INTO review_sentiment (review_id, overall_score, analyzed_at)
        VALUES (?, ?, datetime('now'))
    """, (review_id, analysis["overall_sentiment"]))

    for cat in analysis["categories"]:
        conn.execute("""
            INSERT INTO category_sentiment (review_id, category, score, keywords)
            VALUES (?, ?, ?, ?)
        """, (review_id, cat["name"], cat["sentiment"], json.dumps(cat["keywords"])))

    conn.commit()

Step 3: Build Trend Queries

def get_category_trends(category, days=90):
    conn = sqlite3.connect("sentiment_dashboard.db")
    rows = conn.execute("""
        SELECT DATE(r.created_at) as date, AVG(cs.score) as avg_score, COUNT(*) as count
        FROM category_sentiment cs
        JOIN reviews r ON cs.review_id = r.id
        WHERE cs.category = ? AND r.created_at > datetime('now', ?)
        GROUP BY DATE(r.created_at)
        ORDER BY date
    """, (category, f"-{days} days")).fetchall()

    return [{"date": r[0], "avg_score": round(r[1], 2), "count": r[2]} for r in rows]

def get_category_summary(days=30):
    conn = sqlite3.connect("sentiment_dashboard.db")
    rows = conn.execute("""
        SELECT category, AVG(score) as avg, COUNT(*) as mentions,
               SUM(CASE WHEN score > 0.3 THEN 1 ELSE 0 END) as positive,
               SUM(CASE WHEN score < -0.3 THEN 1 ELSE 0 END) as negative
        FROM category_sentiment cs
        JOIN reviews r ON cs.review_id = r.id
        WHERE r.created_at > datetime('now', ?)
        GROUP BY category
        ORDER BY mentions DESC
    """, (f"-{days} days",)).fetchall()

    return [{
        "category": r[0], "avg_sentiment": round(r[1], 2),
        "mentions": r[2], "positive": r[3], "negative": r[4]
    } for r in rows]

Step 4: Serve the Dashboard API

from flask import Flask, jsonify

app = Flask(__name__)

@app.route("/api/dashboard/summary")
def dashboard_summary():
    return jsonify({
        "categories": get_category_summary(days=30),
        "overall_trend": get_overall_trend(days=90),
        "worst_categories": get_worst_categories(days=30, limit=3)
    })

@app.route("/api/dashboard/category/<category>")
def category_detail(category):
    return jsonify({
        "trend": get_category_trends(category, days=90),
        "recent_reviews": get_recent_reviews_for_category(category, limit=10),
        "common_complaints": get_top_keywords(category, sentiment="negative"),
        "common_praise": get_top_keywords(category, sentiment="positive")
    })

Step 5: Generate Actionable Insights

Use AI to turn data into recommendations:

def generate_insights(summary_data):
    response = client.messages.create(
        model="claude-sonnet-4-20250514",
        max_tokens=300,
        messages=[{
            "role": "user",
            "content": f"""Based on this review sentiment data, provide 3 specific, actionable recommendations.
Focus on the categories with the most negative sentiment or declining trends.

Data: {json.dumps(summary_data)}

Format each recommendation as: What to fix, Why it matters (with numbers), Suggested action."""
        }]
    )
    return response.content[0].text

What to Build Next

Add location-level breakdowns for multi-location businesses. The same brand can have completely different sentiment profiles at different locations. Location-level dashboards help managers focus on their specific issues.

Related Reading

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

Related Systems