screentime

mcp
Security Audit
Fail
Health Pass
  • License — License: MIT
  • Description — Repository has a description
  • Active repo — Last push 0 days ago
  • Community trust — 25 GitHub stars
Code Fail
  • rm -rf — Recursive force deletion command in scripts/build_site.sh
Permissions Pass
  • Permissions — No dangerous permissions requested

No AI report is available for this listing yet.

SUMMARY

Apple Screen Time from iPhone, iPad and Mac in your own database: SQLite, InfluxDB and Grafana, Home Assistant and MCP.

README.md
Screen Time Exporter logo: a 24-hour dial with the midnight-to-six quarter lit and three bars of use.

Screen Time Exporter

Apple Screen Time from your iPhone, iPad and Mac — in your own database, Grafana, Home Assistant and AI assistant.


One small background agent on your Mac. No cloud service, no account, no ActivityWatch server.

CI
Platform: macOS
Python
Grafana
Home Assistant
MCP
License: MIT

Website • Overview • Features • Screenshots • Quick start • Command line • AI assistants • How it works • Docs

Grafana dashboard with demo data: today's screen time with an hourly sparkline, today per device, the 7-day average and its change, daily stacked bars by device and by category, and a category donut.

Overview

Apple shows Screen Time on each device, for a week or two, and nowhere else. You cannot keep it, query it, chart it next to other data or trigger anything from it. Yet every Mac signed in to your Apple Account already receives the app usage of your iPhone and iPad through iCloud.

Screen Time Exporter reads those stores on the Mac — Biome for iPhone and iPad, knowledgeC.db for the Mac itself — every 15 minutes. It keeps every session in a local SQLite database, names and categorises the apps, and passes the result on to InfluxDB and Grafana, Home Assistant, the terminal, or an AI assistant over MCP.

The project stays deliberately:

  • local-first — the database lives on your Mac; nothing is sent anywhere unless you configure a sink.
  • read-only towards Apple — it only reads Apple's stores (knowledgeC.db through a temporary copy) and never writes to them.
  • small — one Python package, one runtime dependency, one launchd agent.
  • honest about what it knows — Apple keeps a few weeks of history; anything older only exists if the exporter was running.

Unofficial hobby project. Not affiliated with Apple — see Disclaimer.

Features

  • Every device on one Mac: iPhones and iPads via iCloud (Screen Time → Share Across Devices), plus the Mac itself, each with its own name.
  • Sessions, not just totals: every app session with start, duration, app and category, aggregated per day, app, category and hour.
  • Late night and deep night: use between 00:00–06:00 and 03:00–06:00, plus the night's phone-free window (bedtime and wake-up).
  • Readable app names: 270+ bundle ids ship with a name and one of 14 categories; unknown ones are named from the installed Mac app or your region's App Store, once, and cached. Your own names go in the config (docs/apps.md).
  • Grafana dashboard: provisioned or importable, with device, category and app filters. A Docker Compose file starts InfluxDB and Grafana with everything wired up.
  • Home Assistant sensors: total, per device, late and deep night per device, week, top app, categories and last sync — v1 entity ids keep working.
  • Terminal reports: screentime summary for a week, day or range, as text, Markdown or JSON; screentime dump as CSV or JSON.
  • MCP server: Claude, Codex, Cursor and other MCP clients answer questions about your screen time from the local database.
  • One-command setup: screentime setup finds devices, tests the connections, writes the config and installs the agent; screentime doctor explains what is wrong.

Screenshots

Apps section with demo data: top 15 apps as bars, an app table with category, devices, total, average per active day and sessions, and one top-10 panel each for MacBook, iPad and iPhone. Night section with demo data: late-night KPIs for today and the last 7 days, late night per day split into 00–03 and 03–06, and a bedtime and wake-up chart with the phone-free night shaded between the lines.
Apps · top apps, app details and top apps per device Night · late and deep night, bedtime and wake-up
Rhythm section with demo data: a typical day as average minutes per hour stacked by device, sessions per day, and a weekday by hour grid with a per-day total. Terminal window showing screentime summary --week last for demo data: totals, change against the previous week, devices, days, top apps, categories, late night and an hourly sparkline.
Rhythm · typical day and weekday × hour screentime summary --week last · real output, demo data

All screenshots use the synthetic data from scripts/demo_data.py.

Full dashboard
The complete Grafana dashboard with demo data, from the header KPIs through devices and categories, apps, night and rhythm.

Quick start

uv tool install plus the setup wizard is the recommended path.

