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

# API Analytics

> Live per-app request log — see exactly what your code sends to api.simkl.com, filter it, export it.

Every registered Simkl app has a built-in **Analytics view** with **up to 24 hours** of individual requests your app made against `api.simkl.com`, plus a **7-day rollup** of daily request totals. It's the fastest way to confirm what your code is actually sending — without setting up your own logger.

## Opening it

<Steps>
  <Step title="Developer dashboard" icon="user-gear">
    Open **[simkl.com/settings/developer/](https://simkl.com/settings/developer/)** while logged in. The page lists every app you've registered.
  </Step>

  <Step title="Your app's row" icon="hand-pointer">
    Click the app to land on its page (URL: `simkl.com/settings/developer/{APP_ID}/`). This is also where your `Client ID` and `Client Secret` live.
  </Step>

  <Step title="Debug link" icon="bug">
    Click **Debug** (top-right of the app card). The analytics view opens in a new tab.
  </Step>
</Steps>

<Note>
  The page is opened via a short-lived signed link. The link **expires after 1 hour** — close and re-open the Debug link from your developer dashboard for a fresh session. The dashboard page is what authorizes you; the analytics URL itself isn't bookmarkable.
</Note>

## What you can do here

* **Confirm your code is actually hitting Simkl.** Issue a request from your app, hit Refresh — if it doesn't appear, your client never reached us (wrong host, blocked by a proxy, or missing the [required headers](#headers-required-to-show-up) so we can't attribute it to your app).
* **Verify your sync loop matches the [two-phase pattern](/guides/sync) the Sync guide requires.** Apps that don't follow it download the whole user library every poll and get rate-limited — sometimes blocked. The Debug view makes both halves easy to audit:
  1. Filter on `Path equals /sync/activities` — this is the cheap "did anything change?" check that has to fire **first** on every poll. If it isn't there, your loop is broken.
  2. Filter on `Path contains /sync/all-items` and look at the **Query** column for every row. Each one should include `date_from=<your_last_saved_timestamp>` so Simkl returns only the delta. A `/sync/all-items` row with no `date_from` means your client is asking for the whole library — fix it before it gets throttled.
* **See exactly what your OAuth library / SDK puts on the wire.** Wrappers and middleware obscure this; the Debug view shows the literal `client_id`, `app-name`, `app-version`, and `User-Agent` your library sent — useful for diagnosing `empty_field` and `grant_error` responses.
* **See the HTTP status Simkl returned, even when your client only shows a generic error.** Some HTTP libraries surface "Network error" or "Bad Request" without the actual status code. The **Edge** and **Origin** columns show `200` / `401` / `403` / `412` etc. for every request — pair the code with [/conventions/errors](/conventions/errors) to map it back to the meaning. Response bodies aren't recorded in the Debug view, but for `GET` requests the **Link** column re-fires the same URL in a new browser tab so you can read the live response body. `POST` / `PUT` / `DELETE` bodies still have to come from your own logging.
* **Spot retry loops, runaway timers, and duplicate calls.** The red **Burst** column and **High Traffic Burst Detected** banner surface "N requests in 1 second from the same IP" patterns automatically — find which path your code is over-firing before the auto-blocker does.
* **Tell edge cache hits from real backend responses.** When `Edge=200` and `Origin` is blank, the response came from the edge cache without touching the backend — useful for understanding why a stale value sometimes persists after a write.
* **Compare staging vs prod, or app A vs app B.** Filter on `User agent` or `Client IP` to slice traffic by deployment / machine and confirm each environment is sending what you think it is.
* **Export a CSV** of the current filtered view to drop into a spreadsheet, share with support, or attach to a bug report.

## Controls

| Control     | What it does                                                                                                                                                                                                         |
| ----------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **TIME**    | Look-back window. Anywhere from `1h` to `24h`. Default `6h`.                                                                                                                                                         |
| **LIMIT**   | Max events per load. Default `100`, max `1000`.                                                                                                                                                                      |
| **Load**    | Apply the current TIME + LIMIT and pull the events.                                                                                                                                                                  |
| **Refresh** | Re-pull with the same settings.                                                                                                                                                                                      |
| **Mask**    | One-click redact of sensitive query-string values (`code`, `token`, `access_token`, `refresh_token`, `redirect`, `redirect_uri`, `pin`) as `***` so screenshots and shared views don't leak secrets. Off by default. |
| **Copy ID** | Copies your `client_id` to the clipboard.                                                                                                                                                                            |
| **Export**  | Downloads the current (filtered) event list as CSV.                                                                                                                                                                  |

## What each column shows

