
Understanding trackagoat's computed analytics metrics — engagement rates, posting velocity, average views, and period-over-period growth.
Raw metrics (views, likes, followers) tell you absolute counts. Derived metrics are computed ratios — rates and velocities that let you compare performance across creators and campaigns of different sizes.
All derived metrics are computed server-side from your historical snapshot data using timezone-aware day bucketing. Request them by adding a metric= parameter to any stats endpoint.
| Metric ID | Formula | Entity support |
|---|---|---|
engagement_rate_by_views | (likes + comments + shares + saves) / views × 100 | video, creator, campaign |
engagement_rate_by_followers | (likes + comments + shares + saves) / follower_count × 100 | creator, campaign |
posts_per_week | posts on that day × 7 | creator, campaign |
avg_views_per_post | views gained / videos posted through that day | creator, campaign |
growth_rate_pop | (value[day] − value[day−1]) / value[day−1] × 100 | video, creator, campaign |
This is the primary TikTok engagement benchmark. It measures what percentage of viewers interacted with the content.
engagement_rate = (likes + comments + shares + saves) / views × 100A null value means views were 0 on that day (divide-by-zero). Days with baseline snapshots contribute 0 to the engagement numerator and denominator.
2026 TikTok engagement benchmarks
curl -H "Authorization: Bearer tga_<key>" \
"https://www.trackagoat.com/api/v1/analytics?entity=creator&entity_id=<uuid>&metric=engagement_rate_by_views&from=2026-01-01&to=2026-03-31"Used when you want to normalize engagement against audience size rather than reach. Useful for creator comparisons regardless of how often they post.
engagement_rate = (likes + comments + shares + saves) / follower_count × 100The follower count used is the last known count as of each day (carry-forward). A null value means no follower data was available for that day.
This metric is not supported for individual videos — use creator or campaign entities.
curl -H "Authorization: Bearer tga_<key>" \
"https://www.trackagoat.com/api/v1/analytics?entity=creator&entity_id=<uuid>&metric=engagement_rate_by_followers&from=2026-01-01&to=2026-03-31"Posting velocity normalized to a weekly rate, computed on a per-day granularity basis.
posts_per_week = posts_on_day × 7A day with 0 posts returns 0.0 (a real rate of zero). null is returned only if there are no videos in scope at all.
curl -H "Authorization: Bearer tga_<key>" \
"https://www.trackagoat.com/api/v1/analytics?entity=creator&entity_id=<uuid>&metric=posts_per_week&from=2026-01-01&to=2026-03-31"Views gained in the period divided by the number of posts published through that day. Shows whether new posts are increasing or hurting per-video efficiency.
avg_views_per_post = views_gained_on_day / videos_posted_through_daynull when no videos have been posted through that day yet.
curl -H "Authorization: Bearer tga_<key>" \
"https://www.trackagoat.com/api/v1/analytics?entity=campaign&entity_id=<uuid>&metric=avg_views_per_post&from=2026-01-01&to=2026-03-31"Day-over-day percentage change for any base metric. Pass base_metric to specify what to measure.
growth_rate = (value[day] − value[day−1]) / value[day−1] × 100null (no prior).null when the prior day's value was 0 or missing.base_metric values: views, likes, comments, shares, saves, followers (creator only), video_count (creator only).# Views growth rate for a creator
curl -H "Authorization: Bearer tga_<key>" \
"https://www.trackagoat.com/api/v1/analytics?entity=creator&entity_id=<uuid>&metric=growth_rate_pop&base_metric=views&from=2026-01-01&to=2026-03-31"
# Follower growth rate
curl -H "Authorization: Bearer tga_<key>" \
"https://www.trackagoat.com/api/v1/analytics?entity=creator&entity_id=<uuid>&metric=growth_rate_pop&base_metric=followers&from=2026-01-01&to=2026-03-31"The /api/v1/analytics endpoint returns:
{
"data": {
"series": [
{
"entity_ref": { "type": "creator", "id": "uuid", "label": "@handle" },
"metric": "engagement_rate_by_views",
"unit": "percent",
"mode": "rate",
"granularity": "day",
"timezone": "America/New_York"
| Field | Description |
|---|---|
series[].entity_ref | Entity type, id, and display label for this series |
series[].points[].value | Computed value, or null for divide-by-zero / missing data |
series[].timezone | IANA timezone used for bucketing |
baselines | Baseline marker events within the range — use as chart annotations |
first_data_date | Earliest date with non-baseline data — use for "All time" preset |
tier_retention_days | Your plan's retention window in days, or null for unlimited |
| Parameter | Type | Description |
|---|---|---|
metric | string | One of the metric IDs above. Omit for legacy response. |
granularity | day | week | month | year | cumulative | custom | Time bucket size. custom requires bucket_days. Defaults to day. |
tz | IANA string | Timezone for bucketing. Defaults to your org's analytics_tz. |
All /api/v1/analytics responses are cached server-side for up to 5 minutes (300 seconds). This means:
meta.cached field in each JSON response is true when data came from cache and false on a cold run.meta.cache_ttl_seconds field is always 300.The cache is also tag-invalidated in real time on data mutations — not just when the TTL expires. Most changes take effect within seconds.
The cache is tag-invalidated (not just TTL-expired) in these situations:
| Event | Scope |
|---|---|
| Scraper writes new video stats | All analytics for the affected org |
| Scraper updates creator profile | All analytics for the affected org |
| Scraper rebuilds a campaign rollup | That campaign's analytics |
| You add/remove a video from a campaign | That campaign's analytics |
| You create, edit, or delete an annotation | Analytics for the annotated entity |
You change the org's analytics_tz setting | All analytics for the org |
After a cache-busting event, the next request for affected data runs a fresh resolver. The maximum staleness in the worst case is 5 minutes (TTL alone), but in practice most data mutations trigger near-instant invalidation via the scraper webhook or inline revalidateTag calls.
Today's in-progress bucket may be up to 5 minutes stale even with invalidation active — this is by design. The partial_bucket field tells you the as_of timestamp of the last data capture so you can show it to users.
Campaign analytics data is served from a pre-aggregated rollup that is rebuilt nightly and updated within ~5 minutes whenever a video is added to or removed from a campaign. Today's partial data may be up to a few minutes behind as changes propagate through the invalidation queue.
Historical saves values in older campaign snapshots may read as 0 — this is expected, as earlier snapshots did not record save counts.
Every Analytics tab ships a shared toolbar that controls all charts on the panel simultaneously.
| Preset | Range |
|---|---|
| Last 7 days | Past 7 days |
| Last 30 days | Past 30 days (default) |
| Last 90 days | Past 90 days |
| Last year | Past 365 days |
| All time | From first recorded data point |
| Custom | Pick any start/end dates with the date picker |
Presets beyond your plan's history window are disabled with an upgrade prompt. All time always works — it clamps automatically to the oldest data available on your plan and shows a notice like "Showing last 90 days (Free plan)."
Controls the width of each time bucket. Choose from Auto, Day, Week, Month, Year, Cumulative, or Custom (N days).
| Mode | Description |
|---|---|
| New | Each bucket shows only the delta gained in that period. |
| Cumulative | Each bucket shows the running total from the beginning of the range. |
Rate-only metrics (engagement rate, growth rate) ignore this toggle — they always show rates.
Toggle the vs prior period switch to overlay a second series shifted back by the same length as the selected range. This lets you see whether this week outperformed last week, or this month versus last month. The prior-period line renders dashed in a muted color alongside the primary series.
When compare is active, a row of Δ% summary cards appears above the charts showing the change for each metric versus the prior period:
±X.Xpp rather than a percentage (since a percentage-of-a-percentage is misleading)Today's bucket (and any in-progress bucket) is drawn dashed on the chart to indicate it's incomplete. It is excluded from the Δ% card calculation so partial data doesn't distort the summary. The prior-period equivalent of that bucket is also excluded, keeping the comparison fair.
If the prior window extends before your tracking history or your plan's retention limit, the available prior period is automatically clamped. A muted notice appears below the toolbar indicating how many days of data were available versus requested — for example:
Prior period partial — 22 of 30 days available (before tracking started)
Hovering a dashed prior-period line in this state shows a tooltip with the same context.
Limitations
compare=prior_period with a non-none breakdown return a 400 error (compare_breakdown_exclusive).Each plan tier has a maximum analytics history window:
| Plan | History window |
|---|---|
| Free | 90 days |
| Starter | 365 days |
| Ultra | Unlimited |
When you select a range that would exceed your tier's limit:
from date outside your window the API gate (below) will fire.If you request a from date older than your plan's retention window, the unified endpoint returns HTTP 402:
{
"data": null,
"error": "Requested range exceeds plan retention window",
"meta": {
"code": "retention_exceeded",
"limitKey": "stats_history_retention_days",
"tier_retention_days": 90,
"requested_from": "2025-01-01",
"earliest_allowed": "2026-01-21"
}
}Use tier_retention_days from any successful response to pre-check the available window before issuing a long-range query.
When an org is downgraded to a lower tier, the previous tier's retention window remains in effect for 14 days to give users time to export data. After 14 days, the new tier's limit is enforced for both queries and the nightly data purge.
On the Creator and Campaign analytics tabs you can overlay up to 5 entities on the same charts to compare performance side-by-side.
Click the "Compare with…" button in the toolbar (the icon with overlapping people).
Search for creators or campaigns by name.
Select up to 4 additional entities — your primary entity is always pinned and shown first.
Each entity gets a distinct color, stable across every chart panel on that tab.
The selected entity IDs are encoded in the URL as ?tbe=id1,id2,.... Copying the URL and sharing it with a teammate preserves the full overlay view — same date range, granularity, and selected entities.
All toolbar state (range preset, granularity, mode, compare toggle, and custom dates) is persisted in the page URL via short query parameters. Copy the URL from your browser's address bar to share an exact chart view with a teammate — they'll land on the same date range and settings.
The toolbar also saves your last-used settings per entity type (creator, campaign, video) in your browser's local storage, so your preferred range is restored when you navigate back to that tab.
engagement_rate_by_followers on video entitiesNot supported — use creator or campaign entities instead.
growth_rate_pop with follower or video count base metricsbase_metric=followers and base_metric=video_count are only supported for creator entities.
The Mode toggle changes how each time bucket is rendered:
| Mode | Chart type | What you see |
|---|---|---|
| New | Bar chart | Delta gained in that bucket only — e.g., views added this week |
| Cumulative | Area chart | Running total from the start of the selected range |
Switching modes does not change the underlying data — only how it is displayed. Use New to spot spikes and posting cadence; use Cumulative to see growth trajectory.
Metrics like Engagement Rate ignore the Mode toggle and always render as a line chart, since a rate is neither a delta nor a running total.
When the most recent bucket covers a time period that hasn't ended yet (e.g., a weekly bucket mid-week), the chart shows a Partial · as of HH:mm TZ label above the chart. The in-progress bar or area is shaded to distinguish it from completed buckets.
Vertical dotted lines on a chart mark when tracking first started for that entity (labeled Tracking started) or when a manual baseline snapshot was recorded (labeled Baseline). Data before a baseline marker represents the snapshot state, not necessarily change over time.
The Breakdown button in each chart panel header lets you decompose a single aggregate series into its top constituent entities — up to 10, with everything else rolled into an Other segment.
| Entity scope | Available breakdown dimensions |
|---|---|
| Campaign | By video, By creator |
| Creator | By video |
How it works:
bdv=video, bdl=creator, etc.), so links are shareable.Constraints:
compare=prior_period) are mutually exclusive. Enabling comparison disables the breakdown menu.On the Video analytics tab, the View Velocity chart shows how many views a video gained per day after it was posted (day 0 = post date).
Toggle Compare to cohort to overlay two dashed reference lines:
Both lines show the number of videos in the cohort in the chart legend. If a creator has only published the current video, the creator avg line is hidden and a note is shown. Org avg always appears when there is data.
The Engagement Breakdown panel on Campaign and Video analytics shows Likes, Comments, Shares, and Saves as stacked segments. Each color maps to one metric. Use Mode: New to see engagement added per period, or Mode: Cumulative for total engagement over the range.
The Engagement Rate panel is available on Creator and Campaign tabs. It calculates:
(likes + comments + shares + saves) / views × 100A value of 5% means roughly 1 in 20 views resulted in some form of engagement. This panel always renders as a line chart and is not affected by the Mode toggle.
Annotations are event markers that appear as pins at the top of each analytics chart. They help you correlate metric changes with real-world events.
| Source | Kind | Description |
|---|---|---|
| User | user | Notes you add manually — title, optional date/time, optional markdown body |
| Auto | creator_profile_change | Detected changes to a creator's TikTok profile (bio, avatar, etc.) |
| Auto | creator_milestone | Follower/view milestones crossed by a creator |
| Auto | campaign_created | When a campaign was created |
| Auto | readme_changed |
Annotations follow a cascade-down model:
Video-scoped annotations do not cascade up — they stay local to that video's tab.
Each chart panel has a toggle in the Annotations popover labeled Show auto annotations. When turned off, only your user-authored notes are shown. This preference is saved in the URL (?tbha=1) and local storage.
Each pin represents one or more annotations bucketed to the same time period. The badge shows how many. Click a pin to see all annotations in that bucket — title, timestamp, any markdown content, and the cascade source if applicable.
formula | by_views | by_followers | Only for engagement_rate_by_views / engagement_rate_by_followers. |
base_metric | string | Required for growth_rate_pop. |
from | YYYY-MM-DD | Range start (default: 30 days ago). |
to | YYYY-MM-DD | Range end (default: today). |
| When a creator or campaign README was edited |