Threads Analytics — self-hosted analytics for your Threads account

A self-hosted Threads analytics dashboard. Connect your access token and explore post performance with detailed charts and metrics.

GitHub stars License: AGPL-3.0 Docker image on GHCR

繁體中文 · English · 日本語

Website · Live demo · Token guide

--- ## Table of Contents - [Features](#features) - [macOS Desktop App](#macos-desktop-app) - [Quick Start](#quick-start) - [Getting Your Threads Access Token](#getting-your-threads-access-token) - [MCP Server](#mcp-server) - [Deployment](#deployment) - [Docker Compose](#docker-compose) - [Docker](#docker) - [Vercel](#vercel) - [Auto-sync](#auto-sync) - [Updating an existing deployment](#updating-an-existing-deployment) - [Development](#development) - [Analytics Reference](#analytics-reference) - [License](#license) --- ## Features - **Today** — everything about today on one page: totals of today's posts with replies awaiting you and follower change, posting rhythm and best hours, every number for each of today's posts, yesterday's posts and what they picked up today, and an inbox of today's replies showing which are still waiting on you (read live from Threads, never stored) - **Overview** — stat cards (views, likes, replies, reposts, quotes, shares, engagement rate) with period-over-period delta, views trend chart (day / week / month), best posting hour recommendation, and viral posts - **Analytics** — 31 charts across **Performance**, **Content**, and **Audience** tabs - **Posts** — searchable, filterable list with per-post analytics panel, including each post's growth curve over its first week - **Giveaway** — draw winners from a post's replies with stackable conditions (keyword, tagged friends, deadline, one entry per account), right inside your dashboard - **MCP server** — let Claude and other AI agents query your analytics through an OAuth-protected endpoint - Multi-account support with account switching - Auto-sync on configurable intervals - Automatic access-token renewal — connect once, no manual re-pasting every 60 days - Password-protected (single `APP_PASSWORD` env var) - English / 繁體中文 / 日本語 UI, with light, dark, and Auto appearance
Overview — your account at a glance

Overview · your account at a glance

Today — today's posts and the replies waiting on you

Today · today's posts and the replies waiting on you

Analytics — account views, split by source

Analytics · account views, split by source

Posts — every post's first week, hour by hour

Posts · every post's first week, hour by hour

Audience — follower growth and where your followers are

Audience · follower growth and where your followers are

Giveaway — winners drawn from a post's replies

Giveaway · winners drawn from a post's replies

