Mathew K Analytics

Lesson 57 · Social Media Content Analytics

Designing Content Analytics Dashboards

In this lesson, we learn how to analyze real social media and content performance data. We focus on designing analytics dashboards for creators or brands to…

⬇ Download notebookOpen in Colab ↗

What you'll learn

Data

No separate download needed — the notebook creates or downloads everything it uses.

📓 Full notebook

Download .ipynb

Designing Content Analytics Dashboards#

  • In this lesson, we learn how to analyze real social media and content performance data.
  • We focus on designing analytics dashboards for creators or brands to monitor their content success.
  • Understanding engagement metrics helps optimize strategies across YouTube and other platforms.
  • By the end, you will be able to build insights and visualization tools for social media datasets.
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import warnings
warnings.filterwarnings('ignore')

Core Content Analytics Concepts#

  • Social media datasets often include posts (videos, reels, or photos) and engagement metrics.
  • Metrics such as views, likes, comments, shares, CTR, and watch time reflect how content performs.
  • Engagement rate measures the ratio of audience interaction to post reach or views.
  • Beginners often mistake high view counts for good engagement, but true insight comes from combined metrics.
  • Always check for missing values and group calculations correctly when benchmarking content.
# Example 1: Load Social Media Content Dataset (cross-platform posts)
np.random.seed(42)
n_posts = 500
views = np.random.randint(100, 100000, n_posts)
df_content = pd.DataFrame({
    'post_id': range(1, n_posts+1),
    'platform': np.random.choice(['YouTube','Instagram','TikTok'], n_posts),
    'date': pd.date_range('2023-01-01', periods=n_posts, freq='6h'),
    'views': views,
    'likes': (views * np.random.uniform(0.02, 0.15, n_posts)).astype(int),
    'comments': (views * np.random.uniform(0.001, 0.05, n_posts)).astype(int),
    'shares': (views * np.random.uniform(0.001, 0.03, n_posts)).astype(int)
})
print(df_content.shape)
print(df_content.head(3))
(500, 7)
   post_id   platform                date  views  likes  comments  shares
0        1  Instagram 2023-01-01 00:00:00  15895   2356       116     253
1        2  Instagram 2023-01-01 06:00:00    960     94        16      26
2        3  Instagram 2023-01-01 12:00:00  76920   3910      2879    1185
# Example 2: Load YouTube Analytics Dataset (video-level metrics)
np.random.seed(42)
n_videos = 300
views_yta = np.random.randint(100, 500000, n_videos)
df_yt = pd.DataFrame({
    'video_id': range(1, n_videos+1),
    'publish_date': pd.date_range('2022-01-01', periods=n_videos, freq='D'),
    'views': views_yta,
    'watch_time': np.random.randint(1000, 500000, n_videos),
    'likes': (views_yta * np.random.uniform(0.01, 0.08, n_videos)).astype(int),
    'comments': (views_yta * np.random.uniform(0.001, 0.02, n_videos)).astype(int),
    'ctr': np.round(np.random.uniform(2, 10, n_videos), 2)
})
print(df_yt.shape)
print(df_yt.head(3))
(300, 7)
   video_id publish_date   views  watch_time  likes  comments   ctr
0         1   2022-01-01  122058      158381   1890      1975  4.14
1         2   2022-01-02  146967      481671   1730      1900  6.99
2         3   2022-01-03  132032      195806  10217       337  5.28
# Beginner Example 1: Calculate simple engagement rate (likes/views) for all posts
df_content['engagement_rate'] = np.round(df_content['likes'] / df_content['views'] * 100, 2)
print(df_content[['platform', 'likes', 'views', 'engagement_rate']].head(5))
    platform  likes  views  engagement_rate
0  Instagram   2356  15895            14.82
1  Instagram     94    960             9.79
2  Instagram   3910  76920             5.08
3    YouTube   1827  54986             3.32
4  Instagram    253   6365             3.97
# Beginner Example 2: Find posts with highest engagement rate
top_eng_posts = df_content.sort_values('engagement_rate', ascending=False).head(5)
print(top_eng_posts[['platform', 'date', 'views', 'likes', 'engagement_rate']])
      platform                date  views  likes  engagement_rate
