7-day offer$199$9
X-Autopilot

X API analytics: 23 metrics and no price row

X has a working post analytics endpoint with 23 metrics, including unfollows. It is missing from the metrics guide, from the rate card, and from two of its own doc pages.

X-Autopilot Team··10 min read
On this page · 7 sections

The short version

  • ▸GET /2/tweets/analytics is live in API version 2.174 and returns 23 metrics per Post, up to 100 Posts a call, bucketed hourly, daily, weekly or total. It includes unfollows and unlikes, which the enterprise Engagement API metric table never carried.
  • ▸X's own metrics guide, the canonical page for getting impressions, does not mention this endpoint once. Neither does skill.md, the capability summary X publishes for AI agents. The only way to find it is the reference page or the OpenAPI description.
  • ▸Two of the four analytics pages in X's docs index are empty. Get 28 Hour Post Insights and Get Historical Post Insights point at /2/insights/28hr and /2/insights/historical, which appear nowhere in the live spec. Those are enterprise Engagement API routes behind a sales call.
  • ▸The rate card has no analytics row, read or write. The rate-limit reference has an Analytics section headed '1 endpoint' that lists /2/tweets/analytics at 300 per 15 minutes and omits /2/media/analytics entirely. One endpoint, two documents, zero numbers.
  • ▸Video counters are typed twice and disagree. The same metric is a plain integer at the top of a media analytics result and an integer-or-string inside the time buckets, because X preserves the backend value when it does not parse as a number.

Quick answer

X has a real post analytics endpoint, GET /2/tweets/analytics, live at API version 2.174. It takes 100 Post ids a call and returns 23 metrics each, bucketed hourly, daily, weekly or total, including two counters the old enterprise Engagement API never had: unlikes and unfollows. The reason almost nobody writes about it is that X's own metrics guide never mentions it, the rate card has no price for it, and two of the four analytics pages in X's documentation index are blank.

Last updated: November 2026

Everything below is checked against the live API description at api.x.com/2/openapi.json, version 2.174, and X's metrics, pricing and rate-limit pages, all read on 9 November 2026.

Two live endpoints, and two pages that render nothing

X's API v2 index lists four analytics and insights pages. Here is what is behind each one.

Doc pageDeclared operationIn the live spec?
Get Post Analyticsget /2/tweets/analyticsYes
Get Media Analyticsget /2/media/analyticsYes
Get 28 Hour Post Insightsget /2/insights/28hrNo
Get Historical Post Insightsget /2/insights/historicalNo

The bottom two pages load with HTTP 200 and render a title and nothing else. No path, no parameters, no response. Their page metadata still declares the operation they were generated for, which is how you learn the paths at all, and the string insights appears zero times in the live description.

That is not a doc bug so much as a product boundary showing through. /28hr and /historical are endpoints of the enterprise Engagement API, whose own page opens with the line that it is "available within our managed access levels only" and that you must first set up an account with the enterprise sales team. Its /28hr and /historical routes take 25 Posts a request, /totals takes 250, impressions only go back 90 days, and the historical window is one year keyed on engagement time rather than Post creation time. None of that is reachable with a card and a credit balance.

Artefacts of the older shape are still lying around. The TypeScript SDK reference documents Get2Insights28hrResponse and Get2InsightsHistoricalResponse, both typed as data: Engagement[], and there is no Engagement schema in the live spec at all. X deprecated the enterprise "Insights track" endpoints on 1 August 2023. Three years later the generated pages are still being published.

The self-serve replacement is the two endpoints that do exist, and they are quietly better than what they replaced.

23 metrics, two of them new

GET /2/tweets/analytics wants four things: ids (1 to 100), a required start_time and end_time, and an analytics.fields list. granularity is optional and defaults to total, with hourly, daily and weekly available.

The 23 field names break down like this:

  • Reach and engagement: impressions, engagements, media_views
  • Public interactions: likes, retweets, quote_tweets, replies, bookmarks, shares
  • Clicks: url_clicks, hashtag_clicks, detail_expands, permalink_clicks, user_profile_clicks
  • App conversion: app_opens, app_install_attempts, email_tweet
  • Audience change: follows, unfollows, likes reversed as unlikes
  • Envelope: id, timestamp, timestamped_metrics

Compare that against the enterprise Engagement API's metric table, which is the closest published reference point. Most of this list maps across one to one, with follows playing the role of the enterprise user_follows. Two do not map at all: unlikes and unfollows have no counterpart in the enterprise table. A per-Post count of people who unfollowed after seeing it, and of people who took a like back, has not been available through any documented X endpoint before this one.

Whether you should act on them is a different question from whether you can read them. A single Post rarely causes an unfollow on its own, and the metric gives you no attribution beyond the time bucket. What it is genuinely good for is finding the shape of a bad week: pull daily granularity across 100 Posts, line follows up against unfollows, and the days you lost ground stop being a mystery. Our guide to X engagement rate covers which ratios are worth tracking once you have the raw counters.

