Skip to main content
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

Developer dashboard

Open simkl.com/settings/developer/ while logged in. The page lists every app you’ve registered.

Your app's row

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.

Debug link

Click Debug (top-right of the app card). The analytics view opens in a new tab.
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.

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 so we can’t attribute it to your app).
  • Verify your sync loop matches the two-phase pattern 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 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

What each column shows

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 failuresOrigin contains 4 (catches 4xx)
  • One endpointPath equals /sync/history
  • One countryCountry equals US
  • One machineClient 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

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 for the full reference. The minimum that works:
Calls without these get attributed to the anonymous bucket and never surface in your Debug view.

See also

Get an API key

Developer dashboard — register a new app or jump to your existing apps’ Debug views.

Required headers

The client_id / app-name / app-version / User-Agent reference.

Rate limits

Per-app daily quotas, per-IP throttling, the 20-second write lock.

Errors

What each error envelope means when the Debug view shows a 4xx / 5xx row.