Instagram Insights API: Complete Developer Guide for 2026
Learn how to use the Instagram Insights API to access analytics data, track engagement metrics, and build reporting tools. Includes code examples and best practices.
The Instagram Insights API provides programmatic access to valuable analytics data for business and creator accounts. Whether you’re building a social media dashboard, automating reports, or analyzing content performance, this guide covers everything you need to integrate Instagram analytics into your applications.
What is the Instagram Insights API?
The Instagram Insights API is part of Meta’s Instagram Graph API. It enables developers to retrieve performance metrics for Instagram Business and Creator accounts, including data on posts, stories, reels, and audience demographics.
Unlike manual analytics checking through the Instagram app, the API allows you to:
- Automate data collection across multiple accounts
- Build custom dashboards and reporting tools
- Integrate Instagram metrics with other data sources
- Track historical performance trends programmatically
Prerequisites for Using Instagram Insights API
Before accessing insights data, you need:
Account Requirements
- Instagram Business or Creator Account: Personal accounts cannot access the Insights API
- Facebook Page Connection: Your Instagram account must be linked to a Facebook Page
- Meta Developer Account: Register at developers.facebook.com
Technical Requirements
- Facebook App: Created in the Meta Developer Dashboard
- Access Tokens: User or Page access tokens with appropriate permissions
- Permissions Granted:
instagram_basic,instagram_manage_insights, andpages_show_list
Setting Up API Access
Step 1: Create a Meta App
- Navigate to Meta for Developers
- Create a new app and select “Business” type
- Add the “Instagram Graph API” product to your app
Step 2: Configure Permissions
Request these permissions for insights access:
instagram_basic
instagram_manage_insights
pages_show_list
pages_read_engagement
Step 3: Generate Access Tokens
For development, use the Graph API Explorer to generate tokens. For production, implement the OAuth flow:
const authUrl = `https://www.facebook.com/v18.0/dialog/oauth?
client_id=${APP_ID}
&redirect_uri=${REDIRECT_URI}
&scope=instagram_basic,instagram_manage_insights,pages_show_list`;
Step 4: Get Instagram Business Account ID
Retrieve your Instagram Business Account ID through the linked Facebook Page:
// First, get the Facebook Page ID
GET /me/accounts?access_token={access-token}
// Then, get the Instagram Business Account
GET /{page-id}?fields=instagram_business_account&access_token={access-token}
Available Metrics and Endpoints
The Instagram Insights API provides metrics at three levels: account, media, and story/reel.
Account-Level Insights
Retrieve overall account performance:
GET /{instagram-account-id}/insights
Available Metrics:
| Metric | Description | Period |
|---|---|---|
impressions | Total times content was displayed | day, week, days_28 |
reach | Unique accounts that saw content | day, week, days_28 |
follower_count | Total followers | day |
email_contacts | Email button taps | day |
phone_call_clicks | Call button taps | day |
text_message_clicks | Text button taps | day |
get_directions_clicks | Directions button taps | day |
website_clicks | Website link taps | day |
profile_views | Profile visits | day |
Example Request:
const response = await fetch(
`https://graph.facebook.com/v18.0/${igAccountId}/insights?` +
`metric=impressions,reach,profile_views&period=day&` +
`access_token=${accessToken}`
);
const data = await response.json();
Media-Level Insights
Get performance data for individual posts:
GET /{media-id}/insights
Photo and Video Metrics:
| Metric | Description |
|---|---|
engagement | Likes + comments + saves |
impressions | Times the media was seen |
reach | Unique accounts reached |
saved | Times saved to collections |
video_views | Video views (videos only) |
Carousel Metrics:
| Metric | Description |
|---|---|
carousel_album_engagement | Total engagement on carousel |
carousel_album_impressions | Carousel impressions |
carousel_album_reach | Unique accounts reached |
carousel_album_saved | Times carousel was saved |
Example Request:
async function getMediaInsights(mediaId, accessToken) {
const metrics = 'engagement,impressions,reach,saved';
const response = await fetch(
`https://graph.facebook.com/v18.0/${mediaId}/insights?` +
`metric=${metrics}&access_token=${accessToken}`
);
return response.json();
}
Story Insights
Stories have unique metrics available for 24 hours after posting:
| Metric | Description |
|---|---|
exits | Times users left the story |
impressions | Total story views |
reach | Unique viewers |
replies | Direct message replies |
taps_forward | Taps to next story |
taps_back | Taps to previous story |
Reels Insights
Reels provide video-specific engagement data:
| Metric | Description |
|---|---|
comments | Comment count |
likes | Like count |
plays | Total plays |
reach | Unique accounts reached |
saved | Save count |
shares | Share count |
Audience Demographics
Access follower demographic breakdowns:
GET /{instagram-account-id}/insights?metric=audience_city,audience_country,audience_gender_age,audience_locale&period=lifetime
Demographic Metrics:
audience_city: Top cities of followersaudience_country: Follower countriesaudience_gender_age: Gender and age distributionaudience_locale: Language preferences
Important: Demographic data requires a minimum of 100 followers.
async function getAudienceDemographics(igAccountId, accessToken) {
const metrics = [
'audience_city',
'audience_country',
'audience_gender_age',
'audience_locale'
].join(',');
const response = await fetch(
`https://graph.facebook.com/v18.0/${igAccountId}/insights?` +
`metric=${metrics}&period=lifetime&access_token=${accessToken}`
);
const data = await response.json();
return data.data;
}
Building a Complete Analytics Dashboard
Here’s a practical implementation for fetching comprehensive insights:
class InstagramInsights {
constructor(accessToken, igAccountId) {
this.accessToken = accessToken;
this.igAccountId = igAccountId;
this.baseUrl = 'https://graph.facebook.com/v18.0';
}
async fetchApi(endpoint, params = {}) {
const url = new URL(`${this.baseUrl}${endpoint}`);
url.searchParams.append('access_token', this.accessToken);
Object.entries(params).forEach(([key, value]) => {
url.searchParams.append(key, value);
});
const response = await fetch(url);
if (!response.ok) {
const error = await response.json();
throw new Error(error.error?.message || 'API request failed');
}
return response.json();
}
async getAccountInsights(period = 'day') {
const metrics = [
'impressions',
'reach',
'profile_views',
'website_clicks',
'follower_count'
].join(',');
return this.fetchApi(`/${this.igAccountId}/insights`, {
metric: metrics,
period: period
});
}
async getRecentMedia(limit = 25) {
return this.fetchApi(`/${this.igAccountId}/media`, {
fields: 'id,caption,media_type,timestamp,permalink,like_count,comments_count',
limit: limit
});
}
async getMediaInsights(mediaId) {
const metrics = 'engagement,impressions,reach,saved';
return this.fetchApi(`/${mediaId}/insights`, {
metric: metrics
});
}
async getAllMediaWithInsights(limit = 25) {
const mediaResponse = await this.getRecentMedia(limit);
const media = mediaResponse.data;
const mediaWithInsights = await Promise.all(
media.map(async (item) => {
try {
const insights = await this.getMediaInsights(item.id);
return { ...item, insights: insights.data };
} catch (error) {
return { ...item, insights: null, error: error.message };
}
})
);
return mediaWithInsights;
}
}
// Usage
const insights = new InstagramInsights(ACCESS_TOKEN, IG_ACCOUNT_ID);
const accountData = await insights.getAccountInsights('days_28');
const mediaPerformance = await insights.getAllMediaWithInsights(10);
Rate Limits and Best Practices
API Rate Limits
The Instagram Graph API enforces rate limits:
- Standard limit: 200 calls per user per hour
- Business Use Case: Higher limits available with approved use cases
Handling Rate Limits
async function fetchWithRateLimit(fetchFn, retries = 3) {
for (let attempt = 0; attempt < retries; attempt++) {
try {
return await fetchFn();
} catch (error) {
if (error.message.includes('rate limit') && attempt < retries - 1) {
const waitTime = Math.pow(2, attempt) * 1000;
await new Promise(resolve => setTimeout(resolve, waitTime));
continue;
}
throw error;
}
}
}
Caching Strategies
Reduce API calls with intelligent caching:
class CachedInsights {
constructor(insights, cacheDuration = 3600000) {
this.insights = insights;
this.cache = new Map();
this.cacheDuration = cacheDuration;
}
async getCached(key, fetchFn) {
const cached = this.cache.get(key);
if (cached && Date.now() - cached.timestamp < this.cacheDuration) {
return cached.data;
}
const data = await fetchFn();
this.cache.set(key, { data, timestamp: Date.now() });
return data;
}
async getAccountInsights(period) {
return this.getCached(
`account_${period}`,
() => this.insights.getAccountInsights(period)
);
}
}
Common Use Cases
Automated Weekly Reports
async function generateWeeklyReport(insights) {
const accountMetrics = await insights.getAccountInsights('week');
const topMedia = await insights.getAllMediaWithInsights(10);
const sortedByEngagement = topMedia
.filter(m => m.insights)
.sort((a, b) => {
const engA = a.insights.find(i => i.name === 'engagement')?.values[0]?.value || 0;
const engB = b.insights.find(i => i.name === 'engagement')?.values[0]?.value || 0;
return engB - engA;
});
return {
period: 'week',
generatedAt: new Date().toISOString(),
accountMetrics: accountMetrics.data,
topPerformingPosts: sortedByEngagement.slice(0, 5)
};
}
Engagement Rate Calculation
function calculateEngagementRate(mediaInsights, followerCount) {
const engagement = mediaInsights.find(m => m.name === 'engagement')?.values[0]?.value || 0;
return ((engagement / followerCount) * 100).toFixed(2);
}
Best Posting Time Analysis
function analyzeBestPostingTimes(mediaWithInsights) {
const hourlyEngagement = {};
mediaWithInsights.forEach(media => {
if (!media.insights) return;
const hour = new Date(media.timestamp).getHours();
const engagement = media.insights.find(i => i.name === 'engagement')?.values[0]?.value || 0;
if (!hourlyEngagement[hour]) {
hourlyEngagement[hour] = { total: 0, count: 0 };
}
hourlyEngagement[hour].total += engagement;
hourlyEngagement[hour].count += 1;
});
return Object.entries(hourlyEngagement)
.map(([hour, data]) => ({
hour: parseInt(hour),
avgEngagement: data.total / data.count
}))
.sort((a, b) => b.avgEngagement - a.avgEngagement);
}
Error Handling
Handle common API errors gracefully:
function handleInsightsError(error) {
const errorCode = error.code;
const errorMessages = {
100: 'Invalid parameter - check your metric names',
190: 'Access token expired - refresh authentication',
200: 'Permission denied - verify app permissions',
4: 'Rate limit exceeded - implement backoff strategy',
10: 'Permission error - user may have revoked access'
};
return errorMessages[errorCode] || `Unknown error: ${error.message}`;
}
Webhook Integration
Set up webhooks to receive real-time updates:
// Webhook endpoint
app.post('/instagram/webhook', (req, res) => {
const { object, entry } = req.body;
if (object === 'instagram') {
entry.forEach(event => {
const { changes } = event;
changes.forEach(change => {
if (change.field === 'mentions') {
handleMention(change.value);
} else if (change.field === 'comments') {
handleComment(change.value);
}
});
});
}
res.sendStatus(200);
});
Security Considerations
Token Storage
Never expose access tokens in client-side code:
// Bad - token exposed
const response = await fetch(`https://graph.facebook.com/...?access_token=${token}`);
// Good - proxy through your server
const response = await fetch('/api/instagram/insights');
Token Refresh
Implement automatic token refresh before expiration:
async function refreshLongLivedToken(currentToken) {
const response = await fetch(
`https://graph.facebook.com/v18.0/oauth/access_token?` +
`grant_type=fb_exchange_token&` +
`client_id=${APP_ID}&` +
`client_secret=${APP_SECRET}&` +
`fb_exchange_token=${currentToken}`
);
return response.json();
}
Limitations and Considerations
Data Availability
- Stories: Insights available for 24 hours only
- Historical data: Limited to 30 days for most metrics
- Demographic data: Requires 100+ followers
- Promoted content: Some metrics differ for ads
API Constraints
- No access to competitor accounts
- Personal accounts excluded
- Some metrics are estimates
- Data may be delayed up to 48 hours
Conclusion
The Instagram Insights API provides powerful analytics capabilities for businesses and developers building social media tools. With proper implementation of authentication, rate limiting, and caching, you can create robust analytics applications that deliver actionable insights.
Start with basic account metrics, expand to media-level analysis, and consider webhook integration for real-time monitoring. Always handle errors gracefully and respect API rate limits to maintain reliable access to Instagram analytics data.