timestamped_metrics is the part worth building around. It returns an array with one entry per granularity bucket, each holding a timestamp and a metrics object with 20 of the counters, every one nullable. So a null is not a zero: it means X returned nothing for that bucket, and treating the two as the same thing will quietly invent engagement that never happened.

Three ways to ask X for impressions, and they do not agree

This endpoint did not replace the older routes, it was added beside them. There are now three ways to get a Post's numbers, with different prices, windows and shapes.

RouteWindowScopeWhat you get
post.fields=public_metricsAny PostAny auth6 counters, public totals only
post.fields=non_public_metrics,organic_metricsPosts from the last 30 daysYour own Posts, user contextPrivate breakdown, no time series
GET /2/tweets/analyticsstart_time to end_time, no published limitUser context23 metrics plus buckets

The 30-day wall on the second row is the one that sends people looking. X states it plainly on its metrics page: non-public, organic and promoted metrics are only available for Posts created within the last 30 days. The analytics endpoint publishes no equivalent limit, which is not the same as having none. Nothing in the spec, the rate-limit page or the pricing page says how far back start_time may reach, and the enterprise endpoint it descends from capped impressions at 90 days. Test your own ceiling rather than inferring one.

Then the detail that explains why this endpoint is so obscure. X's metrics page is the canonical answer to "how do I get impressions from the X API". It documents the three field-based routes, the 30-day limit, the organic-versus-promoted split, and the warning that you cannot request metric subfields. The word analytics appears on it zero times. The fields page offers a "Post analytics" field recipe that is just public_metrics. And skill.md, the structured capability summary X publishes so that AI agents can discover what the platform does, mentions neither analytics nor insights.

So the SERP for this query is full of resellers describing non_public_metrics, because that is what X's own guides describe. The endpoint that answers the question better is one index entry away, documented by an auto-generated page whose own summary line reads "Reference documentation for the endpoint" with the name missing.

If what you want is the human version of these numbers rather than the JSON, our walkthrough of X analytics covers the native dashboard, and what X's expansions and fields actually cost covers the field parameters above.

Video metrics are typed twice, and the two types disagree

GET /2/media/analytics is the video sibling. It takes media_keys instead of ids, up to 100, each matching the two-part digits_digits media key format, with the same required start_time and end_time. Its granularity drops weekly and defaults to daily rather than total, so the same code pointed at both endpoints gets differently shaped responses from identical parameters.

Thirteen fields: video_views, watch_time_ms, play_from_tap, playback_start, playback25, playback50, playback75, playback_complete, cta_url_clicks, cta_watch_clicks, media_key, timestamp, timestamped_metrics.

Two things there will cost you an afternoon.

The playback metrics have two different names in one API. On this endpoint they are playback_start, playback25, playback50, playback75, playback_complete. Through media.fields=non_public_metrics on a Post lookup, the same five counters are playback_0_count, playback_25_count, playback_50_count, playback_75_count, playback_100_count. Same five numbers, two vocabularies, no mapping table anywhere.

The counter types contradict each other. At the top level of a media analytics result, every counter is declared integer. Inside timestamped_metrics, the same counters are declared integer or string, with an unusually candid description: a counter is "an integer when the backend value parses as a number, otherwise the original string." X is telling you, in the spec, that something upstream can hand back a non-numeric value and that it will pass it through rather than fail. The post analytics buckets have no such escape hatch, only nullable integers. If you generate a client from this spec and feed both endpoints through one parser, the media time series is where it breaks.

Getting the media keys in the first place is the step before all of this, and the upload flow that produces them is in X API media upload.

No price row, and one rate limit for two endpoints

The pay-per-use rate card is specific down to $0.001 per block read. It names twelve read resources and sixteen write actions. None of them is analytics, insights or engagement. The only occurrence of the word on the page is a tip saying Owned Reads make it cheaper to build "personal analytics" apps, and the Owned Reads table itself lists twelve routes, none of them an analytics endpoint.

Rate limits are nearly as thin. The reference has a section headed "Analytics (1 endpoint)" with a single row: GET /2/tweets/analytics, 300 per 15 minutes per app and per user. /2/media/analytics is in no table, including the ten-route "Other endpoints" catch-all that does cover oddities like DELETE /2/connections/all.

So what does a call cost? The honest answer is that nothing published says, and the two plausible readings are far apart. Analytics is a read, and reads are billed per resource returned, which would make a 100-Post call 100 resources of something. There is no row naming that something. 300 requests per 15 minutes at 100 ids is 30,000 Posts a window, so if it bills at the Posts: Read rate of $0.005 the ceiling is $150 per 15 minutes, and if it bills at nothing it is free. Do not guess from a neighbouring row. Run one call with a known number of ids, check the Developer Console balance before and after, and derive the unit yourself. How the rest of the card behaves, including the daily deduplication that makes a second read of the same resource free, is in X API pricing, and the per-namespace ceilings are collected in X API rate limits.

