Pull engagement metrics into your own dashboard
Collect publication events, poll platform metrics, and backfill a table you control.
Who it's for
Developers building an internal reporting dashboard or a creator's personal analytics view.
What you'll have
A table of post URLs, publication times and engagement, backed by the latest metrics and historical snapshots.
Before you start
- An active ThreadMaster subscription and a key from Settings → Developer API; set THREADMASTER_API_KEY in your environment.
- Python 3 with requests installed (python -m pip install requests). Run each recipe's Python blocks in order in the same script.
- Published posts, publish:read and webhooks:manage scopes, an HTTPS receiver and durable storage.
- A daily job runner and the signature verification function linked below for your webhook receiver.
Build the workflow
Subscribe to publication events
Register once and save the one-time signing secret securely. Use the linked verifier on raw webhook bytes before accepting any event.
import os import requests BASE = "https://threadmaster.ai/api/public/v1" session = requests.Session() session.headers.update({"Authorization": "Bearer " + os.environ["THREADMASTER_API_KEY"]}) def api(method, path, **kwargs): response = session.request(method, BASE + path, timeout=90, **kwargs) response.raise_for_status() return response.json() webhook = api("POST", "/webhooks/", json={ "url": "https://your-site.example/metrics-events", "events": ["post.published"], "description": "Dashboard publication inbox" }) # Store webhook["secret"] securely for verification. print(webhook["endpoint"]["id"])Store each platform, job id and permalink
Verify the signature, save and queue the event, then acknowledge promptly so processing can happen in a worker. Save or update one record per (platform, job_id) to avoid duplicates, using published_at for the job's completed_at.
def publication_record(event): if event["type"] != "post.published": return None job = event["data"] return { "platform": job["platform"], "job_id": job["id"], "permalink": job["permalink"], "published_at": job["completed_at"] } # Your worker: upsert publication_record(verified_event) in durable storage.Fetch latest metrics and snapshots daily
Each day, load saved publication records and fetch metrics from each platform's endpoint. Save latest for the dashboard and snapshots for trends, keeping one snapshot per post and capture time to avoid duplicates.
def fetch_metrics(record): job_id = record["job_id"] paths = { "x": f"/x/posts/{job_id}/metrics/", "threads": f"/threads-app/posts/{job_id}/metrics/", "facebook": f"/facebook/posts/{job_id}/metrics/", } metrics = api("GET", paths[record["platform"]]) return metrics["latest"], metrics["snapshots"] # Daily runner: load records, fetch_metrics(record), then persist the results.Shape a table without inventing metrics
Build shared columns for platform, post, published_at, likes, impressions/views and replies, with separate Facebook reactions and comments. Leave unsupported Facebook metrics empty and preserve None as missing data so the table does not imply zero engagement.
def dashboard_row(record, latest): platform = record["platform"] return { "platform": platform, "post": record["permalink"], "published_at": record["published_at"], "likes": latest.get("likes"), "impressions/views": latest.get("impressions" if platform == "x" else "views"), "replies": latest.get("replies"), "reactions": latest.get("reactions"), "comments": latest.get("comments"), }Backfill older X posts with a cursor
Choose a since timestamp and follow every page of GET /x/posts/?since= to collect older completed jobs. Replace print with storage that saves or updates records using the same platform/job-id key as live events, avoiding duplicates.
params = {"since": "2026-01-01T00:00:00Z", "limit": 200} while True: page = api("GET", "/x/posts/", params=params) for job in page["data"]: if job["status"] == "posted": print(publication_record({"type": "post.published", "data": job})) if not page["has_more"]: break params["cursor"] = page["next_cursor"]
Use the documented Python or Node signature verification snippet in your receiver.
Watch out for
- X metrics: likes, impressions, replies, retweets, quotes and bookmarks. Threads metrics: views, likes, replies, reposts, quotes and shares.
- Facebook metrics: reactions, comments and shares. Facebook has no impressions metric; reactions are not a likes count.
- Budget daily polling and backfills against the shared per-key request allowance. Check the linked rate limits and X-RateLimit-Remaining; space requests to respect burst limits too.
Check the API rate limits and quotas before running your workflow at scale.
Write your next Twitter thread or LinkedIn post today
Sign up in under a minute. $9 a month, cancel anytime.