A self-hosted Threads analytics dashboard. Connect your access token and explore post performance with detailed charts and metrics.
- Quick Start
- Features
- Requirements
- Development
- Getting Your Threads Access Token
- Analytics Reference
- Deployment
git clone https://github.com/ridemountainpig/threads-analytics.git
cd threads-analytics
pnpm install
cp .env.example .env.local # or create .env.local manually
npx prisma migrate dev --name init
pnpm devOpen http://localhost:3000 and sign in with APP_PASSWORD.
- Overview — stat cards (views, likes, replies, reposts, quotes, shares, engagement rate) with period-over-period delta, daily views chart, best posting hour recommendation, viral posts
- Analytics — 15+ charts across Performance and Content tabs
- Posts — searchable, filterable list with per-post analytics panel
- Multi-account support with account switching
- Auto-sync on configurable intervals
- Password-protected (single
APP_PASSWORDenv var) - English / 繁體中文 / 日本語 UI
- Node.js 20.9+
- pnpm
- PostgreSQL database
git clone https://github.com/ridemountainpig/threads-analytics.git
cd threads-analytics
pnpm installCreate a .env.local file in the project root:
APP_PASSWORD=your_dashboard_password
DATABASE_URL=postgresql://... # PostgreSQL connection string
TOKEN_ENCRYPTION_KEY= # openssl rand -hex 32
CRON_SECRET= # optional, secures /api/cron/sync in production
SYNC_SCHEDULER_ENABLED=false # set true only on long-running deployments| 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 |
npx prisma migrate dev --name initpnpm devOpen http://localhost:3000 and sign in with your APP_PASSWORD.
- Go to Settings in the sidebar
- Click Add Threads account
- Paste your long-lived Threads access token (see Getting Your Access Token)
- Click Sync to fetch your posts and insights
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- Go to developers.facebook.com and create an app with the Threads product
- Generate an Access Token
- In the dashboard: Settings → Add Threads Account → paste token
Tokens are valid for 60 days. The dashboard shows an expiry warning when your token is within 30 days of expiring.
| Section | What it shows |
|---|---|
| Stat Cards | Total views, likes, replies, reposts, quotes, shares, and engagement rate for the selected period. Each card shows a +/−% delta vs the previous period of the same length. |
| Best Hours | Top 2–3 posting hours ranked by median views, with a confidence indicator based on sample size. |
| Daily Views | Daily view counts with a 7-day rolling average and your personal median as a baseline. |
| Top Posts | Posts that exceeded the median view count, ranked by their multiplier (e.g. 3.2× median). |
| Chart | What it shows |
|---|---|
| Overall Performance | Combined daily views, post count, and average views per post on one timeline. |
| Post Quality Map | Scatter plot of every post by reach (views) vs. engagement rate. Dot size = shares. Four quadrants: Breakout, Conversation, Broadcast, Underperforming. |
| Views to Actions Funnel | Conversion rate from total views into each action type (likes, replies, reposts, quotes, shares). |
| Best Time to Post | Heatmap of median views by hour of day. Tooltip shows sample count and confidence level. |
| Engagement Rate Trend | Daily engagement rate (interactions ÷ views) with a 7-day smoothed average. |
| Best Day of Week | Median views, engagement rate, and post count by weekday. |
| Format × Length Matrix | 2-D heatmap comparing every combination of content format and post length against your median reach. |
| Engagement Type Breakdown | Pie chart of the proportion of likes, replies, reposts, quotes, and shares. |
| Engagement Breakdown | Stacked daily chart of likes, replies, reposts, and quotes over time. |
Stat metrics at the top of the tab: Posting Consistency (% of weeks with at least one post), Share Rate, Quote Ratio (quotes ÷ (quotes + reposts)), Total Posts, Longest Streak, and Current Streak.
| Chart | What it shows |
|---|---|
| Posting Activity | Calendar heatmap showing how many posts you published each day. |
| Content Type Performance | Median views, engagement rate, and share rate by media type (Text, Image, Video, Carousel, Audio). Low-sample buckets are faded. |
| Post Length Analysis | Median views broken down by character-count bucket. Tooltip includes average, P75, hit rate, and confidence. |
| Publishing Frequency vs Performance | Whether posting more in a given week raises or lowers per-post average views. |
| Shares Trend | Daily share counts over time. |
| Top Keywords by Engagement | Words (excluding hashtags) with the highest average engagement rate (minimum 3 posts). |
| Optimal Posting Frequency | Per-post reach and engagement compared across different weekly posting volumes. |
| Content Type by Time Slot | Best posting hour for each content format based on median views. |
| Top by Engagement Rate | Highest-engagement posts ranked by (likes + replies + reposts + quotes) ÷ views. |
| Reply-Rate Leaders | Posts ranked by replies ÷ views — your best conversation starters. |
The posts list supports:
- Sort by date, views, or likes
- Search full-text across post content
- Filter by media type (shows only types present in the current period)
Clicking any post opens a detail panel with views, engagement rate, vs-median multiplier, view percentile, and a per-action engagement breakdown.
Set SYNC_SCHEDULER_ENABLED=true in your environment variables. The built-in scheduler starts with the server and syncs at the interval configured in Settings.
Vercel does not support long-running processes. 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 schedule to 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:
| Variable | Value |
|---|---|
CRON_SECRET |
A random secret — generate with openssl rand -hex 32 |
Vercel automatically injects this value as Authorization: Bearer <CRON_SECRET> on every cron request, and the /api/cron/sync route uses it to verify the call is legitimate.
Set all environment variables, then run:
docker build -t threads-analytics .
docker run -p 3000:3000 --env-file .env.local threads-analyticsThe Docker image runs prisma migrate deploy automatically on startup.