393     TikTok 2023-04-09 06:00:00  45117   6755            14.97
186     TikTok 2023-02-16 12:00:00   9574   1432            14.96
443     TikTok 2023-04-21 18:00:00  54121   8082            14.93
427  Instagram 2023-04-17 18:00:00  55709   8292            14.88
44     YouTube 2023-01-12 00:00:00  87413  12997            14.87
# Beginner Example 3: Basic content volume chart by platform
ax = df_content['platform'].value_counts().plot(kind='bar', color=['red','mediumvioletred','orange'])
plt.title('Content Volume by Platform')
plt.ylabel('Number of Posts')
plt.xlabel('Platform')
plt.tight_layout()
plt.show()
No description has been provided for this image
# Intermediate Example 1: Analyze average engagement rate over time
df_content['date_day'] = df_content['date'].dt.date
daily_eng = df_content.groupby('date_day')['engagement_rate'].mean()
plt.figure(figsize=(10,4))
daily_eng.plot()
plt.title('Average Engagement Rate Over Time')
plt.ylabel('Engagement Rate (%)')
plt.xlabel('Date')
plt.tight_layout()
plt.show()
No description has been provided for this image
# Intermediate Example 2: Top 5 days with most viral content (high shares)
viral_days = df_content.groupby('date_day')['shares'].sum().sort_values(ascending=False).head(5)
print(viral_days)
date_day
2023-04-14    6973
2023-02-18    6838
2023-01-07    6416
2023-04-25    6006
2023-02-11    5881
Name: shares, dtype: int64
# Intermediate Example 3: Calculating total and average YouTube metrics by month
df_yt['month'] = df_yt['publish_date'].dt.to_period('M')
monthly_stats = df_yt.groupby('month')[['views', 'likes', 'comments', 'watch_time', 'ctr']].agg(['sum', 'mean'])
print(monthly_stats.head(3))
           views                  likes               comments               \
             sum           mean     sum          mean      sum         mean   
month                                                                         
2022-01  6874384  221754.322581  306179   9876.741935    65504  2113.032258   
2022-02  7131717  254704.178571  324030  11572.500000    65978  2356.357143   
2022-03  8200910  264545.483871  356977  11515.387097    80472  2595.870968   

        watch_time                    ctr            
               sum           mean     sum      mean  
month                                                
2022-01    7489210  241587.419355  182.16  5.876129  
2022-02    6819577  243556.321429  158.87  5.673929  
2022-03    7839899  252899.967742  179.79  5.799677  
# Intermediate Example 4: Correlation heatmap of YouTube metrics
plt.figure(figsize=(8,6))
corr = df_yt[['views', 'likes', 'comments', 'watch_time', 'ctr']].corr()
sns.heatmap(corr, annot=True, cmap='coolwarm', fmt='.2f')
plt.title('Correlation Heatmap of YouTube Video Metrics')
plt.tight_layout()
plt.show()
No description has been provided for this image
# Intermediate Example 5: Identify YouTube videos above 90th percentile for both views and CTR
views_cutoff = df_yt['views'].quantile(0.9)
ctr_cutoff = df_yt['ctr'].quantile(0.9)
viral_videos = df_yt[(df_yt['views'] >= views_cutoff) & (df_yt['ctr'] >= ctr_cutoff)]
print('Number of ultra-viral videos:', len(viral_videos))
print(viral_videos[['video_id', 'publish_date', 'views', 'ctr']])
Number of ultra-viral videos: 7
     video_id publish_date   views   ctr
60         61   2022-03-02  489592  9.49
87         88   2022-03-29  460437  9.60
112       113   2022-04-23  483105  9.77
141       142   2022-05-22  480854  9.51
173       174   2022-06-23  491334  9.56
260       261   2022-09-18  459515  9.85
286       287   2022-10-14  496357  9.75
# Advanced Example 1: Platform engagement benchmarking (boxplot comparison)
plt.figure(figsize=(8,6))
sns.boxplot(x='platform', y='engagement_rate', data=df_content, palette='Set2')
plt.title('Engagement Rate Distribution by Platform')
plt.ylabel('Engagement Rate (%)')
plt.xlabel('Platform')
plt.tight_layout()
plt.show()
No description has been provided for this image
# Advanced Example 2: Identify underperforming dates (low overall engagement)
low_eng = daily_eng.nsmallest(5)
print('Bottom engagement days:')
print(low_eng)
Bottom engagement days:
date_day
2023-01-11    3.9025
2023-01-02    4.4200
2023-04-13    4.7875
2023-03-10    5.2100
2023-03-16    5.3550
Name: engagement_rate, dtype: float64
# Advanced Example 3: Rolling average analysis for engagement trends
df_content['rolling_engagement_7d'] = df_content.sort_values('date')['engagement_rate'].rolling(28).mean()
plt.figure(figsize=(10,4))
plt.plot(df_content['date'], df_content['rolling_engagement_7d'], label='28-Post Rolling Average')
plt.title('Rolling Average Engagement Rate (28 posts)')
plt.ylabel('Engagement Rate (%)')
plt.xlabel('Date')
plt.legend()
plt.tight_layout()
plt.show()
No description has been provided for this image
# Advanced Example 4: Content category performance - group by platform and engagement
platform_perf = df_content.groupby('platform')['engagement_rate'].agg(['mean', 'median', 'std', 'count'])
print(platform_perf)
               mean  median       std  count