Requirements:

  • A Mac signed in to the same Apple Account as your iPhone and iPad, with Screen Time → Share Across Devices on for every device.
  • uv (curl -LsSf https://astral.sh/uv/install.sh | sh). It brings its own Python 3.11+.
uv tool install git+https://github.com/nichtlegacy/screentime
screentime setup             # devices, InfluxDB, Home Assistant, launchd agent
screentime doctor            # every check should say OK
screentime summary --day     # today in the terminal

Expected: screentime setup lists your iPhone, iPad and Mac, runs a first sync and installs the launchd agent io.github.nichtlegacy.screentime, which syncs every 15 minutes.

Apple's stores are protected. Give Full Disk Access (System Settings → Privacy & Security → Full Disk Access) to your terminal for setup and to the Python interpreter that screentime setup prints for the background agent — why two.

InfluxDB and Grafana

docker/docker-compose.yml runs InfluxDB 2.7 and Grafana 12 with the datasource and the dashboard provisioned:

cp docker/.env.example docker/.env       # set INFLUX_TOKEN and both passwords
docker compose -f docker/docker-compose.yml --env-file docker/.env up -d

Grafana listens on port 3000 (GRAFANA_PORT), InfluxDB on 8086 (INFLUX_PORT). Give screentime setup the InfluxDB URL, the token, org home and bucket screentime. For an existing Grafana, add an InfluxDB datasource with the Flux query language and import grafana/dashboards/screentime.json; the dashboard asks for the datasource and bucket.

The dashboard's "today" and "last 7 days" use the browser's time zone, which should match the exporter's timezone.

Home Assistant

Create a long-lived access token (Profile → Security) and give it to screentime setup with your Home Assistant URL. The sensors appear after the next sync:

Sensor State
sensor.screentime_total minutes today, all devices
sensor.screentime_<device> minutes today on one device
sensor.screentime_<device>_late_night / _deep_night minutes today between 00–06 / 03–06
sensor.screentime_week minutes this week, with the daily average
sensor.screentime_top_app, _top_apps, _by_category today's top app, top 10, top category
sensor.screentime_last_sync time of the last export

Attributes, the limits of REST states, example automations and a dashboard card: docs/home-assistant.md.

Upgrading from v1

v2 replaces the CSV, .env and aw-import-screentime with one installed tool. The v1 Home Assistant entity ids stay. Steps: docs/migration.md.

Command line

Command What it does
screentime setup interactive setup and launchd agent; --yes for scripted installs, --uninstall [--purge] to remove
screentime run sync all sources, then export to the configured sinks (what the agent runs)
screentime sync / export [--from DATE] only read the sources / only export, optionally re-sending from a date
screentime summary report for --week, --day or --from/--to, per --device, as text, markdown or json
screentime dump sessions or --daily totals as CSV or JSON
screentime apps unknown / apps lookup <id> apps that still have a guessed name / look one bundle id up (installed app, then App Store)
screentime remap reapply names and categories to all stored sessions
screentime status devices, last run and sinks as JSON
screentime doctor [--online] check config, Full Disk Access, agent, data freshness and connections
screentime mcp MCP server over stdio (--http for localhost HTTP)

Options and the JSON shape: docs/cli.md.

AI assistants (MCP)

screentime mcp is a read-only Model Context Protocol server over the local database. The MCP SDK is an optional extra:

uv tool install --force "screentime-exporter[mcp] @ git+https://github.com/nichtlegacy/screentime"
claude mcp add -s user screentime -- screentime mcp      # Claude Code

For Claude Desktop, add this to ~/Library/Application Support/Claude/claude_desktop_config.json (use the path from which screentime):

{
  "mcpServers": {
    "screentime": { "command": "/Users/you/.local/bin/screentime", "args": ["mcp"] }
  }
}

Codex, Cursor and other clients: docs/mcp.md.

Tool Answers
list_devices which devices exist, since when, how much in total
get_summary the full report for a period, like screentime summary --format json
get_daily_usage per-day totals, late and deep night, first and last activity
get_top_apps, get_categories time per app or category, with share
get_late_night use after midnight, the worst night, every night with use

Try: "How much screen time did I have last week compared to the week before?" or "Was I on my phone after midnight this week?"

Let your AI agent install it

A coding agent with terminal access can run the whole setup; you only flip the Full Disk Access switches and enter tokens yourself. The prompt to paste is in docs/agent-installation.md.

How it works

flowchart LR
  subgraph phone["iPhone · iPad"]
    st["Screen Time<br/>Share Across Devices"]
  end
  subgraph mac["Mac · launchd every 15 min"]
    biome[("Biome App.InFocus<br/>iPhone · iPad")]
    kc[("knowledgeC.db<br/>this Mac")]
    run["screentime run<br/>src/screentime/"]
    db[("SQLite<br/>screentime.db")]
  end
  st -->|"iCloud"| biome
  biome --> run
  kc --> run
  run -->|"sessions + daily aggregates"| db
  names["Installed Mac apps · App Store<br/>unknown bundle ids"] -.->|"name, category"| run
  db -->|"changed days"| influx[("InfluxDB 2")]
  influx --> grafana["Grafana<br/>grafana/dashboards/"]
  db -->|"REST states"| ha["Home Assistant"]
  db -->|"read-only"| cli["summary · dump"]
  db -->|"read-only, stdio"| mcp["screentime mcp"]
  mcp --> ai["Claude · Codex · Cursor"]
  • Sources only read. sources/biome.py parses the SEGB files of the App.InFocus stream, sources/knowledgec.py reads /app/usage from a temporary copy of knowledgeC.db. Each keeps its own cursor in SQLite.
  • Sessions are the source of truth. Sessions are upserted by device, start and bundle id, so overlapping reads are harmless. Touched days are rebuilt into daily, per-app, per-category and hourly aggregates, split at midnight, 03:00 and 06:00.
  • Exports are idempotent. InfluxDB gets each changed (device, day) deleted and rewritten; Home Assistant gets current-day states. A failed sink never loses data, the next run retries.
  • Names without manual work. Unknown bundle ids are named from the app installed on the Mac (Spotlight) or, failing that, your region's App Store, once, and cached. A changed [apps] section renames stored sessions on the next run.
  • Readers never block the sync. summary, dump and the MCP server open the database read-only.

Details: architecture, InfluxDB schema, taxonomy.

Configuration

screentime setup writes ~/.config/screentime/config.toml (mode 0600). Every key is optional; config.example.toml lists them all.

What Where Reference
Time zone, database path top level timezone, db_path config.example.toml
Device names, ignored devices [devices] docs/setup.md
App names and categories [apps], [lookup] docs/apps.md
InfluxDB [influx] or INFLUX_URL, INFLUX_TOKEN, INFLUX_ORG, INFLUX_BUCKET docs/architecture.md
Home Assistant [home_assistant] or HA_URL, HA_TOKEN docs/home-assistant.md
Agent label, config path SCREENTIME_AGENT_LABEL, SCREENTIME_CONFIG docs/setup.md

Data lives in ~/Library/Application Support/screentime/, logs in ~/Library/Logs/screentime/. To remove everything: screentime setup --uninstall --purge, then uv tool uninstall screentime-exporter.

Project structure

src/screentime/
├── sources/            # biome.py (iPhone, iPad), knowledgec.py (Mac)
├── _vendor/ccl_segb/   # SEGB reader from ccl-segb, unchanged
├── importer.py         # sessions into SQLite
├── taxonomy.py         # app names: apps.json, your config, installed apps, App Store
├── aggregates.py       # daily, per-app, per-category and night splits
├── influx.py           # InfluxDB export
├── homeassistant.py    # Home Assistant sensors
├── queries.py          # read-only queries for summary, dump and MCP
├── report.py           # summary and dump
├── mcp_server.py       # MCP tools and resource
├── wizard.py           # screentime setup
├── launchd.py          # launchd agent
├── health.py           # screentime doctor
└── data/               # apps.json (names, categories), models.json (device models)
grafana/                # dashboard and provisioning
docker/                 # InfluxDB + Grafana compose file
scripts/                # demo data generator, landing page build
site/                   # landing page, deployed to GitHub Pages
docs/                   # everything beyond this page

Documentation

The landing page is screentime.nichtlegacy.com. Everything beyond this page is in docs/: setup, migration from v1, command line, app names, Home Assistant, MCP, agent installation, architecture. Release notes: CHANGELOG.md.

Privacy

Everything stays on your Mac unless you configure a sink. Unknown apps are first looked for on the Mac itself; only bundle ids it cannot name go to Apple's public iTunes Lookup API, together with the storefront country. Turn that off with [lookup] enabled = false. The MCP server reads the local database; what your assistant sends to its model is up to the assistant. Tests and screenshots use synthetic data only.

Known limitations

  • macOS only. iPhone and iPad data reaches the exporter only through a Mac with Screen Time sharing on; there is no iOS app. Tested on macOS 27 on Apple silicon.
  • Apple keeps only a few weeks. The first sync reads what is still there (Biome holds about four weeks); history before that is gone.
  • The agent needs Local Network access for an InfluxDB or Home Assistant on your LAN (macOS 15+). Allow it when macOS asks; otherwise exports fail with No route to host (details).
  • Full Disk Access is tied to the Python path. After uv upgrades Python, the background agent needs the grant again; screentime doctor tells you the new path.
  • Home Assistant REST states have no unique_id and vanish on restart until the next sync, at most 15 minutes later (workaround).
  • iPhone and iPad apps outside the App Store (TestFlight, your own builds) and Mac apps that are no longer installed keep a name guessed from the bundle id until you name them in [apps].
  • Not on PyPI yet. Install from GitHub with uv, pipx or pip; every dependency comes from PyPI.

Contributing

Issues and pull requests are welcome, especially app names for apps.json. Checks and guidelines: CONTRIBUTING.md.

Credits

License

MIT.

Disclaimer

Screen Time Exporter is an unofficial, independent hobby project. It is not affiliated with, endorsed by, sponsored by, or connected to Apple Inc. in any way.

"Apple", "Screen Time", "iPhone", "iPad", "Mac", "macOS" and "iCloud" are trademarks of Apple Inc., used here only to describe the data the project reads. It reads files that macOS keeps on your own Mac; it does not use private APIs over the network.

Reviews (0)

No results found