> ## Documentation Index
> Fetch the complete documentation index at: https://docs.sorsa.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Audience Geography

# Audience Geography

How to retrieve the country associated with any public X account and aggregate audience geography data from a follower list.

> **Note:** For a fuller walkthrough with worked examples and country-distribution analysis, see [Twitter Audience Geography API: Analyze Followers by Country](https://api.sorsa.io/blog/twitter-audience-geography-api) on the blog.

***

## The `/about` Endpoint

Returns "About" section metadata for any public X account: country, username change history, X Premium (Blue) status and start date, account source, and organization affiliation.

### Request

```bash theme={null}
curl "https://api.sorsa.io/v3/about?username=elonmusk" \
  -H "ApiKey: YOUR_API_KEY"
```

```python theme={null}
import requests

resp = requests.get(
    "https://api.sorsa.io/v3/about",
    headers={"ApiKey": "YOUR_API_KEY"},
    params={"username": "elonmusk"},
)
print(resp.json())
```

### Parameters

| Parameter   | Type   | Required     | Description       |
| :---------- | :----- | :----------- | :---------------- |
| `username`  | string | One of three | Handle without @. |
| `user_id`   | string | One of three | Numeric user ID.  |
| `user_link` | string | One of three | Full profile URL. |

### Response

```json theme={null}
{
  "country": "United States",
  "username_change_count": 1,
  "last_username_change_at": "2021-01-01T00:00:00Z",
  "premium_start_at": "2026-03-14T18:30:35Z",
  "is_blue_verified": true,
  "source": "US App Store",
  "affiliate_username": null
}
```

### Response fields

| Field                     | Type                      | Description                                                                                                                                                           |
| :------------------------ | :------------------------ | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `country`                 | string                    | Country associated with the account, derived from platform-level signals (not the bio "Location" field). Returns `"Unknown"` when the platform has insufficient data. |
| `username_change_count`   | integer                   | Total number of handle changes on the account.                                                                                                                        |
| `last_username_change_at` | string (ISO 8601) or null | Timestamp of the most recent handle change. `null` if the handle has never changed.                                                                                   |
| `premium_start_at`        | string (ISO 8601) or null | Date the account's X Premium (Blue) subscription started. `null` if the account is not on X Premium.                                                                  |
| `is_blue_verified`        | boolean                   | Whether the account has a Blue (X Premium) verified badge.                                                                                                            |
| `source`                  | string                    | Source shown in the About section, such as the app store region or client the account registered from (for example, `"US App Store"`).                                |
| `affiliate_username`      | string or null            | Handle of the affiliated organization or parent account. `null` when there is no affiliation.                                                                         |

For audience geography you only need `country`. The remaining fields come back on the same call and are documented here for completeness.

***

## Audience Geography Workflow

To build a country distribution for any account's audience:

1. Extract the follower list with `GET /v3/followers`.
2. Call `GET /v3/about` for each follower using their `user_id`.
3. Aggregate the `country` values into a distribution.

```python theme={null}
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):
    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):
    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"
    return "Unknown"


def audience_geography(username, max_follower_pages=5):
    followers = get_followers(username, max_pages=max_follower_pages)
    countries = Counter()
    for user in followers:
        countries[get_country(user["id"])] += 1
        time.sleep(0.05)  # stay within 20 req/s
    return countries, len(followers)
```

### Cost

Each `/about` call counts as one request against your quota. For a 1,000-follower sample, that is roughly 1,005 requests: 1,000 country lookups and 5 follower-list pages (200 followers per page). Every new account starts with 100 free requests (no card required), enough to test a smaller geography sample before choosing a plan. See [Pricing](https://api.sorsa.io/pricing) for per-plan rates.

***

## Exporting to CSV

```python theme={null}
import csv

def export_to_csv(countries, total, path="geography.csv"):
    with open(path, "w", newline="") as f:
        w = csv.writer(f)
        w.writerow(["country", "count", "percentage"])
        for country, count in countries.most_common():
            w.writerow([country, count, round(count / total * 100, 2)])
```

***

## Data Accuracy

The `country` field is derived from platform-level technical signals, not from the user-reported bio "Location" field. This makes it more reliable for aggregate analysis, with two caveats:

* A small percentage of users access X via VPN. Their assigned country reflects the VPN exit node. For sample sizes of 500 or more, this noise averages out and the distribution is accurate within a few percentage points.
* Some accounts return `"Unknown"`. Expect 1-5% in a healthy organic audience; a share above 15-20% in a specific cohort (for example, recent followers after a spike) is a signal worth investigating.

***

## Related

* [Followers & Following](https://docs.sorsa.io/followers-and-following)
* [Target Audience Discovery](https://docs.sorsa.io/target-audiences-Discovery)
* [Competitor Analysis](https://docs.sorsa.io/Competitor-Analysis)
* [Marketing Campaign Verification](https://docs.sorsa.io/Marketing-Campaign-Verification)
* [API Reference: Account About Info](https://docs.sorsa.io/api-reference/users-data/account-about-info)