platform                                    
Instagram  8.990802   9.025  3.962953    162
TikTok     8.629673   8.980  3.775052    153
YouTube    7.999892   7.860  3.630118    185
# Error Example 1: Handle missing likes values (simulate by corrupting some rows)
df_error = df_content.copy()
df_error.loc[df_error.sample(frac=0.03, random_state=42).index, 'likes'] = np.nan
missing_likes = df_error['likes'].isna().sum()
print(f'Missing values in likes: {missing_likes}')
df_error['likes_filled'] = df_error['likes'].fillna(df_error['likes'].median())
Missing values in likes: 15
# Error Example 2: Incorrect aggregation (sum of engagement rate)
wrong_agg = df_content.groupby('platform')['engagement_rate'].sum()
right_agg = df_content.groupby('platform').apply(lambda d: d['likes'].sum() / d['views'].sum() * 100)
print('Incorrect sum:', wrong_agg.head(3))
print('Correct engagement %:', right_agg.head(3))
Incorrect sum: platform
Instagram    1456.51
TikTok       1320.34
YouTube      1479.98
Name: engagement_rate, dtype: float64
Correct engagement %: platform
Instagram    8.914476
TikTok       8.945359
YouTube      8.140516
dtype: float64
# Error Example 3: Misinterpreting CTR (Click-Through Rate)
avg_ctr = df_yt['ctr'].mean()
print(f'Average CTR across all YouTube videos: {avg_ctr:.2f}%')
low_ctr_videos = df_yt[df_yt['ctr'] < 3.0]
print(f'Videos with very low CTR (<3%):', len(low_ctr_videos))
Average CTR across all YouTube videos: 6.17%
Videos with very low CTR (<3%): 37
# Error Example 4: Grouping by wrong column (group by video_id instead of date)
wrong_group = df_yt.groupby('video_id')['views'].sum().head()
correct_group = df_yt.groupby(df_yt['publish_date'].dt.month)['views'].sum().head()
print('Sum by video_id:', wrong_group)
print('Sum by month:', correct_group)
Sum by video_id: video_id
1    122058
2    146967
3    132032
4    365938
5    259278
Name: views, dtype: int32
Sum by month: publish_date
1    6874384
2    7131717
3    8200910
4    7162344
5    7408411
Name: views, dtype: int32

Best Practices and Dashboard Patterns#

  • Always use consistent definitions for your main metrics (likes, engagement, CTR).
  • Benchmark your posts or videos against relevant groups (platform or season).
  • Use visualizations that match your audience: compare periods, slice by platform, or highlight outliers.
  • Review missing data and fill logically to protect dashboard accuracy.
  • Use rolling averages and group comparisons to monitor content growth.
  • Share dashboard views with your team or audience for insights-driven adjustments.
# End-to-End Example: Build a simple cross-platform analytics dashboard
summary = df_content.groupby('platform').agg({
    'views': 'sum',
    'likes': 'sum',
    'comments': 'sum',
    'shares': 'sum',
    'engagement_rate': 'mean'
})
plt.figure(figsize=(9,7))
summary[['views','likes','comments','shares']].plot(kind='bar', subplots=True, layout=(2,2), sharex=True, legend=False, figsize=(9,7))
plt.suptitle('Cross-Platform Content Engagement Dashboard')
plt.tight_layout(rect=[0,0,1,0.95])
plt.show()
print('Mean engagement rate by platform:')
print(summary['engagement_rate'])
<Figure size 900x700 with 0 Axes>
No description has been provided for this image
Mean engagement rate by platform:
platform
Instagram    8.990802
TikTok       8.629673
YouTube      7.999892
Name: engagement_rate, dtype: float64
# Strategy Recommendation: Choose the strongest platform and best post timing
best_platform = summary['engagement_rate'].idxmax()
busiest_times = df_content.groupby(df_content['date'].dt.hour)['engagement_rate'].mean().sort_values(ascending=False).head(3)
print(f'The platform with the highest avg engagement: {best_platform}')
print('The hours with highest engagement rates:')
print(busiest_times)
The platform with the highest avg engagement: Instagram
The hours with highest engagement rates:
date
12    9.00976
0     8.60056
18    8.42832
Name: engagement_rate, dtype: float64
# Export dashboard summary to CSV for sharing
summary.to_csv('dashboard_summary.csv')
# Draw a simple dashboard header as an image for reporting
import matplotlib.patches as mpatches
fig, ax = plt.subplots(figsize=(6,1))
ax.set_axis_off()
ax.text(0.5, 0.5, 'Social Media Content Analytics Dashboard',
        va='center', ha='center', fontsize=20, weight='bold', color='navy')
plt.savefig('dashboard_header.png', bbox_inches='tight', pad_inches=0.2)
plt.close(fig)

Practice & Next Steps#

  • Now you are ready to create your own content analytics dashboards using real or synthetic data.
  • Try building more advanced metrics or visualizations specific to your content niche.
  • Share your results with a teammate or community for fresh feedback.
  • Want deeper analytics? Subscribe to our YouTube channel for bonus walkthroughs.

Found this useful?

All lessons, notebooks and datasets here are free. If they helped you, a coffee keeps new lessons coming.