--- ## macOS Desktop App Macs with Apple silicon (M1 or later) can download the desktop app directly from [GitHub Releases](https://github.com/ridemountainpig/threads-analytics/releases), with no need to install Node.js, pnpm, or PostgreSQL. An Intel Mac build is not currently available. See the [Mac app guide](https://threads-analytics.app/en/desktop) for download, first launch, update, and uninstall instructions. To build the desktop app from source, see the [desktop README](./desktop/README.md). --- ## Quick Start The fastest way to a running instance is the one-click Railway template — it provisions a PostgreSQL database and sets the required environment variables for you: [![Deploy on Railway](https://railway.com/button.svg)](https://railway.com/deploy/zibjsX?referralCode=vPBCb4&utm_medium=integration&utm_source=template&utm_campaign=generic) Prefer to let an AI coding agent (Claude Code, Codex, Cursor…) handle it? Each agent deploy guide comes with a ready-made prompt — paste it into your agent and it provisions the database, deploys the app, and hands back the URL: [Railway](https://threads-analytics.app/en/deploy/railway-agent) · [Vercel](https://threads-analytics.app/en/deploy/vercel-agent) Already have a server? [Docker Compose](#docker-compose) starts the app and its PostgreSQL together with one command, or run the prebuilt image against a database you already have (see [Docker](#docker)). Once the app is up, sign in with your `APP_PASSWORD` and connect a Threads account — see the next section. To run from source instead, see [Development](#development). --- ## Getting Your Threads Access Token 1. Go to [developers.facebook.com](https://developers.facebook.com) and create an app with the **Access the Threads API** use case 2. Generate an **Access Token** 3. In the dashboard: **Settings → Add Threads Account → paste token** For a screenshot-based walkthrough, see [How to Generate a Threads Access Token](https://threads-analytics.app/en/token-guide). Tokens are valid for 60 days, and the app renews them for you: - During each sync, the app checks the token and automatically extends it for another 60 days once fewer than 30 days remain (the Threads API only renews tokens older than 24 hours). - The account card in Settings shows the token's expiry date and the last automatic renewal. - If a token still expires — e.g. the app was offline too long for a sync to renew it — the dashboard shows an expiry warning. Generate a new token and paste it with the **Update token** button on the account card; your synced data is kept. --- ## MCP Server The dashboard ships a remote [MCP](https://modelcontextprotocol.io) server at `/api/mcp` (Streamable HTTP), so AI agents like Claude can query your synced Threads data — posts, aggregated analytics, and follower history — and answer questions or write reports about your account. Everything is **read-only**. ### Connecting an agent Authentication uses OAuth 2.1 with PKCE and Dynamic Client Registration — there is no API key to copy. On first connection the client registers itself, your browser opens the dashboard login (`APP_PASSWORD`), and you approve access on a consent screen. **Claude Code** ```bash claude mcp add --transport http threads-analytics https://your-deployment.example.com/api/mcp ``` Then run `/mcp` inside Claude Code to complete the OAuth sign-in. **Claude (web / desktop)** — Settings → Connectors → **Add custom connector**, and paste `https://your-deployment.example.com/api/mcp`. Connected clients appear in **Settings → Connected agents**, where each one can be revoked at any time. ### Tools | Tool | What it does | | ---------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `get_account_overview` | Every connected account's username, sync status, post count, data date range, and follower growth summary — the recommended first call | | `list_posts` | Posts with metrics; supports date range, sorting (date / views / likes / engagement rate), media-type filter, full-text search, and pagination | | `get_post` | Full detail of a single post, including its complete text and its metrics 1h, 3h, 6h, 12h, 24h, 48h, and 7d after publishing | | `compare_post_growth` | Posts compared at the same age since publishing (e.g. views 24 hours in) and ranked against your median, plus whether posts too young for that milestone are ahead of or behind your others at the same age | | `get_analytics` | 31 aggregated analytics sections over a date range (best time to post, keyword analysis, views distribution, posting streaks, …) — pick only the sections you need | | `get_follower_history` | Daily follower-count snapshots with growth summary, and optionally the latest audience demographics | | `compare_periods` | Core metrics for two periods with absolute and percentage changes, including account-level views; the comparison period defaults to the same-length window immediately before | | `get_monthly_review` | One calendar month against a comparison month (the previous one by default, or any earlier month such as the same month last year) and a trailing baseline: KPIs, top and bottom posts, follower gains, content mix, threads, and weekly trend. Pass last month's experiments to have each one scored | With several accounts connected, every tool except `get_account_overview` takes an `account` argument (username or id). If it is omitted, the tool returns the list of accounts so the agent asks you which one you mean instead of guessing. Dates given as `YYYY-MM-DD` cover that whole day in the analytics timezone (Asia/Taipei by default; the desktop app uses the Mac's timezone); `list_posts`, `compare_post_growth`, `get_analytics`, `compare_periods`, and `get_monthly_review` also take a `timezone` argument to read them in another zone. Post growth (the `get_post` milestones and `compare_post_growth`) comes from the metrics each sync records during a post's first 30 days — every 15 minutes at most in the first hours, daily by the end. Recording starts with the version that added it, so posts published earlier have no growth data, and the more often you sync, the finer each post's early curve. ### Prompts The server also registers ready-made prompts. Most take an optional `period` argument (e.g. `30d`, `90d`, or a date range); `monthly-review` takes a `month` (`YYYY-MM`) and, optionally, the `previous_experiments` from last month's review: | Prompt | What it produces | | ---------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `performance-review` | A full performance report: trends, best/worst posts, and actions to improve | | `content-strategy` | Which formats, lengths, and topics work, with a recommended content mix | | `posting-schedule` | A concrete weekly posting schedule based on when your audience engages | | `viral-post-breakdown` | Deep-dive of outlier posts and the repeatable patterns behind them | | `audience-insights` | Follower growth and demographics, and what they imply for content and timing | | `topic-analysis` | Which topics and writing patterns drive performance, plus new post ideas | | `monthly-review` | A monthly review that scores last month's experiments and sets three new ones; the experiments stay on your side (e.g. `threads-reviews/YYYY-MM.md`), so nothing is written to the server | --- ## Deployment The [self-host guide](https://threads-analytics.app/en/deploy/self-host) on the website walks through all of this step by step: Docker Compose, Docker, running from source, Vercel cron, environment variables, auto-sync, and updates. ### Docker Compose [`docker-compose.yml`](./docker-compose.yml) runs the dashboard next to its own PostgreSQL, so you don't need a database first. In an empty folder, download it and write a `.env` file beside it: ```bash curl -fsSLO https://raw.githubusercontent.com/ridemountainpig/threads-analytics/main/docker-compose.yml cat > .env <` on every cron request, and the `/api/cron/sync` route uses it to verify the call is legitimate. ### Auto-sync On long-running deployments (Docker / VPS / Railway), set `SYNC_SCHEDULER_ENABLED=true` — the Docker Compose file already does. The built-in scheduler starts with the server and syncs every connected account — not only the active one — at the interval configured in Settings. On Vercel, use the cron setup above instead. ### Updating an existing deployment New versions ship as updated Docker images, and deployments running the published image show an update banner in the dashboard when one is available. Database migrations run automatically on startup, so updating only requires getting the new image or code: - **Docker Compose** — in the folder with `docker-compose.yml`: ```bash docker compose pull docker compose up -d ``` - **Docker / VPS** — pull the latest image, then stop the old container and start a new one with the same flags: ```bash docker pull ghcr.io/ridemountainpig/threads-analytics:latest ``` - **Railway** — trigger a redeploy of the service from the Railway dashboard. - **From source** — `git pull`, then `pnpm install && pnpm prisma:generate && pnpm build` and restart with `pnpm start` (runs migrations automatically). - **Vercel** — push the new version; migrations run at build time as described above. Releases are also tagged with their version, such as `1.0.0`, plus `1.0` and `1` for the newest release in that line, so Docker and Docker Compose deployments can pin one instead of `latest` (in Compose, edit the `image:` line). [GitHub Releases](https://github.com/ridemountainpig/threads-analytics/releases) lists what changed in each. Your database (posts, insights, accounts) is preserved across updates. --- ## Development Requirements: Node.js 22.12+ or 24+, pnpm, and a PostgreSQL database. ### 1. Clone and install ```bash git clone https://github.com/ridemountainpig/threads-analytics.git cd threads-analytics pnpm install pnpm prisma:generate ``` ### 2. Set up environment variables ```bash cp .env.example .env.local ``` Then fill in the values: | Variable | Description | How to generate | | ------------------------ | --------------------------------------------- | ---------------------- | | `APP_PASSWORD` | Password to access the dashboard | Choose any string | | `DATABASE_URL` | PostgreSQL connection string | From your DB provider | | `TOKEN_ENCRYPTION_KEY` | Encrypts stored Threads access tokens at rest | `openssl rand -hex 32` | | `CRON_SECRET` | Secures `/api/cron/sync` in production | Random 16+ chars | | `SYNC_SCHEDULER_ENABLED` | Enables the built-in polling scheduler | `true` for Docker/VPS | ### 3. Run database migrations ```bash npx prisma migrate dev ``` ### 4. Start the dev server ```bash pnpm dev ``` Open [http://localhost:3000](http://localhost:3000) and sign in with your `APP_PASSWORD`. ### 5. Connect a Threads account 1. Go to **Settings** in the sidebar 2. Click **Add Threads account** 3. Paste your long-lived Threads access token (see [Getting Your Access Token](#getting-your-threads-access-token)) 4. The first sync starts automatically and may take a few minutes ### Useful commands ```bash pnpm dev # Start development server pnpm build # Build for production pnpm start # Run migrations and start production server npx prisma studio # Open database GUI npx prisma migrate dev --name # Create a new migration ``` --- ## Analytics Reference The dashboard ships 31 charts across the Overview, Analytics (Performance / Content / Audience), and Posts pages. Browse them with demo data on the [website](https://threads-analytics.app/en/analytics); what every chart shows — and the sampling rules behind the audience metrics — is documented in the **[Analytics Reference](./docs/analytics.md)**. --- ## License Threads Analytics is open source under the [GNU Affero General Public License v3.0](./LICENSE). You are free to self-host, modify, and redistribute it — but if you run a modified version as a network service, you must make its source code available under the same license.