Instagram Engagement Rate Calculator: How to Calculate & What the Numbers Mean
Everyone talks about engagement rate. Most people calculate it wrong.
Some divide by reach. Some divide by impressions. Some include saves, some don't. Some count Story interactions, some only count feed posts. Marketing blogs contradict each other. Tools give different numbers for the same account.
This guide straightens it out. You'll learn:
- The standard formula (and why there are multiple)
- How to calculate it manually
- How to automate it with code for any public account
- What the numbers actually mean for your tier and niche
- When a "low" number is actually fine
No fluff, just math.
The Formula (And Why There Are 4 Versions)
There's no single "official" engagement rate formula. Different people use different ones. Here are the four most common:
Formula 1: Engagement Rate by Followers (ERF)
ER = (Likes + Comments) / Followers × 100
Use this when: You want to compare across accounts, especially competitors. This is the industry standard for influencer marketing because follower count is public. Our engagement rate benchmarks use this formula.
Formula 2: Engagement Rate by Reach (ERR)
ER = (Likes + Comments + Saves + Shares) / Reach × 100
Use this when: You're analyzing your own account and have access to Instagram Insights. More accurate because it measures engagement from people who actually saw the post. But you can only calculate this for your own content — reach data isn't public.
Formula 3: Engagement Rate by Impressions (ERI)
ER = (Likes + Comments) / Impressions × 100
Use this when: You're focused on content performance. Impressions include repeat views, so this number is always lower than ERR. Rarely used.
Formula 4: Engagement Rate by Views (for Reels/Video)
ER = (Likes + Comments) / Views × 100
Use this when: You're evaluating Reels or video content specifically. A Reel can get views from millions of non-followers, so dividing by followers makes no sense. This is more common for TikTok analysis.
Which One Should You Use?
| Situation | Best Formula |
|---|---|
| Comparing your account to competitors | ERF (by followers) |
| Evaluating your own content strategy | ERR (by reach) |
| Vetting an influencer before a deal | ERF (by followers) |
| Analyzing Reels/video content | ER by Views |
| Reporting to a client | ERR (by reach) — shows true performance |
For this guide, we'll use ERF (by followers) because it's the only one you can calculate for any public account.
Calculate It Manually (5 Minutes)
No tool, no API, no money. Just arithmetic.
Step 1: Pick 12 Recent Posts
Go to the account's profile. Pick the 12 most recent feed posts (not Reels, not Stories — we'll get to those). Why 12? It gives you roughly a month of content, enough to smooth out outliers.
Step 2: Record Likes and Comments
For each post, write down:
- Likes count (visible unless hidden)
- Comments count
Step 3: Calculate Per-Post ER
For each post:
Post ER = (Likes + Comments) / Followers × 100
Step 4: Average Them
Add all 12 post ERs together, divide by 12.
Example: @natgeo
Let's say National Geographic has 285M followers. A recent post has 450K likes and 1,200 comments:
Post ER = (450,000 + 1,200) / 285,000,000 × 100 = 0.16%
That looks low, but for a 285M-follower account, it's on par. Engagement rates drop dramatically with scale. Check our full benchmarks by tier for context.
Calculate It With Code (Any Account, Seconds)
Manual calculation works for one account. If you're checking competitors, vetting influencers, or running an agency, you need code.
JavaScript
const axios = require('axios');
const API_KEY = process.env.SOCIAVAULT_API_KEY;
const BASE_URL = 'https://api.sociavault.com';
async function engagementRate(username) {
// Get profile — provides follower count
const profile = await axios.get(`${BASE_URL}/v1/scrape/instagram/profile`, {
params: { handle: username, trim: true },
headers: { 'X-API-Key': API_KEY }
});
const user = profile.data.data.data.user;
const followers = user.edge_followed_by.count;
const following = user.edge_follow.count;
const isVerified = user.is_verified;
// Get recent posts — provides likes + comments per post
const posts = await axios.get(`${BASE_URL}/v1/scrape/instagram/posts`, {
params: { handle: username, trim: true },
headers: { 'X-API-Key': API_KEY }
});
const edges = posts.data.data.data.user.edge_owner_to_timeline_media.edges;
if (edges.length === 0) {
console.log(`@${username} has no posts`);
return null;
}
// Calculate per-post engagement rate
let totalER = 0;
const postData = [];
for (const edge of edges) {
const node = edge.node;
const likes = node.edge_liked_by?.count || 0;
const comments = node.edge_media_to_comment?.count || 0;
const er = ((likes + comments) / followers) * 100;
postData.push({
url: `https://instagram.com/p/${node.shortcode}`,
likes,
comments,
er: er.toFixed(3) + '%',
date: new Date(node.taken_at_timestamp * 1000).toLocaleDateString()
});
totalER += er;
}
const avgER = totalER / edges.length;
// Determine tier
let tier = 'Nano';
if (followers >= 500000) tier = 'Mega';
else if (followers >= 100000) tier = 'Macro';
else if (followers >= 50000) tier = 'Mid';
else if (followers >= 10000) tier = 'Micro';
console.log(`\n@${username} ${isVerified ? '✓' : ''}`);
console.log(`Tier: ${tier} (${followers.toLocaleString()} followers)`);
console.log(`Following: ${following.toLocaleString()}`);
console.log(`Posts analyzed: ${edges.length}`);
console.log(`Average Engagement Rate: ${avgER.toFixed(2)}%`);
console.log(`\nPer-post breakdown:`);
postData.forEach(p => {
console.log(` ${p.date} | ${p.likes.toLocaleString()} likes, ${p.comments.toLocaleString()} comments → ${p.er}`);
});
return { username, tier, followers, avgER: avgER.toFixed(2), posts: postData };
}
// Calculate for any account
await engagementRate('cristiano');
Python
import requests
import os
API_KEY = os.getenv('SOCIAVAULT_API_KEY')
BASE_URL = 'https://api.sociavault.com'
headers = {'X-API-Key': API_KEY}
def engagement_rate(username):
"""Calculate engagement rate for any public Instagram account"""
# Get profile
profile = requests.get(
f'{BASE_URL}/v1/scrape/instagram/profile',
params={'handle': username, 'trim': 'true'},
headers=headers
).json()
user = profile['data']['data']['user']
followers = user['edge_followed_by']['count']
following = user['edge_follow']['count']
verified = user.get('is_verified', False)
# Get posts
posts = requests.get(
f'{BASE_URL}/v1/scrape/instagram/posts',
params={'handle': username, 'trim': 'true'},
headers=headers
).json()
edges = posts['data']['data']['user']['edge_owner_to_timeline_media']['edges']
if not edges:
print(f"@{username} has no posts")
return None
# Calculate
rates = []
for edge in edges:
node = edge['node']
likes = node.get('edge_liked_by', {}).get('count', 0)
comments = node.get('edge_media_to_comment', {}).get('count', 0)
er = ((likes + comments) / followers) * 100
rates.append(er)
avg_er = sum(rates) / len(rates)
# Determine tier
if followers >= 500_000:
tier = 'Mega'
elif followers >= 100_000:
tier = 'Macro'
elif followers >= 50_000:
tier = 'Mid'
elif followers >= 10_000:
tier = 'Micro'
else:
tier = 'Nano'
print(f"\n@{username} {'✓' if verified else ''}")
print(f"Tier: {tier} ({followers:,} followers)")
print(f"Posts analyzed: {len(edges)}")
print(f"Average Engagement Rate: {avg_er:.2f}%")
return {'username': username, 'tier': tier, 'followers': followers, 'avg_er': round(avg_er, 2)}
engagement_rate('cristiano')
Cost: 2 API credits per account (1 profile + 1 posts).
Comparing Multiple Accounts Side by Side
This is where the code approach really pays off. Want to compare 5 competitors in your niche? Don't manually check 60 posts. Do this:
async function compareAccounts(usernames) {
const results = [];
for (const username of usernames) {
const result = await engagementRate(username);
if (result) results.push(result);
}
// Sort by engagement rate
results.sort((a, b) => parseFloat(b.avgER) - parseFloat(a.avgER));
console.log('\n\n=== ENGAGEMENT RATE COMPARISON ===\n');
console.log('Rank | Account | Followers | Avg ER');
console.log('-----|-------------------|-------------|-------');
results.forEach((r, i) => {
console.log(` ${i + 1} | @${r.username.padEnd(16)} | ${r.followers.toLocaleString().padStart(11)} | ${r.avgER}%`);
});
return results;
}
// Compare fitness influencers
await compareAccounts([
'kayla_itsines',
'blogilates',
'whitneyysimmons',
'jeffnippard',
'megsquats'
]);
Cost: 2 credits per account × 5 accounts = 10 credits total. In a paid analytics tool, this comparison would cost $30-100/month.
Including Reels in the Calculation
Feed post engagement and Reels engagement are very different. Reels reach non-followers, so their engagement rate (by followers) looks different.
To include Reels:
async function fullEngagementRate(username) {
const profile = await axios.get(`${BASE_URL}/v1/scrape/instagram/profile`, {
params: { handle: username, trim: true },
headers: { 'X-API-Key': API_KEY }
});
const followers = profile.data.data.data.user.edge_followed_by.count;
// Get feed posts
const posts = await axios.get(`${BASE_URL}/v1/scrape/instagram/posts`, {
params: { handle: username, trim: true },
headers: { 'X-API-Key': API_KEY }
});
// Get Reels
const reels = await axios.get(`${BASE_URL}/v1/scrape/instagram/reels`, {
params: { handle: username },
headers: { 'X-API-Key': API_KEY }
});
const postEdges = posts.data.data.data.user.edge_owner_to_timeline_media.edges;
const reelItems = reels.data.items || [];
// Feed post ER
const postRates = postEdges.map(e => {
const likes = e.node.edge_liked_by?.count || 0;
const comments = e.node.edge_media_to_comment?.count || 0;
return ((likes + comments) / followers) * 100;
});
// Reel ER (by followers, for consistency)
const reelRates = reelItems.map(item => {
const likes = item.media?.like_count || 0;
const comments = item.media?.comment_count || 0;
return ((likes + comments) / followers) * 100;
});
const avgPostER = postRates.length ? postRates.reduce((a, b) => a + b, 0) / postRates.length : 0;
const avgReelER = reelRates.length ? reelRates.reduce((a, b) => a + b, 0) / reelRates.length : 0;
const combinedER = [...postRates, ...reelRates];
const avgCombined = combinedER.reduce((a, b) => a + b, 0) / combinedER.length;
console.log(`\n@${username} — Full Engagement Breakdown`);
console.log(`Followers: ${followers.toLocaleString()}`);
console.log(`Feed Post ER: ${avgPostER.toFixed(2)}% (${postRates.length} posts)`);
console.log(`Reels ER: ${avgReelER.toFixed(2)}% (${reelRates.length} reels)`);
console.log(`Combined ER: ${avgCombined.toFixed(2)}%`);
return { avgPostER, avgReelER, avgCombined };
}
await fullEngagementRate('garyvee');
Cost: 3 credits (profile + posts + reels). Worth it when you need the full picture.
What "Good," "Bad," and "Great" Actually Mean
Here's the context most calculators don't give you. Quick reference by follower tier:
| Tier | Followers | Below Average | Average | Good | Great |
|---|---|---|---|---|---|
| Nano | 1K-10K | Under 2.5% | 2.5-4.0% | 4.0-6.0% | 6.0%+ |
| Micro | 10K-50K | Under 1.5% | 1.5-2.8% | 2.8-4.0% | 4.0%+ |
| Mid | 50K-100K | Under 1.0% | 1.0-1.9% | 1.9-3.0% | 3.0%+ |
| Macro | 100K-500K | Under 0.7% | 0.7-1.4% | 1.4-2.0% | 2.0%+ |
| Mega | 500K+ | Under 0.4% | 0.4-0.9% | 0.9-1.5% | 1.5%+ |
These benchmarks come from our analysis of 50,000 Instagram accounts. They're filtered for accounts with genuine, organic engagement — no bots, no pods, no purchased followers.
Important: Niche matters just as much as tier. An Education account at 3.8% is average. A Beauty account at 3.8% is exceptional. See the full breakdown by niche.
Common Mistakes
Mistake 1: Including Your Own Likes
If the account owner likes their own posts (common), that like is counted. For most accounts, this is negligible. For a nano account with 50 likes per post, one self-like doesn't matter. Don't worry about it.
Mistake 2: Using Too Few Posts
Calculating from 3 posts is meaningless. One viral post skews everything. Use at least 12, ideally 20-30.
Mistake 3: Comparing Across Tiers
A 2% ER for a micro account (15K followers) is below average. A 2% ER for a macro account (300K followers) is excellent. Context matters.
Mistake 4: Ignoring Content Type
Reels and carousels get fundamentally different engagement than single images. If you're comparing two accounts, make sure you're comparing similar content mixes.
Mistake 5: Not Accounting for Fake Followers
High follower count + low engagement doesn't always mean bad content. It often means purchased followers diluting the denominator. Our fake follower study found 37.2% of influencer followers are fake. That directly destroys engagement rates.
FAQ
Should I include saves and shares?
Not for public comparisons. Saves and shares are only visible to the account owner. If you include them for your own account, your ER will look higher than anyone else's because you have data they don't. Use likes + comments for apples-to-apples comparison.
My engagement rate dropped. Is that bad?
Check if your follower count grew. If you gained 20K followers but engagement stayed flat, your ER drops — that's normal growth, not a problem. If followers are flat and engagement dropped, then your content is underperforming.
How often should I calculate it?
Weekly for your own account. Monthly for competitors. Before every influencer deal.
Does engagement rate affect the algorithm?
Yes. Instagram uses engagement signals (especially saves and shares in 2026) to decide how widely to distribute your content. Higher engagement = more reach = more engagement. It's a flywheel.
Get Started
Calculate engagement rates for any public Instagram account.
Sign up free — 100 credits gives you 50 engagement rate calculations (2 credits each: profile + posts).
Full API docs: docs.sociavault.com/api-reference/instagram
Related Reading
- What Is a Good Engagement Rate on Instagram in 2026?
- Instagram Profile Scraper API: Extract User Data & Metrics
- Instagram Posts Scraper API: Extract All Posts from Any Profile
- Instagram Reels API: Extract Reels Data & Analytics
- How to Check If an Influencer Has Fake Followers
- Carousels Beat Reels for Retention
- The Death of Follower Count
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.