Social Media ROI Calculator: Measure What Actually Matters
"What's the ROI of social media?" is a question that's been asked for 15 years, and most teams still can't answer it. Not because ROI doesn't exist ā but because they're measuring the wrong things.
Here's how to build an ROI calculation system that connects social metrics to actual business outcomes.
The ROI Formula
Social Media ROI = (Revenue from Social - Cost of Social) / Cost of Social Ć 100
Simple formula. The hard part is measuring "Revenue from Social" ā which is why you need data, not guesses.
Build a Multi-Platform ROI Dashboard
Start by collecting the social metrics that actually tie to revenue:
const API_KEY = process.env.SOCIAVAULT_API_KEY;
const BASE = 'https://api.sociavault.com/v1/scrape';
const headers = { 'X-API-Key': API_KEY };
async function calculateSocialROI(config) {
const { accounts, monthlyCosts, monthlyRevenue } = config;
const metrics = {};
// Instagram
if (accounts.instagram) {
const profileRes = await fetch(
`${BASE}/instagram/profile?username=${encodeURIComponent(accounts.instagram)}`,
{ headers }
);
const profile = (await profileRes.json()).data;
const postsRes = await fetch(
`${BASE}/instagram/posts?username=${encodeURIComponent(accounts.instagram)}`,
{ headers }
);
const posts = (await postsRes.json()).data || [];
const followers = profile?.follower_count || 0;
const avgLikes = posts.length > 0
? Math.round(posts.reduce((s, p) => s + (p.like_count || 0), 0) / posts.length)
: 0;
const avgComments = posts.length > 0
? Math.round(posts.reduce((s, p) => s + (p.comment_count || 0), 0) / posts.length)
: 0;
metrics.instagram = {
followers,
avgLikes,
avgComments,
engRate: followers > 0 ? ((avgLikes + avgComments) / followers * 100) : 0,
estMonthlyImpressions: avgLikes * 12 * posts.length, // rough estimate
postCount: posts.length
};
await new Promise(r => setTimeout(r, 1200));
}
// TikTok
if (accounts.tiktok) {
const profileRes = await fetch(
`${BASE}/tiktok/profile?username=${encodeURIComponent(accounts.tiktok)}`,
{ headers }
);
const profile = (await profileRes.json()).data;
const postsRes = await fetch(
`${BASE}/tiktok/user/posts?username=${encodeURIComponent(accounts.tiktok)}`,
{ headers }
);
const videos = (await postsRes.json()).data || [];
const followers = profile?.stats?.followerCount || 0;
const totalViews = videos.reduce((s, v) => s + (v.stats?.playCount || 0), 0);
const avgViews = videos.length > 0 ? Math.round(totalViews / videos.length) : 0;
metrics.tiktok = {
followers,
totalViews,
avgViews,
videoCount: videos.length
};
await new Promise(r => setTimeout(r, 1200));
}
// Twitter
if (accounts.twitter) {
const profileRes = await fetch(
`${BASE}/twitter/profile?username=${encodeURIComponent(accounts.twitter)}`,
{ headers }
);
const profile = (await profileRes.json()).data;
const postsRes = await fetch(
`${BASE}/twitter/user-tweets?username=${encodeURIComponent(accounts.twitter)}`,
{ headers }
);
const tweets = (await postsRes.json()).data || [];
const followers = profile?.legacy?.followers_count || 0;
const avgLikes = tweets.length > 0
? Math.round(tweets.reduce((s, t) => s + (t.legacy?.favorite_count || 0), 0) / tweets.length)
: 0;
metrics.twitter = {
followers,
avgLikes,
tweetCount: tweets.length
};
await new Promise(r => setTimeout(r, 1200));
}
// Calculate ROI metrics
const totalFollowers = Object.values(metrics).reduce((s, m) => s + (m.followers || 0), 0);
const totalReach = (metrics.instagram?.estMonthlyImpressions || 0) + (metrics.tiktok?.totalViews || 0);
const totalCost = Object.values(monthlyCosts).reduce((s, c) => s + c, 0);
const roi = totalCost > 0 ? ((monthlyRevenue.social - totalCost) / totalCost * 100) : 0;
// Cost per metrics
const costPerFollower = totalFollowers > 0 ? (totalCost / totalFollowers) : 0;
const costPerEngagement = totalReach > 0 ? (totalCost / totalReach * 1000) : 0;
const revenuePerFollower = totalFollowers > 0 ? (monthlyRevenue.social / totalFollowers) : 0;
console.log('\nš Social Media ROI Dashboard');
console.log('ā'.repeat(55));
console.log('\n Platform Metrics:');
for (const [platform, data] of Object.entries(metrics)) {
console.log(` ${platform}: ${data.followers.toLocaleString()} followers`);
}
console.log(`\n Total Reach: ${totalReach.toLocaleString()} impressions/views`);
console.log(` Total Followers: ${totalFollowers.toLocaleString()}`);
console.log('\n Costs:');
for (const [category, amount] of Object.entries(monthlyCosts)) {
console.log(` ${category}: $${amount.toLocaleString()}`);
}
console.log(` Total: $${totalCost.toLocaleString()}/month`);
console.log('\n Revenue:');
console.log(` Social-attributed: $${monthlyRevenue.social.toLocaleString()}/month`);
console.log('\n ROI Metrics:');
console.log(` ROI: ${roi.toFixed(1)}%`);
console.log(` Cost per follower: $${costPerFollower.toFixed(4)}`);
console.log(` CPM (cost per 1K reach): $${costPerEngagement.toFixed(2)}`);
console.log(` Revenue per follower: $${revenuePerFollower.toFixed(4)}`);
const verdict = roi > 200 ? 'Excellent'
: roi > 100 ? 'Strong'
: roi > 0 ? 'Positive but room to improve'
: 'Negative ā review strategy';
console.log(`\n Verdict: ${verdict}`);
return { metrics, roi, totalCost, totalFollowers, totalReach };
}
calculateSocialROI({
accounts: {
instagram: 'glossier',
tiktok: 'glossier',
twitter: 'glossier'
},
monthlyCosts: {
'Content creation': 3000,
'Social manager': 4500,
'Tools & software': 500,
'Paid promotion': 2000
},
monthlyRevenue: {
social: 45000 // Revenue attributed to social channels
}
});
Compare ROI Across Channels
See which platform gives you the best return:
import os
import time
import requests
API_KEY = os.environ["SOCIAVAULT_API_KEY"]
BASE = "https://api.sociavault.com/v1/scrape"
HEADERS = {"X-API-Key": API_KEY}
def compare_channel_roi(accounts, channel_costs, channel_revenue):
"""Compare ROI across social channels"""
results = []
for platform, username in accounts.items():
if platform == "instagram":
r = requests.get(f"{BASE}/instagram/profile", headers=HEADERS,
params={"username": username})
profile = r.json().get("data", {})
followers = profile.get("follower_count", 0)
time.sleep(1)
r = requests.get(f"{BASE}/instagram/posts", headers=HEADERS,
params={"username": username})
posts = r.json().get("data", [])
total_eng = sum(p.get("like_count", 0) + p.get("comment_count", 0) for p in posts)
time.sleep(1)
elif platform == "tiktok":
r = requests.get(f"{BASE}/tiktok/profile", headers=HEADERS,
params={"username": username})
profile = r.json().get("data", {})
followers = (profile.get("stats") or {}).get("followerCount", 0)
time.sleep(1)
r = requests.get(f"{BASE}/tiktok/user/posts", headers=HEADERS,
params={"username": username})
posts = r.json().get("data", [])
total_eng = sum((v.get("stats") or {}).get("diggCount", 0) for v in posts)
time.sleep(1)
elif platform == "twitter":
r = requests.get(f"{BASE}/twitter/profile", headers=HEADERS,
params={"username": username})
profile = r.json().get("data", {})
followers = (profile.get("legacy") or {}).get("followers_count", 0)
time.sleep(1)
r = requests.get(f"{BASE}/twitter/user-tweets", headers=HEADERS,
params={"username": username})
posts = r.json().get("data", [])
total_eng = sum((t.get("legacy") or {}).get("favorite_count", 0) for t in posts)
time.sleep(1)
else:
continue
cost = channel_costs.get(platform, 0)
revenue = channel_revenue.get(platform, 0)
roi = ((revenue - cost) / max(cost, 1)) * 100
cost_per_eng = total_eng > 0 and cost / total_eng or 0
results.append({
"platform": platform,
"followers": followers,
"total_engagement": total_eng,
"cost": cost,
"revenue": revenue,
"roi": round(roi, 1),
"cost_per_engagement": round(cost_per_eng, 3),
"revenue_per_follower": round(revenue / max(followers, 1), 4)
})
results.sort(key=lambda x: x["roi"], reverse=True)
print("\nš Channel ROI Comparison")
print("=" * 60)
print(f"\n {'Platform':<12} {'Cost':>10} {'Revenue':>10} {'ROI':>8} {'CPE':>8}")
print(f" {'ā' * 50}")
for r in results:
print(f" {r['platform']:<12} ${r['cost']:>9,} ${r['revenue']:>9,} "
f"{r['roi']:>7.1f}% ${r['cost_per_engagement']:>6.3f}")
best = results[0]
print(f"\n Best ROI: {best['platform']} ({best['roi']}%)")
print(f" Recommendation: Shift budget from "
f"{results[-1]['platform']} to {best['platform']}")
return results
compare_channel_roi(
accounts={"instagram": "yourhandle", "tiktok": "yourhandle", "twitter": "yourhandle"},
channel_costs={"instagram": 2000, "tiktok": 1500, "twitter": 500},
channel_revenue={"instagram": 12000, "tiktok": 8000, "twitter": 1500}
)
Metrics That Actually Matter for ROI
| Metric | Vanity Version | ROI Version |
|---|---|---|
| Followers | Total follower count | Active follower growth rate |
| Engagement | Total likes | Cost per engagement (CPE) |
| Impressions | Total impressions | Revenue per 1K impressions |
| Traffic | Profile views | Social ā website conversion rate |
| Content | Total posts | Revenue per post |
| Growth | Monthly follower gain | Customer acquisition cost from social |
ROI Benchmarks by Industry
| Industry | Average Social ROI | Top Performers |
|---|---|---|
| E-commerce | 200-400% | 800%+ |
| SaaS | 100-300% | 500%+ |
| D2C brands | 150-350% | 700%+ |
| Professional services | 50-150% | 300%+ |
| Local business | 100-250% | 400%+ |
| Nonprofits | Hard to measure $ | Focus on cost-per-donation |
| B2B | 50-200% | 300%+ |
If your ROI is under 100%, you're losing money on social. But check your attribution first ā most teams under-attribute revenue to social because they only count last-click.
Common Attribution Mistakes
| Mistake | Impact | Fix |
|---|---|---|
| Last-click only | Miss 60-80% of social's influence | Use multi-touch attribution |
| Ignoring dark social | Miss DMs, screenshots, word-of-mouth | Add survey "how did you hear?" |
| No UTM parameters | Can't track social ā site | UTM every link |
| Counting all followers as customers | Inflated expectations | Track conversion rate by channel |
| Not valuing brand awareness | Undervalue top-of-funnel | Include assisted conversions |
Get Started
Sign up free ā start measuring social media ROI with real performance data from every platform.
Related Reading
Found this helpful?
Share it with others who might benefit
Ready to Try SociaVault?
Start extracting social media data with our powerful API. No credit card required.