Audience Insights
Get Analytics answers how did my posts do. This endpoint answers the other half: who follows this account, when they are online, what they tap on the profile and how it compares to its category.
It is one endpoint with a platform, exactly like
/comments and
/post-analytics:
the question is the same for every network, so the URL is too. Adding a network
never changes your integration — the same call starts answering for a new value
of platform.
The field to build a scheduler on is activity_by_hour — the number of
followers connected in each hour of the day, added up over the window. That is
the answer to "when should I publish", and it comes from your own audience
rather than from a generic best-time-to-post table.
- Method:
GET - Endpoint:
/api/uploadposts/audience - Authentication:
- API Key in the
Authorizationheader.Authorization: Apikey <YOUR_API_KEY>
- API Key in the
Query Parameters
| Parameter | Type | Required | Description | Default |
|---|---|---|---|---|
platform | string | Yes | The network to ask. Today only tiktok answers; anything else is a 400 naming the platforms that do. | - |
user | string | Yes | The profile's username. Must have an account of that platform connected. | - |
start_date | string | No | First day of the window, ISO YYYY-MM-DD. | end_date − 29 days |
end_date | string | No | Last day of the window, ISO YYYY-MM-DD. Must be earlier than today. | yesterday |
benchmark_category | string | No | One of the 25 categories in benchmark_categories, case-insensitive. Adds the benchmark block to the answer. | - |
platform=tiktok today. Any other value answers 400 with
error_code: "platform_not_supported" and a message listing what is supported,
so a client can branch on the code instead of on a hard-coded list.
Window rules. The platform refuses a window that ends today or later, and it
keeps at most 60 days of history. Rather than forwarding a request that is
guaranteed to fail, Upload-Post trims what you asked for to what the platform
accepts: an end_date of today becomes yesterday, and a start_date older than
60 days becomes the oldest day available. Render the range that comes back,
not the one you sent — they are not always the same window. A value that is
not an ISO date is a hard 400.
Example Request
curl -G 'https://api.upload-post.com/api/uploadposts/audience' \
-H 'Authorization: Apikey your-api-key-here' \
-d 'platform=tiktok' \
-d 'user=your_profile' \
-d 'start_date=2026-08-01' \
-d 'end_date=2026-08-30'
Successful Response (200 OK)
{
"success": true,
"platform": "tiktok",
"range": { "start_date": "2026-08-01", "end_date": "2026-08-30" },
"audience": {
"countries": [
{ "country": "ES", "percentage": 0.588 },
{ "country": "MX", "percentage": 0.161 },
{ "country": "AR", "percentage": 0.074 }
],
"cities": [
{ "city": "Madrid", "percentage": 0.121 },
{ "city": "Barcelona", "percentage": 0.083 }
],
"ages": [
{ "age": "18-24", "percentage": 0.372 },
{ "age": "25-34", "percentage": 0.411 },
{ "age": "35-44", "percentage": 0.145 }
],
"genders": [
{ "gender": "female", "percentage": 0.624 },
{ "gender": "male", "percentage": 0.376 }
]
},
"activity_by_hour": [
{ "hour": "2", "followers_online": 456 },
{ "hour": "9", "followers_online": 981 },
{ "hour": "14", "followers_online": 1494 },
{ "hour": "21", "followers_online": 1327 }
],
"followers_daily": [
{ "date": "2026-08-01", "total": 12480, "new": 63, "lost": 11 },
{ "date": "2026-08-02", "total": 12539, "new": 71, "lost": 12 }
],
"profile_actions": {
"bio_link_clicks": 318,
"address_clicks": null,
"app_download_clicks": null,
"email_clicks": 12,
"phone_number_clicks": null,
"lead_submissions": null
},
"bio_description": "Corrijo exámenes con IA 📸",
"benchmark_categories": [
"PERSONAL_BLOG",
"MACHINERY_AND_EQUIPMENT",
"HEALTH_AND_WELLNESS",
"PETS",
"AUTOMOTIVE_AND_TRANSPORTATION",
"EDUCATION_AND_TRAINING",
"FOOD_AND_BEVERAGE",
"REAL_ESTATE",
"ELECTRONICS",
"SHOPPING_AND_RETAIL",
"PUBLIC_ADMINISTRATION",
"ART_AND_CRAFTS",
"BABY",
"GAMING",
"RESTAURANTS_AND_BARS",
"HOME_FURNITURE_AND_APPLIANCES",
"PROFESSIONAL_SERVICES",
"SOFTWARE_AND_APPS",
"MEDIA_AND_ENTERTAINMENT",
"BEAUTY",
"SPORTS_FITNESS_AND_OUTDOORS",
"CLOTHING_AND_ACCESSORIES",
"TRAVEL_AND_TOURISM",
"OTHERS",
"FINANCE_AND_INVESTING"
]
}
| Field | Description |
|---|---|
platform | The network the answer came from, echoed back. |
range | The window actually queried, after trimming. Read this one, not your input. |
audience.countries / .cities / .ages / .genders | Follower distribution. percentage is a fraction of 1, not a number out of 100 — 0.588 means 58.8%. Percentages cannot be added across days, so each distribution is the most recent one reported inside the window. |
activity_by_hour | Always 24 entries, "0"–"23" in the account's local time, ordered numerically so 9 comes before 10. followers_online is the sum over the window: in the example the audience bottoms out at 456 at 2 a.m. and peaks at 1494 at 2 p.m., which is the hour to publish into. |
followers_daily | One row per day, oldest first: total followers at the end of the day, new gained and lost. A field is null when the platform did not report it for that day. |
profile_actions | Six counters totalled over the window: bio_link_clicks, address_clicks, app_download_clicks, email_clicks, phone_number_clicks, lead_submissions. null is not 0 — it means the platform answered nothing for this account, while 0 means it answered "nobody clicked". Do not coalesce one into the other in a dashboard. |
bio_description | The account's current bio text. |
benchmark_categories | The 25 values benchmark_category accepts. Always present, so a UI can build its picker without a second call. |
With benchmark_category
Averages tell you whether 3% engagement is good for what this account publishes. A number on its own means nothing; this is the comparison that gives it meaning.
curl -G 'https://api.upload-post.com/api/uploadposts/audience' \
-H 'Authorization: Apikey your-api-key-here' \
-d 'platform=tiktok' \
-d 'user=your_profile' \
-d 'benchmark_category=SOFTWARE_AND_APPS'
The same body as above, plus:
{
"benchmark": {
"category": "SOFTWARE_AND_APPS",
"average_comments": 19,
"average_engagement_rate": 0.0144,
"average_follower_count": 24713,
"average_follower_growth": 186,
"average_likes": 742,
"average_shares": 43,
"average_video_count": 17,
"average_video_views": 21508
}
}
| Field | Description |
|---|---|
benchmark.category | The category you asked for, normalised to upper case. |
benchmark.average_engagement_rate | Fraction of 1 — 0.0144 means 1.44%, the average for SOFTWARE_AND_APPS. |
benchmark.average_likes / average_comments / average_shares | Per post, on average, for accounts in that category. |
benchmark.average_video_views | Average views per video. |
benchmark.average_follower_count / average_follower_growth | Account size and growth in the period the platform measures. |
benchmark.average_video_count | How many videos a typical account in the category publishes in the period. |
Only the metrics the platform actually returned are present, so read the keys you need defensively rather than assuming all eight are there. The category is not stored on the profile: pass it on every call, which also lets you compare one account against two categories when it straddles both.
Error Responses
400 Bad Request— the platform does not answer this question yet. The message names the ones that do.
{
"success": false,
"message": "'instagram' does not support audience insights yet. Supported: tiktok.",
"error_code": "platform_not_supported"
}
400 Bad Request— a date that is not ISOYYYY-MM-DD, abenchmark_categoryoutside the 25 values, or a missingplatform.
{
"success": false,
"message": "end_date must be an ISO date (YYYY-MM-DD).",
"error_code": "invalid_parameter"
}
400 Bad Request— the profile's connection cannot serve this endpoint. Reconnect the account.
{
"success": false,
"message": "Profile 'your_profile' has no TikTok connection that supports this endpoint. Reconnect your TikTok account from Manage Users.",
"error_code": "tiktok_reconnect_required"
}
404 Not Found— no profile with that username exists under your API key (error_code: "PROFILE_NOT_FOUND").409 Conflict— the token expired and the account must be reconnected ("reauth_required": true).502 Bad Gateway— the platform rejected the lookup; its message is returned verbatim inmessage.
Additional Notes
- Which connections answer. On TikTok, the audience, the benchmark and
hashtag suggestions work on any recently connected
account (the
profile_analyticscapability). Only comments andtype=keywordson Suggestions need the account to be reconnected — thecommentsandtrend_searchcapabilities are granted at the moment of connecting, so an older connection does not carry them. - Percentages come from the platform as fractions of 1. Multiply by 100 before rendering.
audience.citiesis the noisiest breakdown: small accounts often get an empty array while countries and ages are populated.- A brand-new connection has no history yet. Expect empty arrays for the first days rather than an error.
Related
- Suggestions — the hashtags and search terms to write the next post with.
- Get Analytics — cross-platform account and per-post metrics, including the full TikTok per-post breakdown (retention, impression sources, audience types).
- Account capabilities.