| Column                            | Meaning                                                                                                                                                                                                                                                                                                  |
| --------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Time**                          | When the request hit Simkl. Defaults to **New York time** (EDT/EST); the column header shows the timezone label so you know what you're looking at.                                                                                                                                                      |
| **Burst**                         | Red `N` badge when N≥3 requests landed in the same second from the same IP. Single requests show nothing.                                                                                                                                                                                                |
| **Method**                        | `GET`, `POST`, etc.                                                                                                                                                                                                                                                                                      |
| **Scheme**                        | `https` (or `http` if your client is misconfigured).                                                                                                                                                                                                                                                     |
| **Path**                          | The endpoint hit. `/oauth/pin`, `/sync/all-items/...`, etc.                                                                                                                                                                                                                                              |
| **Query**                         | Querystring as sent. Click the **Mask** control above to redact sensitive parameters (`code`, `token`, `access_token`, `refresh_token`, `redirect`, `redirect_uri`, `pin`) as `***` before screenshotting or sharing the view. Off by default.                                                           |
| **App Ver**                       | Value your client sent in the `app-version` query parameter. Column only appears if any visible event has it.                                                                                                                                                                                            |
| **Link**                          | Opens the full request URL in a new browser tab — re-fires the same `GET` against `api.simkl.com` and shows the response body inline. Handy for `GET` rows where you want to see the actual JSON your code received. (Doesn't replay POST / PUT / DELETE — the browser address bar can only issue GETs.) |
| **Edge**                          | HTTP status from Simkl's edge layer.                                                                                                                                                                                                                                                                     |
| **Origin**                        | HTTP status from Simkl's backend. Usually the same as Edge; differs when the response was served from the edge cache without touching the backend (Edge `200`, Origin blank).                                                                                                                            |
| **Origin latency (ms)**           | How long the backend took to produce the response, when measured.                                                                                                                                                                                                                                        |
| **Cache status / Cache response** | Whether the request hit the edge cache, and what status it cached.                                                                                                                                                                                                                                       |
| **Client IP**                     | A short opaque ID like `e-JgphVReMb9` — not your real IP. Same machine = same ID, so you can group "all the calls from this user" without exposing addresses.                                                                                                                                            |
| **Country**                       | Where the request came from.                                                                                                                                                                                                                                                                             |
| **User agent**                    | The `User-Agent` header your client sent — useful for telling staging and prod apart.                                                                                                                                                                                                                    |

## Burst detector

When 3+ requests from the same IP land in the same second, the page surfaces a red **High Traffic Burst Detected** banner at the top of the table plus a `X% BURST` badge near the event count. The Burst column highlights the specific rows that fired it.

The three usual culprits:

* **Retry loops without backoff** — fix with exponential backoff + jitter.
* **Parallel requests** — fire calls **sequentially**, awaiting each response before issuing the next. Don't `Promise.all` the same endpoint, don't let a new poll tick start before the previous one returned.
* **UI effects re-firing every render** — gate your `useEffect` / equivalent on a stable dependency.

Repeatedly tripping the banner can get your `client_id` throttled or temporarily blocked. Fix the loop before the auto-blocker fires — recovery isn't automatic.

## Filters

The **Filter results...** box does a free-text match across all visible columns.

**+ Add filter** opens a composer. Pick a column, an operator (`equals`, `not equals`, `contains`, `not contains`, `starts with`, `ends with`, `in`, `not in`), and a value. The value field autocompletes from what's actually in the data. Stack multiple filters — they AND together.

A few recipes:

* **Just failures** → `Origin contains 4` (catches 4xx)
* **One endpoint** → `Path equals /sync/history`
* **One country** → `Country equals US`
* **One machine** → `Client IP equals e-JgphVReMb9` (click the IP in any row to filter to its sibling requests)

**Exclude detail pages** is a one-click filter that hides per-record detail endpoints (typically the chattier ones), so the burst detector and the table focus on your sync/scrobble calls.

## Headers required to show up

<Warning>
  **Requests without identifying parameters don't appear in your analytics.** Simkl matches events to your app by the `client_id` it sees in the request — so every API call has to include:

  * `client_id` query parameter
  * `app-name` and `app-version` query parameters
  * `User-Agent` header in the form `my-app-name/1.0`

  See [Headers](/conventions/headers) for the full reference. The minimum that works:

  ```bash theme={"theme":{"light":"github-light","dark":"vesper"}}
  curl "https://api.simkl.com/<endpoint>?client_id=YOUR_CLIENT_ID&app-name=my-app-name&app-version=1.0" \
    -H "User-Agent: my-app-name/1.0"
  ```

  Calls without these get attributed to the anonymous bucket and never surface in your Debug view.
</Warning>

## See also

<CardGroup cols={2}>
  <Card title="Get an API key" icon="key" href="https://simkl.com/settings/developer/">
    Developer dashboard — register a new app or jump to your existing apps' Debug views.
  </Card>

  <Card title="Required headers" icon="list-check" href="/conventions/headers">
    The `client_id` / `app-name` / `app-version` / `User-Agent` reference.
  </Card>

  <Card title="Rate limits" icon="gauge-high" href="/resources/rate-limits">
    Per-app daily quotas, per-IP throttling, the 20-second write lock.
  </Card>

  <Card title="Errors" icon="triangle-exclamation" href="/conventions/errors">
    What each error envelope means when the Debug view shows a 4xx / 5xx row.
  </Card>
</CardGroup>
