Social media analytics API: How to pull post performance data programmatically

How to retrieve engagement metrics from Instagram, X, LinkedIn, TikTok, YouTube, and other platforms via API — what each platform exposes, the pain of normalizing it, and a unified approach.

Social media analytics API: How to pull post performance data programmatically

The need is simple: how did this post perform?

You published content to five platforms. Now you need the numbers. Impressions, likes, comments, shares — the data your reporting dashboard, client portal, or internal analytics system runs on.

Every major social platform exposes engagement metrics through its API. The problem is not availability. The problem is that each platform exposes different metrics, through different endpoints, with different authentication requirements, in different response formats, on different timelines.

Pulling analytics from one platform is straightforward. Pulling analytics from five platforms and presenting them in a unified view is an integration project.


What each platform exposes natively

Instagram (Graph API)

Instagram’s Insights API requires a Business or Creator account connected to a Facebook Page. You need the instagram_basic and instagram_manage_insights permissions, which require Meta app review.

Media-level metrics: impressions, reach, engagement, saved, video_views (for video content)

Account-level metrics: impressions, reach, follower_count, profile_views

The endpoint is GET /{media-id}/insights with metric names passed as a parameter:

Terminal window
curl "https://graph.facebook.com/v21.0/{media-id}/insights?metric=impressions,reach,saved&access_token={token}"

Limitations: Stories insights expire after 24 hours. Reels have a different metric set than feed posts. Carousel posts return metrics for the carousel as a whole, not per-card. Rate limits are shared across all Graph API calls for the same app, not isolated to insights.

X / Twitter (API v2)

X exposes public metrics on the tweet object itself. When fetching a tweet via GET /2/tweets/{id}, include tweet.fields=public_metrics:

Terminal window
curl "https://api.x.com/2/tweets/1234567890?tweet.fields=public_metrics" \
-H "Authorization: Bearer {token}"

Returns retweet_count, reply_count, like_count, quote_count, and impression_count.

The catch: impression_count requires the tweet author’s authentication context. Public metrics from a third-party app return everything except impressions. To get impressions, you need OAuth 2.0 with the tweet owner’s token — which means different auth flows depending on which metric you need.

Rate limits depend on your API tier. Free tier gets 1 tweet lookup per 15-minute window. Basic ($200/month) gets 15,000 tweet reads. Pro tier and above gives higher limits.

LinkedIn (Marketing API)

LinkedIn provides share statistics through the Marketing API, not the Community Management API. This requires a Marketing Developer Platform application with the r_organization_social_feed permission for organization posts, or r_member_social_feed for personal posts.

Terminal window
curl "https://api.linkedin.com/rest/organizationalEntityShareStatistics?q=organizationalEntity&organizationalEntity=urn:li:organization:12345&shares=urn:li:share:67890" \
-H "Authorization: Bearer {token}" \
-H "LinkedIn-Version: 202401"

Returns totalShareStatistics with impressionCount, clickCount, likeCount, commentCount, shareCount.

The pain point: LinkedIn requires a versioned header (LinkedIn-Version) on every request, and available metrics differ between the Marketing API and the Community Management API. Many developers request the wrong API and get blank responses.

TikTok (Content Posting API)

TikTok’s video query endpoint returns basic metrics if the video was published through the Content Posting API and has a public post ID:

Terminal window
curl "https://open.tiktokapis.com/v2/video/query/?fields=like_count,comment_count,share_count,view_count" \
-H "Authorization: Bearer {token}" \
-d '{"filters": {"video_ids": ["1234567890"]}}'

Limitation: Analytics are only available for videos posted through TikTok’s API (not manual uploads). The video must be public. Historical metrics for older posts require a separate Research API with additional approval.

YouTube (Data API v3)

YouTube’s Analytics API and Data API provide different metric sets. For basic video stats, the Data API is simpler:

Terminal window
curl "https://www.googleapis.com/youtube/v3/videos?part=statistics&id=VIDEO_ID&key={api_key}"

Returns viewCount, likeCount, favoriteCount, commentCount.

