Skip to main content
Hayon collects analytics automatically after each post is published. Metrics are fetched from each platform’s API by a background worker and stored as point-in-time snapshots, giving you a historical view of how your content performs over time.

Analytics overview

The Analytics page at /analytics is the central hub for performance data. It aggregates metrics across all connected platforms into a single dashboard.

Overview

Total reach, engagement, follower counts, and best-performing platform for the selected period.

Timeline

Day-by-day engagement metrics charted over 7 or 30 days, with optional platform filtering.

Growth

Follower count changes over time, broken down per platform.

Top posts

Your highest-performing posts ranked by engagement, reach, or likes.

Platform performance

Side-by-side comparison of engagement totals across all platforms.

Heatmap

A day-of-week / hour-of-day grid showing when your audience is most active.

Period filter

All analytics endpoints accept a period query parameter:
ValueDescription
7dLast 7 days.
30d (default)Last 30 days.
The backend derives start and end timestamps from this value and passes them to the repository layer for aggregation.

API endpoints

Overview

GET /api/analytics/overview Returns aggregated stats for the period: total posts, total engagement, best platform, total and per-platform follower counts.
curl -X GET "https://api.yourhayon.com/api/analytics/overview?period=7d" \
  -H "Authorization: Bearer <token>"
200 response
{
  "data": {
    "stats": {
      "bestPlatform": "bluesky"
    },
    "followers": {
      "total": 3420,
      "breakdown": {
        "bluesky": 1850,
        "mastodon": 1570
      }
    },
    "platformPerformance": [
      { "_id": "bluesky", "totalEngagement": 312, "totalPosts": 14 }
    ],
    "period": {
      "start": "2026-03-15T00:00:00.000Z",
      "end": "2026-03-22T00:00:00.000Z"
    }
  }
}

Timeline

GET /api/analytics/timeline Returns daily engagement data for chart rendering. Optionally filtered by platform.
curl -X GET "https://api.yourhayon.com/api/analytics/timeline?period=30d&platform=bluesky" \
  -H "Authorization: Bearer <token>"

Growth

GET /api/analytics/growth Returns follower count snapshots over time, useful for plotting a growth curve.
curl -X GET "https://api.yourhayon.com/api/analytics/growth?period=30d" \
  -H "Authorization: Bearer <token>"

Top posts

GET /api/analytics/posts/top Returns your best-performing posts. Supports limit, sortBy, and platform query parameters.
ParameterDefaultDescription
limit5Number of posts to return.
sortBytotalEngagementMetric to rank by.
platformFilter to a single platform.
curl -X GET "https://api.yourhayon.com/api/analytics/posts/top?limit=10&sortBy=totalEngagement" \
  -H "Authorization: Bearer <token>"

Platform performance

GET /api/analytics/platforms Returns per-platform engagement totals and post counts for the selected period, sorted by total engagement descending. The first entry in the array is used as bestPlatform in the overview.
curl -X GET "https://api.yourhayon.com/api/analytics/platforms?period=30d" \
  -H "Authorization: Bearer <token>"

Heatmap

GET /api/analytics/heatmap Returns a grid of engagement values indexed by day-of-week and hour-of-day. Use this to identify the optimal time windows for your audience.
curl -X GET "https://api.yourhayon.com/api/analytics/heatmap?period=30d" \
  -H "Authorization: Bearer <token>"

Manual analytics refresh

You can trigger an on-demand analytics fetch for a specific post and platform: POST /api/analytics/posts/:postId/refresh?platform=<platform>
curl -X POST "https://api.yourhayon.com/api/analytics/posts/664f1a2b3c4d5e6f7a8b9c0d/refresh?platform=bluesky" \
  -H "Authorization: Bearer <token>"
This endpoint:
  1. Verifies you own the post.
  2. Sends a { type: "post", postId, platform } message to the analytics queue.
  3. Waits approximately 5 seconds for the worker to complete.
  4. Returns the latest analytics snapshot.
This endpoint is rate-limited to 1 request per 15 minutes per user (enforced by rateLimiter("analytics_refresh", 1, 900)). Exceeding this returns a 429 response.

How analytics are collected automatically

Hayon runs a background cron job that periodically enqueues analytics fetch tasks for recently published posts. The AnalyticsWorker processes these messages and stores snapshots in MongoDB.
1

Cron job triggers

A scheduler enqueues { type: "post", postId, platform } messages for all recently published posts and { type: "account", userId, platforms } messages for follower counts.
2

Worker picks up the message

AnalyticsWorker.processMessage() reads the message type and routes to processPostAnalytics or processAccountAnalytics.
3

Platform API is called

The worker fetches the platformPostId from the post’s platformStatuses, then calls the platform-specific analytics service (getAnalyticsService(platform)) to retrieve live metrics.
4

Snapshot is saved

A new snapshot document is written to MongoDB with the following metrics:
MetricDescription
likesLike/heart count.
sharesReposts, retweets, or boosts.
commentsReply count.
impressionsTimes the post was displayed.
reachUnique accounts that saw the post.
savedTimes the post was saved/bookmarked.
totalEngagementlikes + shares + comments (derived).
engagementRatetotalEngagement / followerCount (derived).
viralityshares / totalEngagement when shares > 0 (derived).
followerCountAtSnapshotFollower count at the time of the fetch.
5

Cache is invalidated

All analytics-related Redis cache keys for the user are invalidated so the next API request fetches fresh aggregated data:
Cache keys invalidated (analytics.worker.ts)
invalidateCache(`analytics:overview:${userId}`);
invalidateCache(`analytics:timeline:${userId}`);
invalidateCache(`analytics:platforms:${userId}`);
invalidateCache(`analytics:top-posts:${userId}`);
invalidateCache(`analytics:growth:${userId}`);
invalidateCache(`analytics:heatmap:${userId}`);

Error handling

The analytics worker handles two special error types from platform APIs:
If the platform returns a DELETED error, the worker marks the platformStatus as deleted and stops processing that post. No further analytics fetches are attempted.
If the platform returns an UNAUTHORIZED error, the worker updates the connected social account’s health status to expired via SocialAccountRepository.updateHealthStatus(). You will see an alert in the Settings page to reconnect the affected account.
For other errors (network issues, temporary API failures), the worker NACKs the message without requeue, routing it to the dead-letter exchange to avoid infinite loops.

Platform support

Not all platforms expose analytics APIs. Support is implemented selectively:
PlatformPost metricsAccount metrics
BlueskyPlannedPlanned
MastodonPartialPartial
InstagramRoadmapRoadmap
FacebookRoadmapRoadmap
ThreadsRoadmapRoadmap
TumblrRoadmapRoadmap
Platforms where analytics are not yet implemented are detected by the worker and silently skipped with a log message. No error is returned to the user.

Build docs developers (and LLMs) love