# X/Twitter Statistics in 2026: What an API Can Actually Measure, and What Nobody Can > Most X statistics roundups re-cite the same handful of numbers. We measured what a public API can and cannot see across 34 accounts, printed the query behind every figure, and traced the rest to their real sources. - **URL:** https://www.twitterapis.com/blogs/x-twitter-platform-statistics-2026 - **Published:** 2026-09-10 - **Author:** Emma - **Tags:** twitter statistics, x statistics, twitter api, x api, platform data, social media measurement --- Every article you have read about X statistics is citing another article about X statistics. That is not a figure of speech. We opened the three most-cited pages in the live search result for this topic and followed their attributions, and not one of them measured anything. Between them they publish four different daily-active-user figures, ranging from 132 million to 251 million, none first-party and none from the same year. Two of them publish the same number, 557 million, attributed to the same source, and label it as two different metrics. > **TL;DR:** X stopped publishing routine usage metrics when it went private, so no current user number in circulation is a first-party disclosure. A public API cannot fill that gap, because platform aggregates are not exposed by any endpoint. What it can do is measure account-level and post-level facts precisely and cheaply. We measured 34 accounts, 36 response fields, two endpoints against each other and three response-time profiles, tagged every figure as measured, cited or estimated, and printed the query behind each measured one. This article is organised around a single rule: every number carries a tag at the point of use. **MEASURED** means we ran a query, and the endpoint, the parameters and the run timestamp are printed beside the figure so you can re-run it and get your own value. **CITED** means a third party published it, we attribute it inline, and we did not independently verify the underlying number. **ESTIMATED** means somebody modelled it, and we say who and how. That sounds like bookkeeping. It is the entire difference between this page and the pages currently ranking above it, none of which distinguishes a measurement from a re-citation, which is how [a company claim from 2023](https://searchengineland.com/guide/twitter-users) ends up being read as a current fact in 2026. ::directive{id="img-1"} ::directive{id="img-14"} One more thing before the numbers. We are not publishing a bot-share percentage, and the reason is in the data rather than in caution. More on that below, with the measurement that settles it. ## What changed: X stopped reporting, and the statistics industry did not notice The reason this whole category is strange is a corporate event rather than a technical one. When Twitter was a public company it filed quarterly results, and those filings were the primary source that every roundup ultimately rested on. The company even maintained its own custom headline metric, monetizable daily active usage, usually written mDAU, which it defined as accounts that could be shown advertising. That definition mattered: mDAU was deliberately narrower than a plain daily-active count, and it was never directly comparable to the daily-active numbers other platforms reported. Anyone comparing Twitter to a peer on daily actives in that era was already comparing two different definitions. After the acquisition and the move to private ownership, the filings stopped. Search Engine Land says so directly in its own guide (**CITED**, [Search Engine Land](https://searchengineland.com/guide/twitter-users), page last updated 4 September 2026): > "Since Twitter's acquisition by Elon Musk, there have been irregular updates on Twitter usage as the company is no longer public and no longer shares regular usage metrics with the public." DemandSage says the same thing in different words (**CITED**, [DemandSage](https://www.demandsage.com/twitter-statistics/), page last updated 13 March 2026): > "Since 2022, the daily active user count has been reported as a private company metric, based on public statements from X/Twitter leadership." And Sprout Social is explicit about the most basic metric of all (**CITED**, [Sprout Social](https://sproutsocial.com/insights/twitter-statistics/), page last updated 10 March 2026): > "Although there's no publicly available data on X's monthly active users (MAU)..." Read those three sentences together and the category collapses. The three most-cited statistics pages for this topic all state, in their own words, that the numbers are not published on a routine basis. Everything downstream of that is an estimate, a company statement, or an app-analytics reading, and the honest version of an X statistics article has to start by saying so. What did not happen is the part worth noticing. The volume of X statistics content did not fall when the primary source disappeared. It went up. The numbers simply detached from their source and kept circulating, and because each page cites a different intermediary, the disagreements are invisible unless you put the pages side by side. ## The numbers everyone cites, and where they actually come from We opened all three pages and recorded what each attributes every figure to. This is the part we could not shortcut, because a search-result snippet gives you the number and hides the attribution, and the attribution is the story. ::directive{id="dt-citation-trace"} Ten figures, zero measurements, and three contradictions sitting in plain sight. **Contradiction one.** Search Engine Land publishes a monthly-active-user number sourced to DataReportal. Sprout Social states that no publicly available monthly-active-user data exists. Both rank on the first page for the same query, and they cannot both be right about whether the metric is knowable. **Contradiction two, and this is the one that should end the category's credibility.** The number **557 million** appears on two different pages, attributed to the same source, Statista, and labelled as two completely different metrics. Sprout Social calls it **potential ad reach**. DemandSage calls it **monthly active users**. Those are not near-synonyms. Potential ad reach is an advertising-platform estimate of addressable audience, which routinely includes accounts a usage metric would exclude and is produced by a different system for a different purpose. One of those two labels is wrong, and a reader taking either page at face value has no way to tell which. **Contradiction three.** There are four daily-active figures in that table: 132 million, "200 to 250 million", 237.8 million and 251 million. They span a range of roughly 119 million, they come from three different intermediaries, and they refer to at least three different years, one of which is 2022. Every one of them is presented on a page carrying a 2026 date. ::directive{id="img-2"} There is a fourth thing worth recording, and it is the kind of detail that only turns up if you actually open the links rather than reading the snippet. The single most-cited page in this cluster, the Backlinko guide to X user counts, no longer serves its own content: the URL now redirects to searchengineland.com (**MEASURED**, HTTP request on 10 September 2026, final URL `https://searchengineland.com/guide/twitter-users` after redirect, HTTP 200). A large share of the inbound citations in this category point at a page that has changed hands, which means the "two independent sources" a careful reader thinks they have are sometimes one source wearing two names.
Had a call with Reddit to discuss pricing. Bad news for third-party apps, their announced pricing is close to Twitter's pricing
by u/iamthatis in r/apolloapp
That thread is about a different platform, and it is here because it is the clearest public record of the mechanism rather than the specifics. When platform data access is repriced, the independent measurement layer around that platform thins out, and what is left is a smaller number of publishers citing each other. 165,623 upvotes and 11,963 comments (**MEASURED**, via our own Reddit data API on 10 September 2026) is a developer ecosystem reacting in real time to exactly that. ## What we measured, and how to re-run it Everything in this section was produced by a small harness that makes plain HTTP calls to a public X data API and writes one JSON file with a run timestamp. Two notes on method, both of which changed a result during this work and are therefore worth your time. **The harness failed completely on its first run.** Every single call returned `CERTIFICATE_VERIFY_FAILED`, which looks exactly like a dead API and is actually a missing certificate bundle on the calling machine. What caught it was a negative control: we deliberately query a handle that must not exist, and on that run it failed identically to the real accounts. Identical failures including the one that was supposed to fail is an instrument problem, not a data problem. After pointing the client at a proper certificate bundle, the real accounts returned and the fake handle returned HTTP 404, which is what a working probe looks like. **We nearly published a false finding.** An early pass read a field called `like_count` and found it empty on every post, which reads like a striking result about missing engagement data. It is not a result at all. The field in the response is `favourite_count`, and it is fully populated on every post we checked. `like_count` is absent from the payload entirely, so reading it returns nothing and a careless script records a silent zero across the board. That is a genuine trap worth knowing about, but it is a trap about field names, not about data availability, and publishing the first version would have invented a defect that does not exist. ### Thirty four accounts, measured directly Queried through the user endpoint, one call per account (**MEASURED**, `GET /twitter/user/info?userName=`, run 2026-09-11). Thirty four of thirty five handles resolved. The one that did not, `jpl`, returned HTTP 404, as did the deliberately fake control handle, so the probe distinguishes a real account from an absent one. The sample was chosen to spread across news organisations, science and government bodies, developer-tool companies and small accounts, rather than to be representative of the platform, which it is not and cannot be. ::directive{id="dt-measured-accounts"} These are snapshots. They were true at the run timestamp and they are already slightly wrong, which is the correct way to think about every number on this page and on every other page in this category. Two observations that only appear because the numbers sit together. @reuters has posted 1,394,404 times with 1,013,840 media items attached, which is a fundamentally different publishing operation from @cern at 7,934 posts, and any "average posts per account" figure computed across a mixed set like this is close to meaningless. And @apnews, at 16,606 followers and 567 posts, is clearly not the primary account of that news organisation, which is a reminder that handle-based lookup answers the question you asked rather than the question you meant. ::directive{id="img-3"} ::directive{id="img-13"} ### What the user endpoint actually returns This is the measurement that surprised us most, and it is the one that does the most work later in this article. The account payload carried **36 distinct fields** across the 34 accounts (**MEASURED**). They split three ways. **Always populated, 18 of 36** (present and non-empty on all 34 accounts): `id`, `username`, `name`, `description`, `followers_count`, `following_count`, `tweet_count`, `favourites_count`, `media_count`, `created_at`, `profile_image_url`, `is_blue_verified`, `verified`, `protected`, `possibly_sensitive`, `profile_bio`, `type`, `unavailable`. **Never populated, 11 of 36** (empty on all 34): `listed_count`, `can_dm`, `default_profile`, `default_profile_image`, `has_custom_timelines`, `is_translator`, `is_automated`, `automated_by`, `withheld_in_countries`, `unavailable_message`, `unavailable_reason`. **Sometimes populated, 7 of 36**: `url` (33 of 34), `cover_picture` (32 of 34), `location` (24 of 34), `verified_type` (21 of 34), `pinned_tweet_ids` (14 of 34), `professional_type` (12 of 34), `affiliate_label` (3 of 34). ::directive{id="img-4"} Here is the methodological point, and we are including it because it argues against our own first draft. We originally ran this across 10 accounts, and at that size `cover_picture` appeared in the always-populated group at 10 of 10. Expanding the sample to 34 moved it to 32 of 34. Nothing about the API changed between those two runs. The smaller sample simply had not yet met an account without a cover image. If a field-availability profile is load-bearing for your code, measure it across a sample that includes the awkward cases, and treat "always" from a small sample as "not yet seen otherwise". Now hold on to the second group. `is_automated` and `automated_by` are the two fields that would tell you whether an account is a declared bot, and they were empty on **34 of 34**. We come back to that. ### Two endpoints, same posts, different answers This one is short and it changes how you should read every engagement figure you have ever seen. We took eight posts from one account, read their engagement counters from a search endpoint, then immediately read the same eight posts through the single-post endpoint, in the same run, seconds apart (**MEASURED**, `GET /twitter/tweet/advanced_search` then `GET /twitter/tweet/detail?tweet_id=`, 2026-09-11). The favourite count matched exactly on **3 of 8**. The view count matched exactly on **5 of 8**. | Post | Favourites, search then detail | Views, search then detail | |---|---|---| | 2098168685013729468 | 633 then 630 | 279,968 then 279,095 | | 2098078917751951729 | 1,357 then 1,358 | 436,005 then 436,005 | | 2097371299274228208 | 17 then 17 | 6,174 then 6,174 | | 2097361251856781396 | 7,453 then 7,466 | 1,153,471 then 1,153,463 | | 2095942995585495196 | 7 then 7 | 4,718 then 4,718 | | 2095890075447964086 | 343 then 343 | 177,998 then 178,000 | | 2095890073031966734 | 1,888 then 1,885 | 972,985 then 972,985 | | 2095585125627003244 | 3,818 then 3,820 | 931,656 then 931,656 | Two things stand out. The differences run in **both** directions, so this is not simply counters ticking up between calls. And the disagreement concentrates on the busiest posts: the largest view gap, 873, is on the newest post in the set, while the older quiet posts agree exactly. ::directive{id="cb-endpoint-agreement"} ::directive{id="img-5"} We are not going to assert a mechanism for this, because we did not measure one and a plausible story is not a finding. What we will assert is the practical consequence, which is solid: an engagement number is a reading taken by one endpoint at one moment. If you are reporting one, record which endpoint produced it and when. If you are comparing two, make sure they came from the same endpoint, or you are measuring the endpoints as much as the posts. ### Response times Five runs per endpoint, median reported (**MEASURED**, 2026-09-11). | Endpoint | Median | Fastest | Slowest | |---|---:|---:|---:| | `user/info` | 0.751 s | 0.730 s | 0.820 s | | `trends` | 0.869 s | 0.751 s | 1.206 s | | `tweet/advanced_search` | 3.020 s | 2.263 s | 3.179 s | Search is roughly four times slower than a point lookup at the median. That is the single most useful number here for anyone planning a collection job, because it decides whether you paginate search or resolve ids directly. Our [reliability measurements](/blogs/twitter-api-reliability-measured-2026) go into the stability side of this in more depth, and the [rate limit guide](/blogs/twitter-api-rate-limit-guide) covers what happens when you push it. ::directive{id="cb-latency"} ::directive{id="img-6"} ### Trend coverage The trends endpoints answer a question people assume is unanswerable, and the answer is a plain number. `GET /twitter/trends/locations` returned **467** available trend locations (**MEASURED**, 2026-09-11). `GET /twitter/trends?woeid=1`, the global location, returned **50** trends in a single response (**MEASURED**, same run). ::directive{id="img-10"} That is a real, current, first-party figure about the shape of the platform's public surface, and it took two calls and under two seconds. There is more on how to use these in the [trends API guide](/blogs/twitter-trends-api-guide). The same community recorded the end state a month later, and it is the clearest single artefact of what happens to an independent measurement layer when access economics change.
Apollo will close down on June 30th. Reddit's recent decisions and actions have unfortunately made it impossible for Apollo to continue
by u/iamthatis in r/apolloapp
221,225 upvotes and 15,278 comments (**MEASURED**, via our own Reddit data API on 10 September 2026). Again, a different platform, and again the mechanism rather than the specifics: the tools that measured and surfaced platform data independently went away, and the publishers left standing were the ones that cite rather than measure. That is the same shape as the X statistics cluster, one step further along. If you want to reproduce the counter-disagreement finding rather than take our word for it, this is the whole comparison, and it needs two endpoints and one loop: ```python search = get("twitter/tweet/advanced_search", {"query": "from:nasa", "product": "Latest"}) agree_fav = agree_views = 0 posts = search["tweets"][:8] for post in posts: detail = get("twitter/tweet/detail", {"tweet_id": post["id"]}) tweet = detail.get("tweet") or detail if post["favorite_count"] == tweet["favorite_count"]: agree_fav += 1 if post["view_count"] == tweet["view_count"]: agree_views += 1 print(post["id"], post["favorite_count"], "->", tweet["favorite_count"], post["view_count"], "->", tweet["view_count"]) print(f"favourites agreed on {agree_fav} of {len(posts)}") print(f"views agreed on {agree_views} of {len(posts)}") ``` Run that and print both totals rather than a single agreement rate. The direction of each disagreement is the informative part, and an aggregate percentage hides it: our run had differences going up and down on the same eight posts, which a single blended agreement rate would have flattened into something that looks like ordinary measurement noise around a true value. It is not noise around a true value. It is two endpoints answering the same question differently at the same instant. ## Measurable or not: twenty metrics, sorted honestly This is the table the incumbent pages do not print, and it is the most useful thing here if you are deciding whether a number you need can be obtained at all. | Metric | Measurable from a public API? | Why | |---|---|---| | Follower count for a named account | Yes | Returned directly, populated on 34 of 34 | | Following count for a named account | Yes | Returned directly, populated on 34 of 34 | | Post count for a named account | Yes | Returned directly, populated on 34 of 34 | | Media count for a named account | Yes | Returned directly, populated on 34 of 34 | | Account creation date | Yes | Returned directly, populated on 34 of 34 | | Blue verification status | Yes | Returned directly, populated on 34 of 34 | | Protected status | Yes | Returned directly, populated on 34 of 34 | | Engagement counters on a named post | Yes, with a caveat | Returned, but two endpoints disagreed on 5 of 8 posts | | Posts matching a query | Yes, as a sample | Search returns matches, not a guaranteed complete set | | Available trend locations | Yes | 467, measured | | Trends for a location | Yes | 50 for the global location, measured | | Whether an account is a declared bot | No | `is_automated` empty on 34 of 34 | | Account list memberships | No | `listed_count` empty on 34 of 34 | | Daily active users | No | Internal metric, no endpoint | | Monthly active users | No | Internal metric, no endpoint | | Total accounts on the platform | No | The account set cannot be enumerated | | Total posts per day, platform-wide | No | The corpus cannot be enumerated | | Revenue | No | Private company, no filing, no endpoint | | Ad impressions and ad spend | No | Advertising system, not a public data surface | | Deleted or suspended account volumes | No | Not exposed, only per-account absence is observable | ::directive{id="cg-measurable-or-not"} ::directive{id="img-12"} The pattern in that table is the single idea worth taking away from this article. A public API is an instrument for **named things**. Give it an account, a post, a query or a place and it will tell you a great deal, quickly and cheaply. Ask it about the platform as a whole and it has nothing, because platform aggregates are computed inside the company from data that never leaves it, and no amount of sampling reconstructs them without a published sampling rate that also does not exist. ## What does no public API expose about X? No public X API exposes daily actives, monthly actives, revenue, ad impressions, total platform post volume, total account count, or declared bot status. Those are internal metrics computed inside the company from data that never leaves it, and no sampling strategy reconstructs them from outside. Expanding on the bottom half of that table, because the reasons differ and the differences matter. **Daily and monthly active users.** These are internal product metrics computed from session data. No public endpoint exposes them, no sampling strategy reconstructs them, and every published figure is either a company statement or an outside model. When Sprout Social writes that there is no publicly available monthly-active-user data, that is not a gap in their research, it is the actual state of the world. It also sits oddly beside DemandSage publishing a monthly-active figure of 557 million, which is contradiction two from earlier. **Revenue, ad spend and ad impressions.** X is private. There is no filing obligation and no endpoint. The $2.5 billion 2024 revenue figure [DemandSage](https://www.demandsage.com/twitter-statistics/) carries is attributed to Business of Apps, which is an analytics publisher rather than the company. **Total posts per day across the platform.** You can count posts matching a query. You cannot count all posts, because you cannot enumerate the whole corpus, and any extrapolation from a sample to a platform total requires knowing the sampling rate, which is not published. **Total account count, and how many are active.** Same problem, harder. You can measure any account you can name. You cannot enumerate the set of all accounts, and a name-based instrument cannot produce a population count. **Account list memberships.** A small but concrete example of the same class: `listed_count` is a documented field and it came back empty on 34 of 34 accounts. A field existing in a response shape is not the same as a field carrying data. **Deleted and suspended account volumes.** Not exposed. You can observe that one specific account is gone, which is a much smaller claim than a rate. **Anything about a protected account beyond its existence.** By design, and correctly so. ::directive{id="img-7"} That distinction is worth stating plainly because it is routinely papered over. An article that lists "561 million monthly active users" next to "the average post gets N engagements" is mixing a third-party model with a measurement and presenting them in the same typeface. They are not the same kind of claim and they do not deserve the same confidence. That post drew 168 favourites and 148,525 views (**MEASURED**, read by id through our own API on 10 September 2026). It is the clearest public statement of the causal chain this article keeps running into: the measurement layer around a platform is a function of what access costs. In fairness to the platform, the same developer later wrote that the pricing had improved, and an X employee publicly framed the earlier limits as a response to abuse rather than a revenue decision. Both of those are real parts of the record and quoting only the complaint would misrepresent it. The platform side of that exchange is on the record too, and it reframes the constraint as an abuse decision rather than a pricing one. That post drew 370 favourites and 45,855 views (**MEASURED**, read by id on 10 September 2026). Both things are true at once: access was expensive enough to thin out independent measurement, and the limits were a response to real abuse. Neither fact rescues a statistic whose source nobody checked. ## What percentage of X accounts are bots, and why is there no number here? Nobody can currently answer this from public data, and this article deliberately publishes no percentage. The two account fields that would answer it, is_automated and automated_by, came back empty on 34 of 34 accounts we measured, so bot status is simply not readable from the account payload. This was going to be a headline number. It is not, and the reason is a measurement rather than an attack of nerves. A bot share is not a count, it is a **classification**, and a classification is only as good as the rule behind it. To publish a defensible figure you need five things stated up front: the population you sampled from, how you sampled it, the exact rule that labels an account automated, the sample size, and two controls, accounts you know are automated that the rule catches, and accounts you know are human that the rule must not flag. Here is the problem, and it is the field-availability measurement from earlier doing real work. The two fields on the account payload that would answer this directly, `is_automated` and `automated_by`, came back empty on **34 of 34** accounts (**MEASURED**, 2026-09-11). The platform's own automation labelling is not readable through this surface at all. That leaves building your own classifier out of proxies: account age, default profile image, posting cadence, follower-to-following ratio, handle patterns. Every one of those is available in the payload. None of them is a bot detector. They are correlates, they are trivially defeated by anyone actually running a bot farm, and they systematically misfire on real humans who joined recently, never set an avatar, post a great deal, or follow more accounts than follow them. Look at the measured table above and you can see the misfire risk directly. @golang follows 0 accounts and @rustlang follows 2, giving both an extreme follower-to-following ratio. @reuters has posted 1,394,404 times, a cadence no human sustains. @apnews has 567 posts and 0 media. Every one of those is an unremarkable, legitimate account, and every one of them would trip at least one naive automation heuristic. A rule built from these signals, applied to a convenience sample, produces a percentage that would be indistinguishable in presentation from a real one. ::directive{id="img-8"} So the honest answer to "what percentage of X is bots" is that we do not know, the fields that would tell us are empty, and anybody publishing a current figure should be asked for their population, their rule, their sample size and their two controls before the number is repeated. Notice that the most recent framing of this question that surfaces publicly is a [Quora thread asking about 2022](https://www.quora.com/What-percentage-of-Twitter-users-are-bots-as-of-2022), which tells you how long it has been since anyone measured it in the open. What a real study would need is not mysterious, it is just expensive: a defined population with a known sampling frame, a labelled training set built by human review, a published classifier with precision and recall reported against a held-out set, and an honest false-positive rate. That is a research project, not a section in a blog post, and pretending otherwise is how an invented number enters circulation and stays there for years. Our [bot detection guide](/blogs/twitter-bot-detection-guide) covers what the individual signals can and cannot support. ## A worked example: engagement rate, and the four ways to get it wrong Engagement rate is the most commonly quoted derived statistic about X, and it is a good demonstration of why provenance tagging matters more than precision. Take the first post in our drift table, id 2098168685013729468, measured at 633 favourites, 93 reposts, 41 replies, 9 quotes, 36 bookmarks and 279,968 views through the search endpoint (**MEASURED**, 2026-09-11). **Mistake one: which denominator.** Engagement rate against views gives roughly 0.3 percent. Engagement rate against the author's follower count gives a completely different number. Both are published as "engagement rate" by different tools, and neither is wrong so long as it says which it is. A figure quoted without its denominator is not a statistic, it is a number. **Mistake two: which numerator.** Do bookmarks count? Do quotes count separately from reposts? Different tools answer differently, and the spread between the narrowest and broadest definitions on this single post is large enough to change the headline. **Mistake three: which endpoint.** We measured that same post at 633 favourites from search and 630 from the single-post endpoint, and 279,968 views versus 279,095, within seconds. Any rate computed from these moves depending on which call produced the inputs. **Mistake four: when.** All of the above were read at one instant on a post that was actively accumulating engagement. An hour later every input is different. None of that makes engagement rate useless. It makes it a **derived** figure that has to carry its definition, its endpoint and its timestamp to mean anything. That is why this article tags figures at the point of use rather than in a footer, and it is why we have published no single headline engagement number: we would have had to pick one of at least eight defensible combinations and present it as the answer. ## How do you measure X yourself? You measure X yourself by calling a public data API for named entities, one account or post at a time, and recording the endpoint, the parameters and the run timestamp beside every number you keep. Everything above is reproducible with well under a hundred calls, for a few cents in total. This is the whole method. A standard read on twitterapis.com is `$0.0008` per call, and signup includes `$0.50` in free credits, which covers roughly 625 standard calls (**CITED**, twitterapis.com pricing). The entire measurement set in this article cost a few cents, which is the practical point of the whole piece: for account-level and post-level facts, independent measurement is no longer the expensive part. Resolve one account: ```bash curl -s -H "Authorization: Bearer $TWITTERAPIS_KEY" \ "https://api.twitterapis.com/twitter/user/info?userName=nasa" ``` Read a specific post's counters: ```bash curl -s -H "Authorization: Bearer $TWITTERAPIS_KEY" \ "https://api.twitterapis.com/twitter/tweet/detail?tweet_id=2098168685013729468" ``` Pull the trend locations count that produced the 467 figure above: ```bash curl -s -H "Authorization: Bearer $TWITTERAPIS_KEY" \ "https://api.twitterapis.com/twitter/trends/locations" ``` The field-availability measurement in Python, which is the one worth copying because it is the one that tells you what you can actually rely on: ```python import json, os, ssl, urllib.request, urllib.parse import certifi CTX = ssl.create_default_context(cafile=certifi.where()) HDRS = {"Authorization": f"Bearer {os.environ['TWITTERAPIS_KEY']}"} def get(path, params): url = f"https://api.twitterapis.com/{path}?" + urllib.parse.urlencode(params) req = urllib.request.Request(url, headers=HDRS) with urllib.request.urlopen(req, timeout=45, context=CTX) as r: return json.loads(r.read()) accounts = ["nasa", "github", "openai", "vercel", "golang", "rustlang"] seen = {} for handle in accounts: user = get("twitter/user/info", {"userName": handle}) for key, value in user.items(): slot = seen.setdefault(key, {"populated": 0, "empty": 0}) slot["populated" if value not in (None, "", []) else "empty"] += 1 for key, counts in sorted(seen.items()): print(f"{key:<26} populated={counts['populated']} empty={counts['empty']}") ``` Three things in that snippet are load-bearing, and each is the reason a specific earlier run produced nothing or produced something wrong. [`certifi.where()`](https://pypi.org/project/certifi/) is not decoration. Without an explicit certificate bundle this fails with `CERTIFICATE_VERIFY_FAILED` on every call, and a total failure reads like a dead API rather than a local trust-store problem. The empty check tests for `None`, empty string and empty list together, because a field that comes back as `[]` is telling you the same thing as a field that comes back as `null`, and counting them differently gives you a wrong availability profile. And the loop counts every key the response **actually contains** rather than a list of keys you expect. That is how you discover that `like_count` is not in the payload at all, instead of quietly recording zeros for it across your whole dataset. Add a negative control before you trust any of it: ```python try: get("twitter/user/info", {"userName": "zzq_not_a_real_handle_9931"}) print("PROBE BROKEN: a fake handle resolved") except Exception as exc: print("control ok, fake handle rejected:", exc) ``` If that fake handle resolves, or if it fails in the same way your real accounts fail, you are not measuring X, you are measuring your own client. That single check is what caught our certificate problem before it became a published finding. ::directive{id="img-11"} ::directive{id="img-16"} The [API reference](/blogs/twitter-api-reference) has the full endpoint surface, [authentication](/blogs/twitter-api-authentication) covers key handling, and [pagination](/blogs/twitter-api-pagination) matters the moment you go past a single page of results. https://www.youtube.com/watch?v=1gQ6uG5Ujiw That full tutorial walks tweet collection through to visualisation and sentiment analysis in Python, which is the analysis layer that sits on top of everything measured above. freeCodeCamp.org, 232,205 views at time of writing (**MEASURED**, via yt-dlp on 10 September 2026). ## Five measurement mistakes worth avoiding Five failure modes that each produce a confident, wrong number: reading a field name the payload does not contain, running without a negative control, treating a small sample's always as always, comparing figures taken from different endpoints, and quoting a derived figure without its definition. Collected from this run rather than from general principle, and we made the first two ourselves. **Reading a field name that is not in the payload.** `like_count` versus `favourite_count`. The failure is silent: your code gets nothing, records a zero, and the dataset looks complete. Enumerate the keys the response contains before you write code that reads specific ones. **Running without a negative control.** If every call fails, a probe with no control cannot tell you whether the API is down or your client is broken. The control costs one call. **Treating a small sample's "always" as always.** `cover_picture` was 10 of 10 at one sample size and 32 of 34 at another. Nothing changed except how many accounts we looked at. **Comparing numbers from different endpoints.** We measured two endpoints disagreeing on the same post's view count by 873 within seconds. If your before-and-after used different calls, part of your delta is the instrument. **Quoting a derived figure without its definition.** Engagement rate has at least two plausible denominators and several plausible numerators, and the spread between them is bigger than most of the differences people report as findings. ## What to measure instead, when the platform number does not exist Most people arriving at an X statistics page do not actually need a platform-level number. They need to answer a question about something specific, and reached for the platform figure because it was the thing on offer. Here are four common questions, each rewritten into a form a public API can actually answer. **"How big is X?" becomes "how big is the audience I can reach on X?"** The platform total is unavailable and would not help you anyway. What is available is precise: the follower counts of the accounts in your space, measured directly and cheaply. In our run, thirty four lookups took under a minute and cost a few cents. A list of the fifty accounts that matter in your category, measured monthly, tells you far more about your addressable audience than any global figure, and it has the enormous advantage of being a measurement rather than somebody's model. **"Is X growing?" becomes "are the accounts I care about growing?"** Platform growth is not observable from outside. Per-account growth is trivially observable: record follower counts on a schedule and diff them. The only discipline required is the one this article keeps repeating, which is to record the timestamp and the endpoint alongside the number, because a follower count without a timestamp cannot be differenced against anything. **"What is the average engagement rate on X?" becomes "what is the engagement rate for this account, on this definition?"** As the worked example showed, the platform average is both unavailable and, because of definitional spread, close to meaningless even if it existed. A per-account rate computed on a definition you state and hold constant is a real instrument. It will not match anyone else's number, and that is fine, because you are using it to compare your own posts to each other rather than to an industry benchmark that was computed differently. **"How much of the conversation is us?" becomes a share-of-voice measurement over a named query.** Search returns posts matching a query, which is enough to compute your share of matched posts over a window. The honest caveat is the one that limits every search-based measurement, including ours: search returns a sample of matches rather than a guaranteed complete set, so a share-of-voice figure is a ratio between two samples drawn the same way. That is genuinely useful for tracking direction over time, and genuinely not a population statistic. Keeping the query, the endpoint and the window fixed across runs is what makes the comparison valid. The pattern across all four is the same. The platform-level question is unanswerable and the entity-level question is cheap. The statistics industry grew up around the first kind of question because for a decade the company published the answer for free, and it has not adjusted to the fact that it stopped. There is also a quiet economic point in here. The reason nobody independently re-measured X's headline numbers after the filings stopped is that gathering the underlying data was expensive enough to make it somebody's funded research project rather than an afternoon. For platform aggregates that is still true, and always will be, because the data does not exist outside the company. For the entity-level facts that most people actually need, it stopped being true, and the content in this category has not caught up with that either. ## What should you do with a statistic you did not measure? Ask four questions of it before you repeat it: what kind of claim is it, who actually produced it, what date does the underlying claim carry, and what is the number even called. If it is a per-entity fact rather than a platform aggregate, measure it yourself instead. This is the practical residue of the whole exercise, and it generalises well beyond X. **Ask what kind of claim it is.** Platform aggregate, or per-entity fact? If it is an aggregate about a private company, it is an estimate or a statement, never a measurement, and it should be read with the confidence you would give a press release. **Follow the attribution one more hop than feels necessary.** The figure that looks sourced usually points at another article. We found a 2023 company claim and a Q2 2022 figure both being served inside 2026-dated pages, not through anyone's bad faith, but because nobody re-checks a number that everyone else is also printing. **Check the date on the underlying claim, not the date on the page.** A page updated in 2026 can be, and in this category routinely is, restating a figure from several years earlier. **Check what the number is even called.** The 557 million figure is published as ad reach by one page and monthly actives by another, from the same upstream source. If two pages disagree about what a number measures, neither of them verified it. **If it is a per-entity fact, consider measuring it.** This is the part that has genuinely changed. Follower counts, post counts, account ages, engagement counters, trend coverage: these are a call away and cost a fraction of a cent each. There is no longer a good reason to cite somebody else's follower count for an account you could have looked up in under a second. ::directive{id="img-15"} ::directive{id="img-9"} **And be suspicious of a clean number.** Our own measurement found two endpoints disagreeing about the same post's view count by 873. Real measurement is noisy, and a figure presented without a timestamp, an instrument and a margin has usually had the noise removed by somebody who did not measure it. ## Who the intermediaries actually are, and what their numbers are The attribution table has four names in the "attributed to" column that are doing most of the load-bearing work in this entire category: DataReportal, eMarketer, Statista and Business of Apps. It is worth being precise about what those attributions mean, and equally precise about what we did and did not check. What we verified is the **structure** of the chain, by opening each publisher page and recording what it says its own source is. What we did not do is audit each intermediary's methodology, and we are saying so rather than implying a depth of checking we did not perform. That matters because the next hop is where the real uncertainty lives, and a reader who wants to rely on one of these figures should go there themselves. Here is the structural point, which does not require auditing anyone. None of those four names is X. They are data publishers, market-research firms and analytics aggregators. Their figures for a private company's usage are necessarily **models or compilations**, built from some mixture of company statements, advertising-platform outputs, panel data, app-store analytics and their own estimation. That is legitimate work and it is often the best available answer. It is simply not a disclosure, and the distinction disappears completely by the time a number reaches a roundup that says "561 million monthly active users" in bold with a source link underneath. Two specific consequences follow, and both are visible in our table. **Advertising-platform figures and usage figures are different objects.** A potential-reach number is generated by an ad system to tell a buyer how many accounts they could theoretically target. It is produced for a commercial purpose, it is not audited as a usage statistic, and it routinely includes accounts a usage metric would exclude. That is very likely the root of the 557 million double-labelling: one publisher carried it with the label the source attached, and one carried it as monthly actives. Somebody made a category error somewhere in the chain, and the number kept travelling with both labels attached. **App-analytics figures measure apps, not platforms.** The 132 million daily-active figure Search Engine Land attributes to TechCrunch is explicitly described on that page as covering iOS and Android mobile apps. That is a genuinely useful measurement of a genuinely different thing: it excludes web entirely. Comparing it to a company-stated daily-active figure that includes all surfaces is comparing two different denominators, and the 119 million spread between the low and high daily-active figures in our table is at least partly that, rather than disagreement about reality. The practical rule this produces is short. When a statistic about a private platform reaches you, the question is not "is this number right". It is "what kind of object is this, who made it, and for what purpose". A potential-reach figure is not wrong; it is an answer to a question you probably were not asking. ## How do you reproduce the citation trace yourself? Open the top-ranking pages themselves rather than their search snippets, record the intermediary each figure is attributed to rather than just the publisher, check the date on the underlying claim rather than the date on the page, follow any redirects, and put every page in one table so the disagreements become visible. This took under an hour and it needs no API and no budget. **Open the top results, not the snippets.** A search snippet gives you the number and strips the attribution. Every finding in our table came from the body of the page, and two of the three contradictions are invisible from the search result alone. **Find the attribution for each headline figure.** Most reputable roundups do attribute, usually inline or in a caption. If a page states a platform-level figure with no attribution at all, that is your answer about the page. **Write down the intermediary, not just the publisher.** "Sprout Social says 251 million" is not the useful record. "Sprout Social, citing Mashable, says 251 million" is, because it is the only form in which you can spot that two pages are leaning on the same upstream source. **Check the date of the underlying claim.** This is where the surprises are. A page updated this year can carry a figure from three or four years ago, correctly attributed, with nothing on the page drawing your attention to the gap. In our trace, one daily-active figure is from a 2023 company statement and another is Q2 2022. **Follow redirects.** We found the most-cited page in the cluster now redirecting to a different publisher's domain. If you are counting independent sources, a redirect quietly reduces your count. **Put the pages in one table.** This is the step people skip and it is the step that produces every finding. Individually each of those three pages reads as careful and well-sourced. Side by side, they publish four irreconcilable daily-active figures and give one number two different names. Neither page is behaving badly. The category simply has no mechanism for noticing that it disagrees with itself. When you do this on your own topic, expect the same shape. Closed citation loops form wherever primary reporting stops and demand for content does not, and the tell is always the same: many pages, few sources, and a date on the page that is much newer than the date on the claim. ## The honest scoreboard for this article Counting the substantive figures in this piece: the measured set covers 34 accounts across seven always-populated counters, 36 response fields split three ways, 8 posts measured twice through two endpoints, 3 endpoints timed over 5 runs each, 467 trend locations, 50 global trends, and 3 engagement figures on named public posts. The cited set is the 10 rows of the attribution table plus the pricing line, every one attributed inline to the publisher that carried it. One more thing about that split, because it is the part a reader can check without trusting us. Every measured figure in this article names the endpoint that produced it and the date it was produced, which means any of them can be falsified in about a second by running the same call and getting a different answer. That is a deliberately weak position to put ourselves in, and it is the position the incumbent pages never take: a figure attributed to an aggregator cannot be falsified by a reader at all, because there is nothing for them to re-run. The asymmetry is the whole argument. A number you can check is worth more than a number that sounds authoritative, even when the checkable number is smaller, older or less flattering. Zero figures in this article are ESTIMATED, because we did not model anything. Where a modelled figure would have been needed, most obviously for platform user totals and for bot share, we have said that we do not have one rather than producing one. That ratio is the actual deliverable. This page is not better than the incumbents because our numbers are bigger or newer. It is better because you can tell, for every single figure, which kind of claim it is and how to check it. ## The limits of this article, stated plainly The measurement sample is 34 accounts and 8 posts, chosen for recognisability and spread rather than randomly, so the field-availability profile is a statement about those payloads and not a population estimate. A sample including protected, suspended, brand-new or non-English accounts would very likely shift which fields land in the sometimes-populated bucket, exactly as expanding from 10 to 34 already did once. The response-time figures are five runs each from one machine on one network at one time of day. They are indicative of relative cost between endpoints, which is the only use we put them to, and they are not a service-level claim. The counter-disagreement finding is 8 posts from a single account. It reproduced cleanly within that set and the direction pattern is consistent, but it is a small sample and the exact ratio deserves a larger replication before anyone leans on it. The citation tracing covers the three most-cited pages in one search result, in one country, on one day. Other pages in the cluster may source differently, and these pages will change. The engagement-rate worked example uses one post. It is an illustration of definitional spread, not a measurement of typical engagement, and it should not be read as one. None of those caveats are in tension with the article's actual argument, which is not "here are the true numbers". It is "here is which numbers can be measured, here is what measuring them actually returns, and here is where the widely-repeated ones come from". That argument survives all five limits, and we would rather print them than have you find them. If you want the other side of our own measurement work, the [monitoring coverage honesty](/blogs/twitter-monitoring-api-coverage-honesty-2026) piece documents where our own coverage falls short, and [why advanced search misses posts](/blogs/why-x-advanced-search-misses-posts-2026) covers the sampling question that limits every search-based measurement including ours. For cost planning, [cost by workload](/blogs/twitter-api-cost-by-workload-2026) and the [cost benchmark](/blogs/twitter-api-cost-benchmark-2026) are the relevant pages, and [choosing an API](/blogs/how-to-choose-twitter-api-2026) covers the decision itself. If you are coming from the official product, [official X API versus third party](/blogs/official-x-api-vs-third-party-2026) and [is the Twitter API free](/blogs/is-twitter-api-free) answer the first two questions people ask, [what the firehose is](/blogs/what-is-the-twitter-firehose-2026) covers full-volume access, [error codes](/blogs/twitter-api-error-codes) and [what rate limited means](/blogs/what-rate-limited-means-on-x-2026) cover the failure modes, [advanced search operators](/blogs/twitter-advanced-search-operators) covers query construction, [scraping tweets](/blogs/how-to-scrape-tweets) covers the collection patterns, [API cost](/blogs/twitter-api-cost) covers the per-call economics, [the 2026 pricing change](/blogs/x-api-pricing-change-2026) covers what moved, and the [complete tutorial](/blogs/twitter-api-tutorial-2026-complete-guide) is the place to start if this is your first call. External sources referenced above, for anyone who wants to follow the chain themselves: the [X developer documentation](https://docs.x.com/overview), [Search Engine Land's user guide](https://searchengineland.com/guide/twitter-users), [Sprout Social's statistics roundup](https://sproutsocial.com/insights/twitter-statistics/), [DemandSage's statistics page](https://www.demandsage.com/twitter-statistics/), [Statista's Twitter topic hub](https://www.statista.com/topics/737/twitter/), the Quora threads on [user counts](https://www.quora.com/How-many-Twitter-users-are-there) and [monthly actives](https://www.quora.com/How-many-active-users-does-Twitter-have-monthly), and the Hacker News discussions of [the 2023 pricing announcement](https://news.ycombinator.com/item?id=35094729), [the original pricing thread](https://news.ycombinator.com/item?id=34632185) and [the Pro tier](https://news.ycombinator.com/item?id=38846497). ## Frequently Asked Questions ### How many people use X in 2026? There is no current first-party figure. X stopped publishing routine usage metrics after it went private, and the numbers in circulation come from third-party aggregators and news reports rather than from X. Search Engine Land cites 561 million monthly active users for July 2025 sourced to DataReportal, and separately cites a company claim of 200 to 250 million daily active users dating from 2023. Sprout Social states plainly that there is no publicly available monthly-active-user data. Treat any single current user number you see as an estimate from an aggregator, not a disclosure. ### Can you measure X's daily active users with an API? No. Daily and monthly active users are internal platform metrics and no public X endpoint exposes them. A public API can measure per-account and per-post facts, such as follower counts, post counts, account creation dates and engagement counters on individual posts, and it can sample search results. It cannot see platform-wide aggregates, revenue, ad impressions or total daily post volume. Any published figure for those is either a company statement or an outside estimate. ### What percentage of X accounts are bots? Nobody can currently answer this from public data, and we are not publishing a number. The automation fields that would answer it come back empty: across 34 accounts we sampled, the is_automated and automated_by fields on the user endpoint were empty on 34 of 34. That means bot status cannot be read from the account payload, so any published bot-share percentage rests on a classifier the publisher built themselves, and is only as good as the rule, the sample and the controls they disclose. ### Why do all the X statistics articles show the same numbers? Because they are citing each other and a small number of shared upstream sources. We traced the figures on the three most-cited pages in this search result and found four different daily-active-user figures ranging from 132 million to 251 million, none of them first-party and none from the same year. We also found the same number, 557 million, attributed to the same source, Statista, but labelled potential ad reach by one publisher and monthly active users by another. ### How much does it cost to measure X yourself? On twitterapis.com a standard read is $0.0008 per call, and signup includes $0.50 in free credits, which covers roughly 625 standard calls. Every measurement in this article was produced with well under a hundred calls. The practical cost of re-running the whole measurement set is a few cents, which is the point: the reason public X statistics went stale is that independent measurement used to be expensive, and for the account-level and post-level facts in this article it no longer is. ### Do two X API endpoints always agree on the same post's engagement counts? No, and we measured it. Querying eight posts through a search endpoint and then immediately through a single-post endpoint, the favourite count matched exactly on three of eight and the view count on five of eight, with differences running in both directions. The gaps were largest on the newest and busiest post and zero on older quiet ones. Any engagement number is a reading taken by one endpoint at one moment, so record the endpoint and the timestamp beside it. ### What fields does the X user endpoint actually return? In our measurement across 34 accounts the payload carried 36 distinct fields. Eighteen were populated on every single account, including follower count, following count, post count, media count, account creation date and the blue verification flag. Eleven were empty on every account, including both automation fields and the listed count. Seven varied by account, including location, pinned posts and professional type. Expanding the sample from 10 accounts to 34 moved one field out of the always-populated group, which is why sample size is worth stating.