For deeper analytics (watch time, audience retention, traffic sources), you need the YouTube Analytics API, which requires OAuth and has a different endpoint structure entirely. Quota costs matter — each API call consumes quota units from a daily budget of 10,000 units, and video queries cost 1-3 units depending on parts requested.

Facebook (Graph API)

Page post insights use a similar pattern to Instagram:

Terminal window
curl "https://graph.facebook.com/v21.0/{post-id}/insights?metric=post_impressions,post_clicks,post_reactions_like_total&access_token={token}"

Requires a Page access token with the read_insights permission. Metrics are returned as time-series data with period values (day, week, days_28, lifetime).

Threads (API)

Threads exposes media insights through Meta’s API:

Terminal window
curl "https://graph.threads.net/v1.0/{media-id}/insights?metric=views,likes,replies,reposts,quotes,shares&access_token={token}"

The API is newer and still evolving. Available metrics are views, likes, replies, reposts, quotes, and shares. Rate limits follow Meta’s standard Graph API limits.


The normalization problem

Each platform returns a different shape. Instagram calls it impressions. X calls it impression_count. YouTube calls it viewCount. LinkedIn wraps it in totalShareStatistics.impressionCount. TikTok calls it view_count.

A table of “likes” across platforms:

PlatformField nameEndpointAuth required
Instagramlikes (insights)/{media-id}/insightsPage token + app review
Xlike_count/2/tweets/{id}Bearer token (any tier)
LinkedInlikeCount/organizationalEntityShareStatisticsMarketing API token
TikToklike_count/v2/video/query/OAuth token
YouTubelikeCount/youtube/v3/videosAPI key or OAuth
Facebookpost_reactions_like_total/{post-id}/insightsPage token
Threadslikes/{media-id}/insightsUser token

Seven platforms, seven field names, seven endpoint patterns, seven auth models. And this is just for “likes” — one of the simpler metrics.

Building a unified analytics view means writing a normalization layer that:

  1. Authenticates differently per platform
  2. Calls different endpoints with different parameter formats
  3. Parses different response structures
  4. Maps platform-specific metric names to your internal schema
  5. Handles different rate limit windows and retry logic
  6. Accounts for metrics that exist on some platforms but not others (Pinterest has outbound_clicks; no other platform does)

This normalization layer is tedious to build and expensive to maintain. Every time a platform updates its API version, renames a field, or changes its rate limits, your layer needs updating.


Pulling unified analytics through Postproxy

Postproxy’s stats endpoint returns normalized engagement data for any post published through the API, across all platforms, in one request:

Terminal window
curl "https://api.postproxy.dev/api/posts/stats?post_ids=post_abc123,post_def456" \
-H "Authorization: Bearer YOUR_API_KEY"
{
"data": {
"post_abc123": {
"platforms": [
{
"profile_id": "prof_ig1",
"platform": "instagram",
"records": [
{
"stats": {
"impressions": 4521,
"likes": 187,
"comments": 23,
"saved": 45,
"profile_visits": 12,
"follows": 3
},
"recorded_at": "2026-03-08T14:00:00Z"
},
{
"stats": {
"impressions": 5102,
"likes": 214,
"comments": 31,
"saved": 52,
"profile_visits": 18,
"follows": 5
},
"recorded_at": "2026-03-09T06:00:00Z"
}
]
},
{
"profile_id": "prof_tw1",
"platform": "twitter",
"records": [
{
"stats": {
"impressions": 12840,
"likes": 92,
"retweets": 34,
"comments": 15,
"quotes": 8,
"saved": 11
},
"recorded_at": "2026-03-08T14:00:00Z"
}
]
}
]
}
}
}

One request. Both platforms. Consistent envelope. Each platform returns its native metric set — Instagram includes saved and profile_visits, X includes retweets and quotes — but the structure is identical across platforms.


Snapshots, not just latest values

The stats endpoint returns all recorded snapshots, not just the current numbers. Each snapshot includes a recorded_at timestamp, so you can build trend lines:

Day 1: impressions: 1,200 → likes: 45
Day 2: impressions: 3,800 → likes: 112
Day 3: impressions: 5,100 → likes: 214

Filter by time range to get exactly the window you need:

