⚡ XActions
📖 Guides & Reference

📈 History Store & Auto-Snapshots

Time-series account metrics — track followers, engagement, and growth over days, weeks, or months. Competes with Circleboom and SocialBlade.


Overview

The History Store records periodic snapshots of any X/Twitter account's metrics into a local SQLite database (~/.xactions/analytics.db). It supports:

  • Account snapshots — followers, following, tweet count, listed count
  • Tweet snapshots — likes, retweets, replies, quotes, views per tweet
  • Daily engagement roll-ups — engagement rate, impressions, top tweet
  • Auto-snapshots — periodic scraping on a configurable schedule
  • Export — JSON or CSV for external analysis

Available via: CLI, MCP tools, API, Node.js library, and Dashboard.


Quick Start

CLI

# View account history (last 30 days, daily intervals)
unfollowx history elonmusk --days 30 --interval day

# Start auto-snapshotting every 60 minutes
unfollowx snapshot elonmusk --interval 60

# Export history as CSV
unfollowx history elonmusk --export --format csv

MCP (AI Agents)

Tool: x_history_get
Args: { "username": "elonmusk", "days": 30 }

Tool: x_history_snapshot
Args: { "username": "elonmusk" }

Tool: x_growth_rate
Args: { "username": "elonmusk", "days": 7 }

Tool: x_compare_accounts
Args: { "usernames": ["elonmusk", "jack"], "metric": "followers_count" }

Node.js

import {
  saveAccountSnapshot,
  getAccountHistory,
  getGrowthRate,
  compareAccounts,
  exportHistory
} from 'xactions/src/analytics/historyStore.js';
import { startAutoSnapshot } from 'xactions/src/analytics/autoSnapshot.js';

// Save a manual snapshot
await saveAccountSnapshot('elonmusk', {
  followers_count: 200000000,
  following_count: 800,
  tweet_count: 35000,
  listed_count: 150000,
  verified: true
});

// Get history
const history = getAccountHistory('elonmusk', {
  from: '2025-01-01',
  to: '2025-02-01',
  interval: 'day'   // 'raw' | 'day' | 'week' | 'month'
});

// Growth rate
const growth = getGrowthRate('elonmusk', 30);
// { totalChange: 500000, avgPerDay: 16667, trend: 'growing', percentChange: 0.25 }

// Compare accounts
const comparison = compareAccounts(['elonmusk', 'jack'], 'followers_count');

// Auto-snapshot every 30 minutes
await startAutoSnapshot('elonmusk', 30);

API

# Get account history
GET /api/analytics/history/elonmusk?days=30&interval=day

# Get growth rate
GET /api/analytics/growth/elonmusk?days=7

# Compare accounts
POST /api/analytics/compare
{ "usernames": ["elonmusk", "jack"], "metric": "followers_count" }

# Export as CSV
GET /api/analytics/export/elonmusk?format=csv

Architecture

src/analytics/
├── historyStore.js    → SQLite time-series storage + queries
├── autoSnapshot.js    → Periodic auto-snapshot scheduler
└── index.js           → Re-exports

api/routes/history.js  → REST API endpoints
dashboard/analytics-dashboard.html → Chart.js visualization

Database Schema

Stored in ~/.xactions/analytics.db (SQLite via better-sqlite3).

Table Purpose Key Columns
account_snapshots Per-account metric time-series username, followers_count, following_count, tweet_count, listed_count, snapshot_at
tweet_snapshots Per-tweet metric time-series tweet_id, username, likes, retweets, replies, quotes, views, snapshot_at
engagement_daily Daily engagement roll-ups username, date, avg_engagement_rate, total_impressions, total_engagements, top_tweet_id

Function Reference

saveAccountSnapshot(username, data)

Inserts a new account metrics data point.

Param Type Description
username string X/Twitter handle
data.followers_count number Follower count
data.following_count number Following count
data.tweet_count number Total tweets
data.listed_count number Lists the account appears on
data.verified boolean Verified status

Returns: { username, snapshot_at }

saveTweetSnapshot(username, tweetId, metrics)

Stores per-tweet metrics for tracking performance over time.

Param Type Description
username string Author's handle
tweetId string Tweet ID
metrics object { likes, retweets, replies, quotes, views, bookmark_count }

saveDailyEngagement(username, stats)

Upserts a daily engagement summary (replaces if same date exists).

getAccountHistory(username, options)

Option Type Default Description
from string ISO date start
to string ISO date end
interval string 'raw' 'raw', 'day', 'week', or 'month'

Returns: Array of snapshot objects.

getTweetHistory(tweetId, options)

Returns metric history for a specific tweet. Supports from and to date filters.

getGrowthRate(username, days)

Param Type Default Description
username string X handle
days number 30 Lookback period

Returns: { username, days, dataPoints, totalChange, avgPerDay, trend, percentChange, dailyGrowth }

compareAccounts(usernames, metric, options)

Compares multiple accounts over time on a single metric.

Param Type Default Description
usernames string[] Accounts to compare
metric string 'followers_count' Metric column name

Returns: { metric, usernames, timeSeries, summary }

exportHistory(username, format)

Exports all data for a user as json or csv.


Auto-Snapshot Functions

startAutoSnapshot(username, intervalMinutes, scrapeFn)

Param Type Default Description
username string Account to monitor
intervalMinutes number 60 Snapshot interval
scrapeFn Function null Custom scrape function (auto-uses Puppeteer if null)

stopAutoSnapshot(username)

Stops snapshots for a specific user.

listActiveSnapshots()

Returns all active snapshot schedules: [{ username, intervalMinutes, startedAt }]

stopAllSnapshots()

Graceful shutdown — stops all active schedules. Automatically called on process exit.


MCP Tools

Tool Input Description
x_history_get username, days? Get account history over time
x_history_snapshot username Take an immediate snapshot
x_growth_rate username, days? Calculate follower growth rate
x_compare_accounts usernames[], metric? Compare accounts on a metric

⚡ Free and open source

No API keys, no monthly fees, no signup. Star the repo if it saved you a subscription.

View on GitHub