Auth is the one uncomplicated part. Post analytics wants tweet.read and users.read; media analytics wants tweet.read alone. Both accept OAuth 1.0a as an alternative. Both are user context, so you are only ever reading Posts the authorising account owns.

What to build with it

Three uses where this endpoint earns its obscurity premium.

Decay curves. granularity=hourly over a 48-hour window tells you how long a Post actually kept collecting impressions, per Post, rather than as an average. That is the number most posting-schedule advice is missing, and it is why we measured how long an X post keeps getting views rather than repeating the folklore.

Click attribution that survives. url_clicks, permalink_clicks and detail_expands are three different intents collapsed into one number by most dashboards. Separated and bucketed, they tell you whether people left for your link or stayed to read the thread.

Audience accounting. follows minus unfollows, per Post, per day. Nothing else published gives you the second term.

What it will not do is tell you about anyone else's Posts. This is owned-content analytics, user context only, and there is no public equivalent beyond public_metrics. If your plan needs competitor numbers, you are back to counting what the lookup endpoints return.

And if the goal behind the dashboard is simply an account that keeps posting and replying while you are elsewhere, the metrics are the scoreboard rather than the game. X-Autopilot runs on your own Mac in your own browser session, so there is no shared cloud IP pool and no delegate account in the path, which is a smaller detection surface than a hosted scheduler rather than an absent one. Driving engagement through a browser sits in a gray area under X's automation rules rather than being something X endorses. The analytics endpoints above are fully sanctioned, and they are the cleanest way to find out whether any of it worked.

Frequently asked

Answers indexed by Google + AI assistants.

What is the X API analytics endpoint?+

GET /2/tweets/analytics. You pass up to 100 Post ids, a required start_time and end_time, an optional granularity of hourly, daily, weekly or total, and an analytics.fields list chosen from 23 metric names. It returns one object per Post with the totals, and a timestamped_metrics array with one bucket per granularity interval. Auth is OAuth 2.0 user context with tweet.read and users.read, or OAuth 1.0a. There is a companion endpoint, GET /2/media/analytics, for video.

Can I get Post impressions from the X API?+

Three ways, and they are not equivalent. public_metrics.impression_count on a Post lookup gives the public total for any Post. post.fields=non_public_metrics and organic_metrics give the private breakdown for Posts you own, but only for Posts created in the last 30 days. GET /2/tweets/analytics gives a time series over a window you choose. The first is cheapest, the third is the only one that answers when the views happened.

What metrics does /2/tweets/analytics return?+

23 field names: impressions, engagements, likes, unlikes, retweets, quote_tweets, replies, bookmarks, shares, follows, unfollows, media_views, url_clicks, hashtag_clicks, detail_expands, permalink_clicks, user_profile_clicks, app_opens, app_install_attempts, email_tweet, id, timestamp and timestamped_metrics. Every counter is also available per time bucket inside timestamped_metrics.

How much does the X API analytics endpoint cost?+

Nothing published says. X's pay-per-use rate card names twelve read resources and sixteen write actions, and the word analytics appears on that page only inside a tip about Owned Reads. No row covers /2/tweets/analytics or /2/media/analytics. Measure your credit balance across one real call before you budget anything on it.

Why are the X post insights doc pages empty?+

Because the operations they point at are not in the API description the docs site renders. Both pages load, both appear in X's documentation index, and both declare an OpenAPI operation in their page metadata: get /2/insights/28hr and get /2/insights/historical. Neither path exists in the live spec at version 2.174, where the string insights does not appear at all. The real /28hr and /historical endpoints belong to the enterprise Engagement API, which requires an account set up through X's enterprise sales team.

Sources
Related searches
x api analytics/2/tweets/analyticsx api post analyticsx api impressions endpointtwitter api analytics 2026x api media analyticsx api non_public_metricsx api engagement metricsx analyticsx api pricingx api rate limitsx engagement ratetwitter analytics apipost impressions apix api v2 fields
DY
Deepak YadavBuilding X-Autopilot

Product designer and indie hacker. Runs the agent on his own X account every day and writes up what the data shows, including when it's inconvenient.

Follow on X →
Try X-Autopilot.
7-day offer: $199 $9 once. No subscription, no monthly bill. Real Chrome on your Mac.
See pricing▶
Free PDF · the X Growth Playbook

The exact playbook we use to grow on X

The bio that converts, the daily reply loop, the posting cadence, and the tool stack, in one no-fluff PDF. Drop your email and it's yours.

No spam. Unsubscribe anytime.

Free tools

Try it yourself.

All free X tools →
Keep reading

Related posts.