Insta Insight
PausedAlways-on Android tablet dashboard showing my wife's Instagram Creator account stats, wake-triggered against the Graph API with a self-refreshing token and no backend.
Highlights
- No backendTalks straight to the Instagram Graph API and refreshes its own long-lived token on the tablet.
- 7-page kiosk dashboardA double-tap wake lands on an auto-rotating dashboard, pinned so nothing else is reachable.
- Undocumented API quirkTraced silently empty comment responses to a Meta Live-mode requirement, written up as a note.
- Battery-first refreshFetches only on wake, with two narrowly scoped WorkManager jobs as the exceptions.
Overview
A single-purpose Android app for a tablet mounted where my wife can glance at her Instagram Creator account stats without opening the Instagram app and digging through its Insights UI. It wakes on a double-tap, fetches from the Instagram Graph API, and auto-rotates through a 7-page dashboard — followers, growth, the latest post, all-time totals, unseen comments, audience demographics, and history graphs — kiosk-pinned so nothing else is reachable on the tablet.
Deliberately no backend: the app talks directly to graph.instagram.com and
refreshes its own long-lived token in place, so there’s no server to run or
pay for, at the cost of the token and its refresh logic having to live
entirely on-device.
Problem
- A passive, always-current view, not another app to open. The point is a glance while walking past the tablet, not a session of opening Instagram and tapping into Insights.
- No backend, but tokens expire. A ~60-day long-lived token has to
refresh itself from the tablet with no server-side secret involved —
driving the choice of the Instagram Login surface specifically for its
secret-free
ig_refresh_tokengrant. - Meta’s setup and docs don’t match reality. Getting from “create an app”
to “comments actually return data” needed several undocumented or
poorly-documented steps: a tester invite accepted by the account owner
(not the app admin), a scope added later without which the comments edge
returns an empty array with no error, and finally switching the app to
Live mode before comments return anything at all. See
SETUP.mdin the repo for the full walkthrough. - Android kiosk behavior isn’t obvious either. Screen Pinning, show-when- locked, and turn-screen-on all had to be combined by trial and error to get a double-tap wake to land directly on the dashboard.
Phases
Tech stack
Languages
- Kotlin
App language throughout.
Frameworks
- Jetpack Compose
Dashboard UI, auto-rotating post pager, kiosk-mode screen.
Libraries
- Retrofit
Typed calls to graph.instagram.com.
- OkHttp
HTTP client + logging interceptor under Retrofit.
- kotlinx.serialization
JSON models for every Graph API response.
- DataStore
Local caches: dashboard, follower history, unseen comments.
Tooling
- EncryptedSharedPreferences
Keystore-backed storage for the single long-lived access token, pinned to security-crypto 1.0.0.
- WorkManager
Two narrow, self-rescheduling job chains that deliberately break the wake-only rule (new-post polling, midnight snapshot).
APIs & Platforms
- Instagram Graph API
Instagram Login surface (graph.instagram.com), chosen for secret-free token refresh.
Approach
Every Graph API call that isn’t guaranteed to be supported gets its own try/catch rather than being trusted to succeed or batched with reliable calls — one unsupported metric silently zeroing an entire combined response was the concrete failure that drove that pattern. The wake-only refresh model (no background service) and the never-clear-a-good-cache rule both follow from the same constraint: this runs unattended on a tablet nobody is actively watching, so a transient failure should degrade gracefully rather than surface as a blank screen or a drained battery. The two background-job exceptions (see Background refresh exceptions) kept that same discipline — narrowly scoped, self-terminating, and stateless enough that neither needed its own error-recovery path beyond WorkManager’s own retry.
Future improvements
- Proper pagination/backoff for all-time stats if the account ever grows past the current ~100-post cap fetched in one call — fine today at 13 posts, not built to scale further.
Related
Setup and the full Meta app / API access walkthrough (tester invites, scope
gotchas, the Live-mode requirement for comments, kiosk configuration) live in
SETUP.md in the project repo.






