Analytics reports
Read account metrics and native analytics reports for YouTube, X, Bluesky, Threads, Instagram, LinkedIn, and TikTok, with the scopes and limits each one needs.
Analytics has two normalized reads:
const metrics = await social.analytics.getAccountMetrics(account);
const report = await social.analytics.getReport(account, {
from: "2026-01-01",
to: "2026-01-31",
metrics: ["views"],
});
getAccountMetrics and getPostMetrics return MetricValue[]. Items contain name, numeric value,
unit, period, fetchedAt, freshness, and source.
getReport returns { query, rows, fetchedAt, source }; each row contains
dimensions and numeric metrics. The query also accepts dimensions, such as
["day"]. There is no cursor or iterate method. The client validates ordered
YYYY-MM-DD dates, at least one metric, and nonempty names. Invalid input
raises invalid_input.
Each metric keeps its existing provider name and adds canonicalName when
the counter has a portable equivalent: views, likes, comments, shares,
impressions, reach, saves, clicks, followers, or profile_views.
For example, YouTube’s viewCount maps to views, X’s replies maps to
comments, and bookmarks maps to saves. Direct adapters and managed
backends use the same projection. Unknown metrics retain their name without
a canonical name; rates and watch time are not relabeled as counters.
const metrics = await social.analytics.getPostMetrics(post);
const views = metrics.find((metric) => metric.canonicalName === "views")?.value;
Units and reporting periods remain provider-specific. Match the period and source before comparing or adding values, since multiple provider counters can share a canonical name. A missing counter means the provider did not return it, not zero. The tabs below list each route’s existing names and periods.
The examples assume one social client built with the platform’s adapter and an
account from connectedAccountRef, using the platform’s own account ID.
Platform support
Only YouTube implements the normalized analytics.report.read. Every tab below
supports getAccountMetrics. An unavailable operation raises
unsupported_capability.
YouTube
Account metrics and reports. The two reads use different APIs and scopes:
getAccountMetricsreads channel statistics from the YouTube Data API and needshttps://www.googleapis.com/auth/youtube.readonly.getReportcalls YouTube Analytics and needshttps://www.googleapis.com/auth/yt-analytics.readonly. Revenue metrics also needhttps://www.googleapis.com/auth/yt-analytics-monetary.readonly.
Report dates must be bounded and metric names provider-safe. YouTube Analytics data can lag by a day or more.
Configure youtube({ auth: { accessToken, channelId } }). The adapter calls
YouTube Analytics reports.query:
const report = await social.analytics.getReport(account, {
from: "2026-01-01",
to: "2026-01-31",
metrics: ["views", "estimatedMinutesWatched"],
dimensions: ["day"],
});A row can look like { dimensions: { day: "2026-01-03" }, metrics: { views: 1842, estimatedMinutesWatched: 96.5 } }. YouTube can omit rows for an empty period;
the SDK returns rows: []. Account metrics are lifetime channel viewCount,
subscriberCount (omitted when the channel hides it), and videoCount. Post
metrics are lifetime viewCount, likeCount, and commentCount.
X
Account metrics only. Needs a user OAuth token and current X API access and billing.
Configure x({ auth: { userId, accessToken } }). appBearerToken is for other
X operations, not this read.
const metrics = await social.analytics.getAccountMetrics(account);
const followers = metrics.find((metric) => metric.name === "followers_count")?.value;Account items are lifetime profile public metrics: followers_count,
following_count, tweet_count, and listed_count when returned. X has no
normalized bounded report. Post metrics are lifetime likes, reposts,
replies, quotes, impressions, and bookmarks, renamed from X’s *_count
fields, each only when X returns it.
Bluesky
Account metrics only, from a profile snapshot. Needs the account DID and a JWT or OAuth session.
Configure bluesky({ auth: { service, did, accessJwt } }), or pass session
instead of accessJwt. The snapshot contains lifetime followers,
following, and posts. Post metrics are likes, reposts, replies, and
quotes. Bluesky has no date-range report.
const metrics = await social.analytics.getAccountMetrics(account);Threads
Account and post metrics. Needs the OAuth scopes threads_basic and
threads_manage_insights.
Configure threads({ auth: { userId, accessToken } }), with an optional
graphVersion. getAccountMetrics requests views, likes, replies,
reposts, quotes, clicks, and followers_count. followers_count is a
lifetime total. views comes back as daily values, and the SDK returns the
latest day with that day as its period. The other totals have
period: "unknown" because Meta does not state their window. Threads reports
link clicks as link_total_values; the SDK renames it clicks.
getPostMetrics(post) requests views, likes, replies, reposts,
quotes, shares, and clicks (again renamed from link_total_values), with
period: "lifetime". Any metric Meta omits is left out. Threads has no
normalized account report.
const metrics = await social.analytics.getAccountMetrics(account);
const post = await social.analytics.getPostMetrics(platformPostRef({ ...account, postId }));Account metrics only. Instagram Login needs instagram_business_basic and
instagram_business_manage_insights. Facebook Login needs instagram_basic,
instagram_manage_insights, and pages_read_engagement.
Configure instagram({ auth: { accessToken, accountId, flavor } }) with the
flavor that matches your granted permissions. The lifetime account items are
followers_count and media_count. Post metrics depend on the media type: feed
posts and reels request likes, comments, saved, shares, and reach;
stories request only shares and reach. Meta may return fewer. Instagram has
no normalized bounded report.
const metrics = await social.analytics.getAccountMetrics(account);
const post = await social.analytics.getPostMetrics(
platformPostRef({ ...account, postId: mediaId }),
);Account metrics for organizations, plus native organization statistics.
Needs Community Management API access and rw_organization_admin or
r_organization_admin. Member accounts are not eligible.
Configure linkedin() with an organization author URN such as
urn:li:organization:123. getAccountMetrics returns the organization’s
lifetime follower count. Follower, page, and share statistics are native:
import { connectedAccountRef } from "@opencoredev/social-sdk";
import type { LinkedInTimeInterval } from "@opencoredev/social-sdk/linkedin";
const author = process.env.LINKEDIN_ORGANIZATION_URN;
if (author === undefined || !/^urn:li:organization:\d+$/.test(author)) {
throw new Error("Set LINKEDIN_ORGANIZATION_URN to urn:li:organization:<id>");
}
const account = connectedAccountRef({
backend: "default",
platform: "linkedin",
accountId: author,
});
const native = social.native("default", { acknowledgeUnsafe: true });
if (native === undefined) throw new Error("This adapter has no native module");
const interval: LinkedInTimeInterval = {
granularity: "DAY",
start: Date.parse("2026-01-01"),
end: Date.parse("2026-01-31"),
};
const rows = await native.getOrganizationFollowerStatistics({ account, interval, context });Type the interval as LinkedInTimeInterval, or write it inline in the call.
A separately declared object literal widens granularity to string, which
does not type-check.
Use getOrganizationPageStatistics and getOrganizationShareStatistics for the
other reports. Follower intervals accept DAY, WEEK, or MONTH. Page and
share intervals accept only DAY or MONTH. Use LinkedInPageShareTimeInterval
for reusable page/share intervals and LinkedInTimeInterval for followers.
A time-bound interval requires start. A follower row contains the organization, interval,
gains, and breakdowns. Native calls bypass client authorization middleware.
TikTok
Account metrics, and post metrics through analytics.read. Account metrics
need user.info.stats; post metrics need video.list.
Configure tiktok() with the creator openId, an access token, and verified
media origins. The lifetime account items are follower_count,
following_count, likes_count, and video_count.
getPostMetrics(post) returns like_count, comment_count, share_count,
and view_count for one video. TikTok has no normalized report method.
const metrics = await social.analytics.getAccountMetrics(account);
const video = await social.analytics.getPostMetrics(
platformPostRef({ ...account, postId: videoId }),
);Errors
Credential or account identity mismatches raise unauthorized. A missing
capability raises unsupported_capability. Provider throttling and transport
failures keep their SocialError codes. An empty successful result is
valid and does not prove that historical values are zero.