Skip to content
Social SDK Cloud, the hosted SDK, is taking early-access signups.Join the list
Social SDK megaphone markSocial SDK
Esc
↑↓navigate↵open⌘Jpreview
On this page

Read posts and analytics

Read feeds, single posts, likes, and current post metrics through the normalized API, with platform tabs covering scopes, limits, and native reads.

To get post analytics from X, Instagram and LinkedIn in one place with code, register each platform’s adapter in one Social SDK client and call social.analytics.getPostMetrics with a reference to each post. Each call reads that platform’s own API and returns a list of metrics with a name, a numeric value, a unit, a period, and a source. X returns likes, reposts, replies, quotes, impressions, and bookmarks; Instagram returns likes, comments, saved, shares, and reach from media insights; LinkedIn returns likes and comments. A metric the platform doesn’t return is left out, not set to zero.

npm install @opencoredev/social-sdk
pnpm add @opencoredev/social-sdk
yarn add @opencoredev/social-sdk
bun add @opencoredev/social-sdk
nub add @opencoredev/social-sdk
aube add @opencoredev/social-sdk
import { createSocial, platformPostRef } from "@opencoredev/social-sdk";
import { instagram } from "@opencoredev/social-sdk/instagram";
import { linkedin } from "@opencoredev/social-sdk/linkedin";
import { x } from "@opencoredev/social-sdk/x";

const social = createSocial({
  backends: {
    x: x({
      auth: { userId: process.env.X_USER_ID!, accessToken: process.env.X_ACCESS_TOKEN! },
    }),
    instagram: instagram({
      auth: {
        accountId: process.env.IG_ACCOUNT_ID!,
        accessToken: process.env.IG_ACCESS_TOKEN!,
        flavor: "instagram-login",
      },
    }),
    linkedin: linkedin({
      auth: {
        accessToken: process.env.LINKEDIN_ACCESS_TOKEN!,
        author: "urn:li:organization:12345",
      },
      apiVersion: "202610",
    }),
  },
});

const posts = [
  platformPostRef({
    backend: "x",
    platform: "x",
    accountId: process.env.X_USER_ID!,
    postId: "1850000000000000000",
  }),
  platformPostRef({
    backend: "instagram",
    platform: "instagram",
    accountId: process.env.IG_ACCOUNT_ID!,
    postId: "17900000000000000",
  }),
  platformPostRef({
    backend: "linkedin",
    platform: "linkedin",
    accountId: "urn:li:organization:12345",
    postId: "urn:li:share:7000000000000000000",
  }),
];

for (const post of posts) {
  const metrics = await social.analytics.getPostMetrics(post);
  console.log(post.platform, metrics.map((metric) => `${metric.name}=${metric.value}`).join(" "));
}

Each request goes straight to the platform with your own app’s tokens, so the access rules are the platform’s: X needs a user token and current X API access, Instagram needs a professional account plus instagram_business_basic and instagram_business_manage_insights with Instagram Login, and LinkedIn Page posts need r_organization_social and r_organization_social_feed. The platform tabs below and Analytics reports cover the rest of each route’s access. Units and periods differ by platform, so match period and source before you add numbers from different networks. For what each platform requires before you can post or read, see the social media APIs guide.

This page covers post and feed reads, post and account metrics, and provider-native likes lists. See Search, Social graph, Notifications, and Analytics reports for those separate surfaces.

Normalized API

The facade returns provider-shaped JsonObject items in a Page:

const page = await social.posts.list(account, { limit: 20 });
const one = await social.posts.get(platformPostRef);

Pass nextCursor back unchanged with the same account and options. Cursors are opaque. posts.iterate(account, { maxPages, maxItems }) is lazy and bounded. Page-size limits differ by route; 20 is valid on every direct adapter (TikTok allows at most 20, YouTube and Instagram at most 50, the others 100).

Items are projections, not full provider objects. Most adapters copy a fixed list of scalar fields and drop nested objects and arrays, so the tabs below list what each route actually returns.

The examples assume one client and one connected account for the adapter you configure below:

const social = createSocial({ backend: adapter });
const account = connectedAccountRef({ backend: "default", platform: "x", accountId: "123" });

Post metrics

const metrics = await social.analytics.getPostMetrics(platformPostRef);
const accountMetrics = await social.analytics.getAccountMetrics(account);

Both return MetricValue[]. An omitted metric means the provider did not return it, not zero. Bounded date-range reports are covered in Analytics reports.

Platform support

X

Reads: posts list, get, and iterate. Metrics: account and post, plus native likes lists. Access: user scopes and your X API tier.

Use a user OAuth token. appBearerToken is for app-only operations such as full-archive search, not user timelines.

import { x } from "@opencoredev/social-sdk/x";

const adapter = x({ auth: { userId: "123", accessToken: process.env.X_ACCESS_TOKEN! } });

posts.list and posts.get return id, text, author_id, created_at, and conversation_id. They do not include public_metrics or referenced posts; read counts with analytics.getPostMetrics. User timeline, home timeline, mentions, liked posts, and liking users are native operations: userPosts, homeTimeline, mentions, likedPosts, and likingUsers. They need the matching X read capability, user scopes, and an eligible API tier. Missing access raises missing_permission; throttling raises rate_limited.

