---
title: "Global analytics across every connected account"
method: GET
path: "/analytics/overview"
tags: ["Analytics"]
---

# Global analytics across every connected account

`GET /analytics/overview`

## Request

- Base URL: `https://api.multi-upload-tool.com/api/v1`
- URL: `https://api.multi-upload-tool.com/api/v1/analytics/overview`
- Auth: API key in header `x-api-key`

Aggregates the collected metrics of all your active accounts.

The numbers come from Multi Upload Tool's own store, filled by a nightly collector — they are not read from the platforms at request time. Check `lastRefreshedAt` before presenting them as live: a number without its reading time looks real time, and the first time it disagrees with the platform's own app it reads as a bug rather than a collection that has not run yet.

A metric a platform does not report is counted as `0`, not omitted: YouTube exposes no shares, Bluesky no views, Pinterest no likes.

## Query parameters

- `tags` string
- `source` 'all' | 'mut' | 'external'
- `timezone` string

## Headers

- `X-Team-ID` integer

## Response `200`

Aggregated analytics for the matching accounts.

- object
  - `success` unknown
  - `data` Analytics: What the collector holds for the accounts in scope. Every metric is a running total read from the platform, not a per-day figure.
    - `overview` object
      - `totalViews` integer
      - `totalLikes` integer
      - `totalComments` integer
      - `totalShares` integer
      - `videoCount` integer
      - `accountCount` integer
      - `bestAccount` object, nullable
        - `name` string
        - `platform` 'tiktok' | 'youtube' | 'instagram' | 'facebook' | 'linkedin' | 'pinterest' | 'bluesky' | 'threads' | 'x': A supported social platform.
        - `views` integer
    - `videos` object[]: One row per tracked post, with its metrics, an `isTrending` flag and `source`: `mut` if it was published through Multi Upload Tool, `external` if it was posted directly on the platform.
    - `bestPerforming` object, nullable
      - `mostViewed` object
      - `mostEngaging` object
    - `topHashtags` object[]
    - `postingInsights` PostingInsights: When this account has published, and what those slots averaged. Derived from the posts already collected, so it says nothing until there are enough of them.
      - `timezone` string: The zone the buckets were read in — whatever you asked for, or `UTC`.
      - `minSamples` integer: Posts a bucket needs before it can be ranked.
      - `byWeekday` PostingBucket[]: Always 7 entries, Sunday first, including the days with nothing in them.
        - `weekday` integer: 0 = Sunday, following Postgres' `dow`. Present on `byWeekday` and `bestDay`.
        - `hour` integer: Hour of day in the requested timezone. Present on `byHour` and `bestHours`.
        - `posts` integer
        - `avgViews` integer
        - `ranked` boolean: False when `posts` is under `minSamples`. The bucket keeps its average — it is worth showing — but it is never eligible to win. One lucky post is a coincidence, not a slot, and it is the loudest one: a single viral video gives its bucket an average no honest bucket can beat.
      - `byHour` PostingBucket[]: Always 24 entries, 00:00 first.
        - `weekday` integer: 0 = Sunday, following Postgres' `dow`. Present on `byWeekday` and `bestDay`.
        - `hour` integer: Hour of day in the requested timezone. Present on `byHour` and `bestHours`.
        - `posts` integer
        - `avgViews` integer
        - `ranked` boolean: False when `posts` is under `minSamples`. The bucket keeps its average — it is worth showing — but it is never eligible to win. One lucky post is a coincidence, not a slot, and it is the loudest one: a single viral video gives its bucket an average no honest bucket can beat.
      - `bestDay` PostingBucket: One weekday or one hour of day, averaged over the posts that landed in it.
        - `weekday` integer: 0 = Sunday, following Postgres' `dow`. Present on `byWeekday` and `bestDay`.
        - `hour` integer: Hour of day in the requested timezone. Present on `byHour` and `bestHours`.
        - `posts` integer
        - `avgViews` integer
        - `ranked` boolean: False when `posts` is under `minSamples`. The bucket keeps its average — it is worth showing — but it is never eligible to win. One lucky post is a coincidence, not a slot, and it is the loudest one: a single viral video gives its bucket an average no honest bucket can beat.
      - `bestHours` PostingBucket[]: Up to 5 hours, best first. Ranked buckets only.
        - `weekday` integer: 0 = Sunday, following Postgres' `dow`. Present on `byWeekday` and `bestDay`.
        - `hour` integer: Hour of day in the requested timezone. Present on `byHour` and `bestHours`.
        - `posts` integer
        - `avgViews` integer
        - `ranked` boolean: False when `posts` is under `minSamples`. The bucket keeps its average — it is worth showing — but it is never eligible to win. One lucky post is a coincidence, not a slot, and it is the loudest one: a single viral video gives its bucket an average no honest bucket can beat.
      - `sampleSize` integer: Posts carrying a publication date, i.e. what the buckets were built from.
    - `dailyHistory` object[]
    - `platformHistory` object[]
    - `summary` object: The last 30 days against the 30 before. `null` means not measured, never zero.
      - `windowDays` 30
      - `views` object: Views gained in each period, summed from the daily series (gaps spread evenly, as on the chart). `measuredDays` says how many days of each period had data.
        - `current` integer, nullable
        - `previous` integer, nullable
        - `change` integer, nullable
        - `changePct` number, nullable
        - `measuredDays` object
          - `current` integer
          - `previous` integer
      - `followers` object: `total` = latest follower count summed over accounts. `change` only counts accounts that were also measured 30 days ago, so it stays `null` for the first 30 days of history.
        - `total` integer, nullable
        - `previous` integer, nullable
        - `change` integer, nullable
        - `changePct` number, nullable
      - `postsPublished` object
        - `current` integer
        - `previous` integer
        - `change` integer
    - `followerHistory` object[]: One point per day over the window: the sum of each account's last known follower count. Days before the first reading are omitted.
      - `date` string, date
      - `followers` integer
    - `accountTags` string[]: Only on the single-account route.
    - `lastRefreshedAt` string, date-time, nullable: When the collector last read the platform. Show it next to the numbers.
    - `neverSynced` boolean: `true` means nothing has ever been collected, as opposed to collected and empty. The two deserve different messages: "connect and wait for tonight" is not "you have no posts yet".
    - `syncErrors` object[]: Accounts whose last collection failed. A failing account never stops the others.
      - `accountName` string
      - `platform` 'tiktok' | 'youtube' | 'instagram' | 'facebook' | 'linkedin' | 'pinterest' | 'bluesky' | 'threads' | 'x': A supported social platform.
      - `error` string

## Other responses

- `401`: The API key is missing, invalid, revoked or expired.
- `403`: The token is valid but not permitted to act on this resource, usually because of team scoping or the caller's team role.

---

[API](https://skmtc.dev/multi-upload-tool/apis/multi-upload-tool-api.md) · [All operations](https://skmtc.dev/multi-upload-tool/apis/multi-upload-tool-api/llms.txt) · [OpenAPI document](https://skmtc.dev/multi-upload-tool/apis/multi-upload-tool-api/revisions/bb7e72abbb76?raw)