Terminal window
curl "https://api.postproxy.dev/api/posts/stats?post_ids=post_abc123&from=2026-03-01T00:00:00Z&to=2026-03-09T00:00:00Z" \
-H "Authorization: Bearer YOUR_API_KEY"

This matters for reporting tools. Clients do not just want to know a post got 5,000 impressions — they want to see how quickly it got there, when engagement peaked, and how it compared to last week’s post over the same timeframe.


Thread analytics

For thread posts (X and Threads), the stats endpoint aggregates metrics across the entire thread — parent post plus all replies — under the parent post’s ID. You do not need to query each tweet in a thread individually.

A five-tweet thread on X returns combined impressions, likes, and retweets for the full conversation. This matches how most reporting tools want to present thread performance: as a single content unit, not five separate data points.


Building a cross-platform analytics dashboard

A practical implementation pulls stats on a schedule, stores them in your database, and renders them in your UI:

// Pull stats for recent posts every 8 hours
async function syncPostStats(apiKey, postIds) {
const batchSize = 50; // API max per request
for (let i = 0; i < postIds.length; i += batchSize) {
const batch = postIds.slice(i, i + batchSize);
const response = await fetch(
`https://api.postproxy.dev/api/posts/stats?post_ids=${batch.join(',')}`,
{ headers: { 'Authorization': `Bearer ${apiKey}` } }
);
const { data } = await response.json();
for (const [postId, postData] of Object.entries(data)) {
for (const platform of postData.platforms) {
const latestRecord = platform.records[platform.records.length - 1];
await db.upsertPostStats({
post_id: postId,
platform: platform.platform,
profile_id: platform.profile_id,
stats: latestRecord.stats,
recorded_at: latestRecord.recorded_at
});
}
}
}
}

Or skip the polling entirely — subscribe to the platform_post.insights webhook event and get notified when new analytics are available:

{
"id": "evt_ins_abc123",
"type": "platform_post.insights",
"created_at": "2026-03-09T06:00:00Z",
"data": {
"post_id": "post_abc123",
"platform": "instagram",
"insights": {
"impressions": 5102,
"likes": 214
}
}
}

Your system updates in near-real-time without polling. No wasted API calls on posts that have not changed.


What the native APIs require vs. what Postproxy handles

ConcernNative APIs (build yourself)Postproxy stats endpoint
AuthenticationDifferent OAuth flow per platformOne API key
Endpoint format7 different URL patternsOne endpoint: GET /api/posts/stats
Response normalizationCustom parser per platformConsistent JSON envelope
Rate limitsPer-platform, shared with other API callsPer-post batch (50 per request)
Historical dataMost platforms return latest onlySnapshots stored over time
Thread aggregationQuery each post individuallyAggregated under parent post ID
Webhooks for new dataPlatform-specific (if available)platform_post.insights event
Metrics availableVaries by platform, permission, and tierPlatform-native metrics, consistent structure

Metrics available per platform

Platformimpressionslikescommentssavedsharesretweetsquotesrepliesrepostsclicksprofile_visitsfollowsoutbound_clicks
Instagramxxxxxx
Facebookxxx
X (Twitter)xxxxxx
LinkedInx
TikTokxxxx
YouTubexxxx
Threadsxxxxxx
Pinterestxxxxx

Each platform returns its native metric set. Postproxy does not fabricate metrics that a platform does not provide — LinkedIn genuinely only exposes impressions through its API. But the data that is available comes back in the same structure, from the same endpoint, with the same auth.


When to use the stats endpoint vs. native APIs

Use Postproxy’s stats endpoint if you publish through Postproxy and need cross-platform analytics in a consistent format. One integration covers all platforms. Historical snapshots are stored for you.

Use native platform APIs directly if you need metrics for content not published through Postproxy, need real-time analytics (sub-hour freshness), or need platform-specific metrics that go beyond post-level engagement (audience demographics, traffic sources, watch-time percentiles).

For most teams building dashboards, reporting tools, or client portals, the stats endpoint eliminates the normalization layer entirely. You write one integration instead of seven.

Start pulling cross-platform analytics through the Postproxy API.

Ready to get started?

Start with our free plan and scale as your needs grow. No credit card required.