Bluesky

Reads: author feed through posts.list, plus native getPost and getPostThread. Metrics: account and post, plus native likes lists. Access: repo. Feed page size is 1 to 100.

Use a PDS service and DID with an access JWT, or an OAuth session.

import { bluesky } from "@opencoredev/social-sdk/bluesky";

const adapter = bluesky({
  auth: {
    service: "https://bsky.social",
    did: "did:plc:example",
    accessJwt: process.env.BSKY_JWT!,
  },
});

posts.list reads the account’s author feed. Each item is { post, reason? }, where post has uri, cid, the like, repost, reply, and quote counts, indexedAt, and public author fields (did, handle, displayName, avatar). Validated nested fields include record text, timestamps, facets, reply references, and embeds; AppView embeds; labels; and repost reasons. Image, video, external-link, and quoted-post embeds are retained, including quotes with attached media. Fields outside the public allowlist are omitted. Use native getPost({ uri }) or getPostThread({ uri }) for additional record or thread data; neither returns a cursor. The normalized post ref can carry the native uri and cid. Native getLikes lists users who liked a post; getActorLikes lists posts an actor liked. An invalid page size raises invalid_input.

Threads

Reads: list and get. Metrics: account and post. Access: user token. Feed page size is 1 to 100.

Use the Threads user ID and a long-lived user access token.

import { threads } from "@opencoredev/social-sdk/threads";

const adapter = threads({ auth: { userId: "th_123", accessToken: process.env.THREADS_TOKEN! } });

List items contain id, text, username, media_type, permalink, and timestamp. The after cursor is opaque. posts.get and search.posts are normalized; posts.get returns the post fields the native getPost reads. Threads has post and selected account insights but no normalized likes list. Mentions and keyword search options beyond the normalized input are native.

Instagram

Reads: media list and get. Metrics: account and post insights. Access: a professional account.

Use a professional account ID and access token, and pick Instagram Login or Facebook Login. Business discovery and hashtag features need Facebook Login.

import { instagram } from "@opencoredev/social-sdk/instagram";

const adapter = instagram({
  auth: {
    accountId: "17840000000000000",
    accessToken: process.env.IG_TOKEN!,
    flavor: "instagram-login",
  },
});

Media includes Graph API fields such as ID, caption, media type, permalink, timestamp, and URLs. Insights can include likes, comments, saves, shares, and reach. Mentions, tagged media, and business discovery are native. The tags mentions edge works with both login flavors. Missing permissions raise missing_permission.

YouTube

Reads: uploads and get. Metrics: channel and video statistics. Access: an OAuth token and the channel ID.

Normalized posts are videos from the channel uploads feed.

import { youtube } from "@opencoredev/social-sdk/youtube";

const adapter = youtube({
  auth: { accessToken: process.env.YOUTUBE_TOKEN!, channelId: "UC_example" },
});

posts.get returns id, snippet (title, description, channelId, publishedAt), and status (privacyStatus, uploadStatus, selfDeclaredMadeForKids). It does not include statistics; read view, like, and comment counts with analytics.getPostMetrics. Playlists and playlist items are native. Reports need the separate https://www.googleapis.com/auth/yt-analytics.readonly scope and a bounded query. An inaccessible video raises an error instead of returning an empty item.

LinkedIn

Reads: author feed and get. Metrics: post, and account for organizations only. Access: r_member_social or r_organization_social.

Use a person or organization author URN and a monthly API version.

import { linkedin } from "@opencoredev/social-sdk/linkedin";

const adapter = linkedin({
  auth: { accessToken: process.env.LINKEDIN_TOKEN!, author: "urn:li:person:abc" },
  apiVersion: "202609",
});

Person authors need r_member_social; organization authors need r_organization_social. The author feed uses an opaque offset cursor. Organization account metrics need an administrator grant such as rw_organization_admin. Member-profile account analytics are not supported. Invalid URNs or API versions raise invalid_config.

TikTok

Reads: video list and get. Metrics: account stats and per-video counts. Access: Display API with user.info.stats and video.list.

TikTok reads use an access token, the creator’s Open ID, and verified media origins.

import { tiktok } from "@opencoredev/social-sdk/tiktok";

const adapter = tiktok({
  auth: { accessToken: process.env.TIKTOK_TOKEN!, openId: "open-id" },
  verifiedMediaOrigins: ["https://media.example.com"],
});

Video items include ID, creation time, title, description, dimensions, share URL, and like, comment, share, and view counts. getPostMetrics reads the same four counts through the video query endpoint and needs video.list. Account counts need user.info.stats. TikTok has no normalized likes list.

Errors and unsupported platforms

An unavailable capability raises unsupported_capability. Authentication failures use reconnect_required or unauthorized; denied scopes use missing_permission; bad cursors, references, or limits use invalid_input; throttling uses rate_limited; and inaccessible resources can be not_found or gone. Do not turn errors into empty pages or zero metrics.

The direct Facebook adapter reads Page posts through posts.list and posts.get, comments, post and Page counts, and daily Page Insights; see the Facebook page. Managed backends that cover Facebook declare their own support. Inspect social.capabilities() before enabling a feature.

Last updated on November 5, 2026