Table of Contents
- Features
- macOS Desktop App
- Quick Start
- Getting Your Threads Access Token
- MCP Server
- Deployment
- Development
- Analytics Reference
- 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_PASSWORDenv var) - English / 繁體中文 / 日本語 UI, with light, dark, and Auto appearance
macOS Desktop App
Macs with Apple silicon (M1 or later) can download the desktop app directly from GitHub Releases, with no need to install Node.js, pnpm, or PostgreSQL. An Intel Mac build is not currently available.
See the Mac app guide for download, first launch, update, and uninstall instructions.
To build the desktop app from source, see the desktop README.
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:
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 · Vercel
Already have a server? 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).
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.
Getting Your Threads Access Token
- Go to developers.facebook.com and create an app with the Access the Threads API use case
- Generate an Access Token
- In the dashboard: Settings → Add Threads Account → paste token
For a screenshot-based walkthrough, see How to Generate a Threads Access Token.
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 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
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
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:
Deployment
The self-host guide 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 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:
curl -fsSLO https://raw.githubusercontent.com/ridemountainpig/threads-analytics/main/docker-compose.yml
cat > .env <<EOF
APP_PASSWORD=$(openssl rand -hex 12)
TOKEN_ENCRYPTION_KEY=$(openssl rand -hex 32)
POSTGRES_PASSWORD=$(openssl rand -hex 16)
EOF
grep APP_PASSWORD .env
docker compose up -d
Save the APP_PASSWORD that grep prints; it's the password you sign in with. To pick your own, edit .env and run docker compose up -d again. Compose waits for the database, runs migrations, and serves the dashboard on port 3000 with the sync scheduler on; DATABASE_URL and SYNC_SCHEDULER_ENABLED are set for you. Any other variable in .env (such as CRON_SECRET) is passed to the app too.
Data lives in the postgres-data volume, which survives restarts and updates. PostgreSQL only reads POSTGRES_PASSWORD when it first creates that volume, so keep the value you started with — and note that docker compose down -v deletes the volume along with every synced post.
Docker
To run only the app container against a PostgreSQL you already have, use the prebuilt multi-arch (amd64/arm64) image on GitHub Container Registry. Set the environment variables, then run:
docker run -p 3000:3000 --env-file .env.local ghcr.io/ridemountainpig/threads-analytics:latest
Or build the image from source yourself:
docker build -t threads-analytics .
docker run -p 3000:3000 --env-file .env.local threads-analytics
The Docker image runs prisma migrate deploy automatically on startup.
Vercel
Import the repository into Vercel and set the environment variables. The vercel-build script (prisma generate && prisma migrate deploy && next build) generates the Prisma client and runs migrations at build time; Vercel prefers it over build when present.
Vercel does not support long-running processes, so the built-in sync scheduler cannot run there. Use Vercel Cron Jobs to call /api/cron/sync on a schedule instead:
-
Add a
vercel.jsonto the project root:{ "crons": [ { "path": "/api/cron/sync", "schedule": "0 * * * *" } ] }Adjust
scheduleto match the sync interval you set in Settings (e.g.0 * * * *for every hour,*/30 * * * *for every 30 minutes). Note that Vercel's free plan limits cron frequency. -
In the Vercel dashboard go to Settings → Environment Variables and add:
Vercel automatically injects this value as
Authorization: Bearer <CRON_SECRET>on every cron request, and the/api/cron/syncroute 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: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:
docker pull ghcr.io/ridemountainpig/threads-analytics:latest -
Railway — trigger a redeploy of the service from the Railway dashboard.
-
From source —
git pull, thenpnpm install && pnpm prisma:generate && pnpm buildand restart withpnpm 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 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
git clone https://github.com/ridemountainpig/threads-analytics.git
cd threads-analytics
pnpm install
pnpm prisma:generate
2. Set up environment variables
cp .env.example .env.local
Then fill in the values:
3. Run database migrations
npx prisma migrate dev
4. Start the dev server
pnpm dev
Open http://localhost:3000 and sign in with your APP_PASSWORD.
5. Connect a Threads account
- Go to Settings in the sidebar
- Click Add Threads account
- Paste your long-lived Threads access token (see Getting Your Access Token)
- The first sync starts automatically and may take a few minutes
Useful commands
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 <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; what every chart shows — and the sampling rules behind the audience metrics — is documented in the Analytics Reference.
License
Threads Analytics is open source under the GNU Affero General Public License v3.0. 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.