{"id":49267195,"url":"https://github.com/jdelaire/opensocialdashboard","last_synced_at":"2026-04-25T11:01:17.306Z","repository":{"id":344321754,"uuid":"1180416800","full_name":"jdelaire/opensocialdashboard","owner":"jdelaire","description":"Open-source dashboard for tracking daily follower and subscriber counts from public social profiles without OAuth.","archived":false,"fork":false,"pushed_at":"2026-04-10T01:06:52.000Z","size":201,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-10T03:09:23.843Z","etag":null,"topics":["analytics","follower-tracking","playwright","react","scraping","social-dashboard","social-media","sqlite","subscriber-tracking","typescript"],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jdelaire.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":".github/SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-03-13T02:44:57.000Z","updated_at":"2026-04-10T01:06:56.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/jdelaire/opensocialdashboard","commit_stats":null,"previous_names":["jdelaire/opensocialdashboard"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/jdelaire/opensocialdashboard","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jdelaire%2Fopensocialdashboard","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jdelaire%2Fopensocialdashboard/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jdelaire%2Fopensocialdashboard/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jdelaire%2Fopensocialdashboard/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jdelaire","download_url":"https://codeload.github.com/jdelaire/opensocialdashboard/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jdelaire%2Fopensocialdashboard/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32259472,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-25T09:15:33.318Z","status":"ssl_error","status_checked_at":"2026-04-25T09:15:31.997Z","response_time":59,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["analytics","follower-tracking","playwright","react","scraping","social-dashboard","social-media","sqlite","subscriber-tracking","typescript"],"created_at":"2026-04-25T11:01:16.088Z","updated_at":"2026-04-25T11:01:17.293Z","avatar_url":"https://github.com/jdelaire.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Open Social Dashboard\n\nLocal, self-hosted dashboard that collects daily follower/subscriber snapshots from public profile URLs without OAuth.\n\n## Stack\n- Node.js 20+\n- TypeScript (strict)\n- SQLite (`better-sqlite3`)\n- Playwright (fallback extraction)\n- Express API + Vite/React UI\n\n## Setup\n1. Install dependencies:\n   ```bash\n   npm install\n   ```\n2. Create your local accounts file and edit the targets:\n   ```bash\n   cp config/accounts.json.example config/accounts.json\n   ```\n3. Run one collection:\n   ```bash\n   npm run collect\n   ```\n4. Print a CLI summary of metrics across all accounts:\n   ```bash\n   npm run summary\n   ```\n   Output format is chat-friendly lines: `Account - Followers - Trend`.\n5. Start dashboard + API:\n   ```bash\n   npm run dev\n   ```\n6. Open `http://localhost:5173`.\n\nBy default dev mode uses `APP_API_PORT=8790` for API + Vite proxy consistency.\n\n## Accounts Config\n`config/accounts.json` contains:\n- `id` string (stable id)\n- `platform` (`instagram` | `tiktok` | `rednote` | `youtube` | `x`)\n- `label` string\n- `url` string\n- `enabled` boolean\n- `auth_profile_source_path` optional string path to a Chromium user-data directory to seed a dashboard-local Playwright profile copy. Use it for platforms that need an authenticated session in Playwright, such as RedNote or Instagram when Meta serves a login wall.\n- `manual_followers` optional integer to bypass collection and store an exact follower count manually for that account.\n\nUse `config/accounts.json.example` as the committed template and keep your real `config/accounts.json` local-only.\n\n## Collector Behavior\n- Attempts fast HTML extraction first (10s timeout).\n- Falls back to Playwright extraction when HTML fails (20s navigation timeout).\n- If `manual_followers` is set for an account, the collector skips scraping and records that exact value with `method=manual`.\n- Retries Playwright once for transient errors.\n- Writes exactly one snapshot per account per Bangkok day (`UNIQUE(account_id, date)` with upsert).\n- Detects block/captcha pages and records failed status with `error_code=captcha`.\n- Preserves lower-bound public counts (for example RedNote `1万+`) as `\u003e=` values instead of dropping them entirely.\n- When an account defines `auth_profile_source_path`, the collector seeds a one-time local copy under `data/playwright-profiles/\u003caccount-id\u003e` and uses that copied profile for Playwright collection.\n- If that copied authenticated session stops yielding exact follower data, collection records `error_code=auth_required` so the dashboard can signal that the local profile needs to be refreshed.\n- To reseed an auth profile copy, close the source browser/profile first, then delete `data/playwright-profiles/\u003caccount-id\u003e` and rerun collection.\n- Keeps deltas and growth rates conservative: they only compute when both snapshots are exact counts.\n- API process includes an in-process auto-collector loop (every 24h) while running.\n- Auto-collector can be configured with:\n  - `AUTO_COLLECT_DISABLED=1` to disable\n  - `AUTO_COLLECT_INTERVAL_HOURS=24` to change interval (max 168)\n\n## API\n- `GET /api/accounts`\n- `GET /api/accounts/:id/snapshots?days=365`\n- `POST /api/collect/run`\n\n## Cron Examples (09:00 Asia/Bangkok)\nSet `TZ=Asia/Bangkok` inside cron command so date bucketing matches collector logic.\nUse cron if you want fixed wall-clock scheduling; the in-process loop runs every N hours from server start.\n\n### macOS\n```cron\n0 9 * * * cd /Users/you/Projects/social-dashboard \u0026\u0026 TZ=Asia/Bangkok /usr/local/bin/node /Users/you/Projects/social-dashboard/node_modules/.bin/tsx /Users/you/Projects/social-dashboard/collector/run.ts \u003e\u003e /Users/you/Projects/social-dashboard/collector.log 2\u003e\u00261\n```\n\n### Linux\n```cron\n0 9 * * * cd /home/you/social-dashboard \u0026\u0026 TZ=Asia/Bangkok /usr/bin/node /home/you/social-dashboard/node_modules/.bin/tsx /home/you/social-dashboard/collector/run.ts \u003e\u003e /home/you/social-dashboard/collector.log 2\u003e\u00261\n```\n\n## Troubleshooting\n- `Failed to load: API returned 404` in UI:\n  - Usually means `/api` is proxying to a different service on your machine.\n  - Check that local API is running at `http://localhost:8790/api/health`.\n  - If port conflict exists, set a custom API port for both processes:\n    ```bash\n    APP_API_PORT=8890 npm run dev\n    ```\n- `captcha` failures: platform is showing bot checks; collection stores failed snapshots by design.\n- `extract_failed`: selectors/text patterns did not produce a confident count; connector needs tuning.\n- `auth_required`: the platform served a login wall or the copied authenticated browser profile is no longer usable; refresh or reseed the local profile copy.\n- `playwright_failed`: install browser binaries:\n  ```bash\n  npx playwright install chromium\n  ```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjdelaire%2Fopensocialdashboard","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjdelaire%2Fopensocialdashboard","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjdelaire%2Fopensocialdashboard/lists"}