Updated June 2026: re-verified the official X API geography limits against the current pay-per-use model (the old per-tier request caps no longer apply to new developers, rate limits are now per-endpoint), corrected how and when X surfaces the "Account based in" value (the public "About this account" panel rolled out in late 2025, not 2024), confirmed the /about endpoint returns a country field, and re-checked every endpoint and price against the live Sorsa reference.
Key Takeaway. Twitter audience geography is the country distribution of an X account's followers. You build it by pulling the follower list, looking up the country X associates with each follower (the value behind the public "Account based in" label, not the self-reported bio), and aggregating the results. It works for your own account and any public account.
X (formerly Twitter) once exposed audience country data inside its native analytics for your own account, and it has never let you see it for anyone else's. There is no public button that tells you which countries an influencer's followers live in, or how a competitor's audience splits across markets. The official X API only exposes geography at the tweet level, which is rare since most users do not geotag, or through Profile Geo enrichment on the Enterprise tier, which most teams cannot afford.
Sorsa API, an alternative Twitter/X API provider, closes that gap with a single endpoint, /about, which returns the country X associates with any public account on flat per-request pricing, with no OAuth and no approval queue. Pair it with the /followers endpoint and you can build a full country breakdown of any account's audience, your own or a competitor's. This guide covers where that country value actually comes from, why it beats parsing the bio "Location" field, four production pipelines in Python, and what it costs.
We have run audience-geography pipelines for growth and research teams since the v1.1 era and migrated dozens of them off the official API after the 2023 pricing changes. It is one of the most common asks we get, and one of the easiest to get wrong.
Table of Contents
- Where X actually stores geography
- Why audience geography is hard to get
- Four real use cases
- How accurate is the country data
- The /about endpoint reference
- Four Python pipelines for Twitter audience geography
- Exporting and visualising
- How much does this cost
- In practice
- FAQ
- Getting started
Where X actually stores geography
X carries three different geographic signals for an account, and they are not interchangeable. Most articles on this topic conflate them.
1. Bio "Location" field. The free-form text users type into their profile. It is unstandardised, often a joke ("the internet", "my mom's basement"), often empty, and never validated. Scraping this field is what every legacy social-listening tool did, and it is why their geographic charts were never accurate. Roughly 30 to 40 percent of accounts leave it blank or fill it with non-geographic text.
2. Tweet-level Place data. When a user geotags a tweet, the payload carries a Place object with a country code. Per X's own developer documentation on filtering tweets by location, this is opt-in at the tweet level, and the precise-location feature was removed from the iOS and Android apps in 2019. Under 3 percent of tweets carry geo metadata, so it is useless for audience-level analysis.
3. The account's country, shown as "Account based in". X associates a country with each account from platform-level signals (IP history, device data, payment methods, app store), not from anything the user typed. This is the value X surfaces publicly as "Account based in" inside the "About this account" panel that rolled out across profiles in late 2025, and it is the same signal the country-badge browser extensions read. For a full breakdown of what each field in that panel means, see our explainer on X's "Account based in" label.
The Sorsa /about endpoint returns this third signal as a country field. It is the most reliable of the three for aggregate work: it is populated for the large majority of active accounts, it is platform-derived rather than self-reported, and it does not depend on the user enabling tweet-level geotagging.
Why audience geography is hard to get
If the data exists, why does not every analytics tool show it? Three reasons.
First, the official X API does not expose this country value as a simple queryable field for arbitrary accounts. You can read it for a single profile by parsing the public About panel, but there is no documented v2 endpoint for it. Profile Geo enrichment exists as a separate Enterprise add-on, with enterprise-only operators such as profile_country for filtering tweets by author country, but that is a five-figure annual contract and it works at the tweet-stream level rather than the audience level.
Second, the volume problem. To know where a competitor's audience lives, you look up the country for every follower, not just the account itself. For an account with 100,000 followers, that is 100,000 lookups plus a few hundred follower-list pages. Official v2 endpoints stay rate-limited per 15-minute window, varying by endpoint and typically in the low hundreds of requests under the current pay-per-use model, so a single competitor audit at that scale runs into many hours, often days, of throttled calls before you even count the per-resource cost.
Third, the consumer tools are locked to your own account. Login-based analytics tools such as Circleboom, TweepsMap, Fedica, and Audiense authenticate via OAuth as you, so they can only map your own followers, never a competitor's. They also read the self-reported bio "Location" field and exclude followers who left it blank, which skews the sample toward whoever happened to fill it in.
| Approach | Whose audience | Data source | Scale | Notes |
|---|---|---|---|---|
| Consumer login tools | Your own account only (OAuth) | Self-reported bio location; blanks excluded | Point-and-click, no bulk or code | Visual map, but no competitor audiences |
| Official X API | Any, but no simple field | Tweet-level geo, or Enterprise Profile Geo | Enterprise contract for profile geo | Five-figure, tweet-stream level |
Sorsa /about | Any public account | Platform country ("Account based in") | One request per account, 20 req/s | Flat per-request, JSON, read-only |
Sorsa sidesteps all three constraints. It returns the country directly via /about, runs on flat monthly plans rather than per-resource billing, and works for any public profile without a user-side OAuth grant. For the full cost picture, see our 2026 Twitter API pricing breakdown.
Four real use cases
These are four scenarios where audience geography drives a real decision. The pipelines later in this guide map directly onto them.
Influencer vetting before a regional campaign
A consumer-tech brand we worked with was about to put a mid-five-figure budget into a US launch with six creators, each of whom claimed to reach "US tech professionals". The audit showed several had well under half their followers actually based in the US, and the largest of them sat far below what its follower count implied. That shifted budget toward smaller creators with tighter US concentration before any contract was signed. Anyone running paid influencer marketing should vet audience geography before signing, not after.
Market expansion research
Before committing to localised content, a paid-ads budget, or a regional hire, look at what your audience already is. A B2B SaaS team found through an audit that a meaningful share of their organic followers sat in a market they had never targeted with content or ads, enough to justify a localised landing page and a small local event. The reverse pattern is also useful: a region with near-zero followers tells you that you are starting from scratch and should budget for awareness rather than conversion. This is the geographic half of audience research; the interest and follower-overlap half is covered in our target-audience playbook.
Inorganic-growth detection
If a small or mid-sized account suddenly gains a large cohort of followers from a country with no obvious connection to its activity, that is a strong inorganic-growth signal. A research group we advised flags accounts whose follower country distribution shifts by more than roughly 15 points in 30 days; most flagged accounts turn out to have bought followers or been the target of an amplification campaign. For brands, the same logic catches bought-follower contests and astroturf by competitors. Geography is one signal among several; the full account-level method is in our guide to auditing fake followers.
Cross-border conversation mapping
For academic and policy research, you can take any topic, pull recent tweets via /search-tweets or /mentions, then run the unique authors through /about to map how the conversation distributes geographically. We have seen this used for studying diaspora communities, misinformation flows, and cross-border policy debates. The country distribution of who is actually talking about a topic, weighted by engagement, says a lot about whose conversation it really is.
How accurate is the country data
The country from /about is platform-derived, so it is much more reliable than bio parsing, but it is not perfect, and it is worth being honest about the limits.
A small share of accounts use a consistent VPN and get tagged with the VPN exit country rather than where the user lives. For a single lookup that matters; for aggregate analysis at samples of 500 followers or more, VPN noise averages out and the overall distribution holds within a few points.
Some accounts return no country. This happens when X lacks enough signal to assign one with confidence, typically for very new or very low-activity accounts. The pipelines below bucket these as "Unknown". In a healthy 1,000-follower sample, expect roughly 1 to 5 percent. A much higher Unknown share in a cohort of recent followers is itself useful: it correlates with bought-follower vendors.
The country reflects the account's current geographic association, which can change if the user genuinely relocates or switches VPN, so treat a long-running cohort as a snapshot rather than a fixed identity.
Against the bio "Location" field, the contrast is stark. The consumer tools that dominate this space read self-reported bio text and drop followers who left it blank, while the country from /about is inferred by X from connection signals and is populated for most active accounts. For market sizing, ad targeting, influencer vetting, and competitive benchmarking, that accuracy is more than enough. For forensic single-account identification, treat any one lookup as a hypothesis.
The /about endpoint reference
Authentication is a single header: ApiKey: YOUR_API_KEY. Full details are in the Sorsa authentication docs.
curl "https://api.sorsa.io/v3/about?username=elonmusk" \
-H "ApiKey: YOUR_API_KEY"
Response:
{
"country": "United States",
"username_change_count": 1,
"last_username_change_at": "2021-01-01T00:00:00Z"
}
The field you want for geography is country. You can identify the account by any one of three parameters: username (handle without @), user_id (numeric stable ID), or user_link (full profile URL). For aggregate workflows we use user_id, because it does not change if the account rebrands its handle. The two extra fields, username_change_count and last_username_change_at, are handy for stability scoring. One request equals one quota call on any plan, with no per-endpoint multipliers.
Four Python pipelines for Twitter audience geography
All four build on two helpers: one that pulls a follower list from GET /followers (up to 200 profiles per page, see Followers and Following), and one that resolves a single follower's country from GET /about.
import requests
import time
from collections import Counter
API_KEY = "YOUR_API_KEY"
BASE_URL = "https://api.sorsa.io/v3"
HEADERS = {"ApiKey": API_KEY}
def get_followers(username, max_pages=10):
"""Paginate GET /followers (up to 200 profiles per page)."""
followers, cursor = [], None
for _ in range(max_pages):
params = {"username": username}
if cursor:
params["next_cursor"] = cursor
resp = requests.get(f"{BASE_URL}/followers", headers=HEADERS, params=params, timeout=30)
resp.raise_for_status()
data = resp.json()
followers.extend(data.get("users", []))
cursor = data.get("next_cursor")
if not cursor:
break
time.sleep(0.1)
return followers
def get_country(user_id):
"""Return the country for a user_id, or 'Unknown' if X has no value."""
try:
resp = requests.get(f"{BASE_URL}/about", headers=HEADERS,
params={"user_id": user_id}, timeout=15)
if resp.status_code == 200:
return resp.json().get("country") or "Unknown"
except requests.RequestException:
pass
return "Unknown"
Pipeline 1: single account lookup
The simplest case, useful as a building block and for ad-hoc verification. For a one-off check with no code, the location checker runs the same lookup from the browser.
def get_account_geo(identifier):
"""Country and stability metadata for one account (username, user_id, or URL)."""
if identifier.startswith("http"):
params = {"user_link": identifier}
elif identifier.isdigit():
params = {"user_id": identifier}
else:
params = {"username": identifier.lstrip("@")}
resp = requests.get(f"{BASE_URL}/about", headers=HEADERS, params=params, timeout=15)
resp.raise_for_status()
return resp.json()
data = get_account_geo("elonmusk")
print(data["country"], data["username_change_count"])
Pipeline 2: full audience geography
The core workflow. Pull the follower list of any public account, resolve each follower's country, aggregate.
def audience_geography(username, max_pages=10):
followers = get_followers(username, max_pages=max_pages)
counts = Counter(get_country(f["id"]) for f in followers)
return counts, len(followers)
counts, total = audience_geography("nasa", max_pages=5)
for country, n in counts.most_common(10):
print(f"{country}: {n} ({n / total * 100:.1f}%)")
At 20 requests per second, a 1,000-follower sample resolves in about a minute sequentially. For larger audits, run get_country across a thread pool of 15 to 18 workers to stay under the rate limit while cutting wall-clock time.
Pipeline 3: competitor comparison
Run the same audit across a shortlist of accounts and compare a target market's share. Audience geography is one input into a broader Twitter competitor analysis workflow.
def compare_accounts(usernames, market="United States"):
for u in usernames:
counts, total = audience_geography(u, max_pages=5)
share = round(counts.get(market, 0) / total * 100, 1) if total else 0
print(f"{u}: {total} sampled, {market} {share}%, top {counts.most_common(3)}")
compare_accounts(["competitor_a", "competitor_b", "competitor_c"])
Pipeline 4: bought-follower detection by country pattern
Bought-follower cohorts have a distinctive country signature: a high Unknown share and an unexpected single-country concentration.
def inorganic_signal(counts, total):
unknown = counts.get("Unknown", 0) / total * 100 if total else 0
known = [(c, n) for c, n in counts.items() if c != "Unknown"]
top_country, top_n = max(known, key=lambda x: x[1], default=("none", 0))
top_share = top_n / total * 100 if total else 0
flags = []
if unknown > 20:
flags.append(f"high Unknown share ({unknown:.0f}%)")
if top_share > 60:
flags.append(f"single-country concentration ({top_country} {top_share:.0f}%)")
return flags
It is a heuristic, not proof. Sophisticated farms can mask country, but the pattern catches the bulk of cheap inorganic growth.
Exporting and visualising
Once you have the counts object, export it for reporting or drop it straight into a map. To get the breakdown into a shared sheet for non-technical stakeholders, see how to export X data to Google Sheets.
import csv
def export_to_csv(counts, total, path="audience_geography.csv"):
with open(path, "w", newline="") as f:
w = csv.writer(f)
w.writerow(["country", "count", "percentage"])
for country, count in counts.most_common():
w.writerow([country, count, round(count / total * 100, 2)])
The country names /about returns are standard English names, so they map directly into a Plotly choropleth without an ISO lookup. This produces the same kind of map the consumer tools sell, generated from your own data and saved as a standalone HTML file.
import plotly.express as px
def plot_choropleth(counts, path="audience_map.html"):
rows = [{"country": c, "followers": n} for c, n in counts.items() if c != "Unknown"]
fig = px.choropleth(rows, locations="country", locationmode="country names",
color="followers", color_continuous_scale="Blues")
fig.write_html(path)
How much does this cost
Audience geography is a high-volume workflow, since you make one /about call per follower. Concrete numbers on the Sorsa Pro plan (100,000 requests for $199 per month, $0.00199 per request):
| Workload | Requests | Cost on Pro |
|---|---|---|
| Single account lookup | 1 | $0.002 |
| 1,000-follower sample audit | ~1,005 | ~$2.00 |
| 10,000-follower full audit | ~10,050 | ~$20.00 |
| Three-competitor comparison, 1,000 each | ~3,015 | ~$6.00 |
| Monthly recurring 1,000-sample audits, 20 accounts | ~20,100 | covered by Pro |
One-off audits for a single account fit inside the Starter plan ($49 per month, 10,000 requests); regular agency or analytics work usually lands on Pro. The full tier list is on the pricing page. The optimisation lever for campaign verification is that you do not need every follower, only the accounts that completed the campaign action, which is usually two orders of magnitude smaller than the full follower list.
In practice
An analytics agency we work with audits creator audiences for clients at the deal stage. Running the full-audience pipeline across a shortlist of creators, a few hundred to a few thousand followers sampled each, costs a few dollars on Pro and finishes in minutes, where the same job on the official API would mean an Enterprise contract or days of throttled v2 calls. For teams running this as an ongoing program rather than a one-off, geography slots into a wider competitor tracking setup. The recurring reason they rely on it is the data source: the country comes from X's own "Account based in" signal, not the bio field the login tools read, so the distribution holds up when a client pushes back on the numbers.
FAQ
Can you see what country a Twitter account is based in without an API?
Yes for a single account, no at scale. X shows the country on each profile's public "About this account" panel, and our explainer on the "Account based in" label walks through reading it by hand. For an aggregate distribution across thousands of followers, you need an API such as Sorsa's /about, which returns the same country value at REST scale on a flat per-request cost.
Why is the bio "Location" field unreliable for audience geography?
The bio "Location" field is free-form text typed by the user, not validated, not standardised, and frequently empty or facetious. Roughly 30 to 40 percent of accounts leave it blank or fill it with non-geographic text. Even when filled, "NYC", "New York City", and "Big Apple" are three strings a naive script treats as three places. The country value from /about is platform-derived and avoids all of these failure modes.
Does the official X API expose follower country data?
Not at the per-account level for arbitrary accounts on the v2 paid tiers. Profile Geo enrichment, which adds country metadata to tweets based on the author's profile, is an Enterprise-only add-on with five-figure pricing. The standard v2 user-lookup endpoints do not return the "Account based in" country. This is the gap Sorsa's /about fills: the same underlying signal, exposed as a flat REST call.
How long does an audience geography audit take?
For a 1,000-follower sample at the Sorsa rate limit of 20 requests per second, a sequential script finishes in about a minute. A 10,000-follower audit takes 8 to 12 minutes sequentially, or 1 to 2 minutes with a thread pool of 15 to 18 concurrent workers. The follower-list pagination is a small fraction of the total; the per-follower /about calls dominate.
What happens when /about returns no country?
When /about returns no country, X did not have enough signal to assign one with confidence, usually for very new or very low-activity accounts. The pipelines in this guide bucket those as "Unknown". In a healthy 1,000-follower sample, expect 1 to 5 percent. A noticeably higher Unknown share in a cohort of recent followers correlates with inorganic-growth patterns and bought-follower vendors.
Can you detect bought followers using audience geography?
Yes, with caveats. Bought-follower vendors usually source from a narrow set of countries with low oversight, and their accounts tend to be low-activity, which produces a distinctive cohort signature: a high Unknown share, an unexpected single-country concentration, and elevated handle churn. Pipeline 4 in this guide implements the heuristic. It is not perfect, since sophisticated farms can mask country, but it catches the bulk of cheap inorganic growth.
Which Twitter API alternative supports audience geography lookups at scale?
Sorsa API is one of the few alternatives that exposes the "Account based in" country through a documented REST endpoint (/about), pairs it with bulk follower extraction at up to 200 profiles per request, and bills on flat-rate monthly plans rather than per-call. For a broader view of the options, see our writeup on Twitter API alternatives.
Getting started
The fastest way to try this is to grab a key from the Sorsa dashboard, run the single-account snippet against any handle, then scale up. The /about reference lives in the endpoint docs, the full workflow has a dedicated audience-geography page, and the playground lets you hit /about from a browser before writing any code. Pricing is flat per request on every plan, with no approval step, so a one-off single-account audit fits inside Starter and recurring agency work lands on Pro. If you are extracting followers for the audit, our guide to pulling follower lists has the pagination patterns and edge cases.
Reviewed by Keksich, founder of Sorsa, marketer and X API researcher.
How this was put together: this guide is built on our own work running an alternative Twitter/X API, including the /about and /followers endpoints that power these pipelines, with every endpoint and price re-verified against the live Sorsa v3 reference and pricing in June 2026. For X's own geographic behaviour we drew on X's developer documentation covering tweet-location filtering and Enterprise Profile Geo operators; for what the public "Account based in" label is and when it rolled out, our own explainer linked in the first section. The cost figures are computed from the current Pro per-request rate, not estimated.