# X (Twitter) Account Analytics (`guezi/x-account-analytics`) Actor

One analytics row per X (Twitter) account: average and median likes, reposts, replies and views, two engagement rates, posting frequency, best day and hour to post, content mix, top hashtags, mentions and linked sites, plus the five best posts. No X account or login needed.

- **URL**: https://apify.com/guezi/x-account-analytics.md
- **Developed by:** [Kawtar](https://apify.com/guezi) (community)
- **Categories:** Social media
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$80.00 / 1,000 account reports

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## X (Twitter) Account Analytics

Turn any X (Twitter) account into a single, decision-ready analytics row. Give
it a list of accounts and it reads their recent public posts and returns one
report per account: average and median likes, reposts, replies and views, two
separate engagement rates, posting frequency, a full day-of-week and
hour-of-day breakdown, the content mix, the topics and sites the account links
to, and its five best posts by reach and by likes. No X account and no login
needed.

This is the report you would otherwise build by hand in a spreadsheet after
exporting hundreds of posts — except the arithmetic is done honestly, with the
number of posts behind every average stated on the row.

### What you can do with it

- **Benchmark competitors on one screen.** Put twenty accounts in, get twenty
  rows out, sort by engagement rate and see instantly who is actually working.
- **Find the best time to post.** Every report carries a full posting breakdown
  by day of the week and by hour of the day, plus the day and hour where this
  account's own posts earned the most views.
- **Qualify influencers and partners before you pay them.** A large follower
  count with a 0.02% engagement rate tells a very different story from a small
  account at 3%. Both rates are on the row.
- **Track your own account over time.** Schedule a weekly run over your handle
  and watch averages, cadence and content mix move.
- **Brief a content team with evidence.** The content mix (photo/video share,
  link share, reply share, long-post share) plus the top hashtags, mentions and
  linked sites describe an account's strategy in one row.
- **Screen a long list fast.** Analytics for 200 accounts is one run and one
  spreadsheet, not 200 profile visits.

### What you get

One row per account. This is a real row from a run over `OpenAI`, abridged:

```json
{
  "inputProfile": "@OpenAI",
  "userId": "4398626122",
  "username": "OpenAI",
  "displayName": "OpenAI",
  "profileUrl": "https://x.com/OpenAI",
  "followers": 5087026,
  "following": 4,
  "postCount": 2048,
  "verifiedType": "Business",
  "joinedAt": "2015-12-06T22:51:08.000Z",
  "avatarUrl": "https://pbs.twimg.com/profile_images/1885410181409820672/ztsaR0JW.jpg",

  "postsAnalysed": 200,
  "ownPostsAnalysed": 180,
  "repostsAnalysed": 20,
  "dateRangeStart": "2026-04-30T19:08:00.000Z",
  "dateRangeEnd": "2026-08-04T21:05:30.000Z",
  "daysCovered": 96.08,
  "postsPerDay": 2.07,
  "postsPerWeek": 14.5,

  "totalLikes": 783571,
  "avgLikes": 4353.17,
  "medianLikes": 1639,
  "maxLikes": 47565,
  "avgReposts": 424.51,
  "avgReplies": 285.09,
  "avgQuotes": 254.63,
  "avgBookmarks": 985.21,
  "totalViews": 285178226,
  "avgViews": 1584323.48,
  "medianViews": 357408,
  "maxViews": 30967000,

  "totalEngagements": 1134470,
  "avgEngagementsPerPost": 6302.61,
  "engagementRateByViewsPct": 0.3978,
  "engagementRateByFollowersPct": 0.1239,
  "postsWithViewCount": 180,
  "postsWithoutViewCount": 0,
  "metricCoverage": {
    "postsAnalysed": 200, "ownPosts": 180,
    "likes": 180, "reposts": 180, "replies": 180,
    "quotes": 180, "bookmarks": 180, "views": 180,
    "engagementRateByViews": 180, "engagementRateByFollowers": 180,
    "contentShares": 180
  },

  "postsByDayOfWeek": {
    "Monday": 25, "Tuesday": 33, "Wednesday": 53, "Thursday": 57,
    "Friday": 29, "Saturday": 3, "Sunday": 0
  },
  "postsByHourUtc": {
    "00:00": 11, "13:00": 8, "16:00": 15, "17:00": 60,
    "18:00": 17, "19:00": 21, "20:00": 33, "21:00": 15
  },
  "mostActiveDayOfWeek": "Thursday",
  "mostActiveHourUtc": 17,
  "avgViewsByDayOfWeek": { "Monday": 1140741.85, "Tuesday": 1840813.03, "Sunday": null },
  "avgViewsByHourUtc": { "13:00": 2557859.57, "17:00": 1625783.81, "20:00": 1785844.52 },
  "bestDayOfWeekByViews": "Tuesday",
  "bestHourUtcByViews": 13,

  "pctWithMedia": 44.44,
  "pctWithLinks": 24.44,
  "pctQuotes": 4.44,
  "pctLongForm": 39.44,
  "pctReplies": 48,
  "pctReposts": 10,

  "topHashtags": [],
  "topMentions": [
    { "value": "AndrewMayne", "count": 5 },
    { "value": "Broadcom", "count": 2 },
    { "value": "Microsoft", "count": 2 }
  ],
  "topDomains": [
    { "value": "openai.com", "count": 26 },
    { "value": "open.spotify.com", "count": 5 },
    { "value": "podcasts.apple.com", "count": 5 }
  ],
  "languageMix": [ { "value": "en", "count": 174 }, { "value": "zxx", "count": 6 } ],

  "topPostsByViews": [
    {
      "postId": "2079658951264920020",
      "url": "https://x.com/OpenAI/status/2079658951264920020",
      "text": "We're partnering with @huggingface to investigate an unprecedented security incident…",
      "createdAt": "2026-07-21T20:05:06.000Z",
      "likes": 20823,
      "views": 30967000
    }
  ],
  "topPostsByLikes": [
    {
      "postId": "2074704958419792299",
      "url": "https://x.com/OpenAI/status/2074704958419792299",
      "text": "GPT-5.6 Sol, along with Terra and Luna, will launch publicly this Thursday. We’re expanding preview access globally now.",
      "createdAt": "2026-07-08T03:59:42.000Z",
      "likes": 47565,
      "views": 9867332
    }
  ],

  "unavailable": false,
  "scrapedAt": "2026-08-05T22:11:52.062Z"
}
```

### How the numbers are worked out

Three rules decide every figure on the row, and all three exist because the
obvious shortcut produces confidently wrong analytics.

**1. An average is taken only over the posts that actually carry the value.**
X shows a view count on most recent posts and on fewer older ones. Where no
view count is published, this actor leaves the field empty instead of writing a
zero — and the empty ones are left out of `avgViews` and `medianViews` rather
than dragging them down. `postsWithViewCount` and the `metricCoverage` block
tell you exactly how many posts stood behind each average, so you can judge how
much weight the figure deserves.

**2. Figures about content come from the account's own posts.** When an account
reposts somebody else, the likes and replies on that post belong to the
original author, and X reports the repost itself with no likes of its own.
Mixing those in would pull every average toward zero — on a repost-heavy
account it can understate average likes by 40% or more. The same is true of
what a post contained: a repost does not carry the photo, video, link or long
body of the post it passed on, so treating it as "published without a photo"
halves the picture, and on a live account with a third of its feed reposted it
did exactly that.

So `avgLikes`, `avgViews`, the medians, the engagement rates, the topic lists,
the top-post lists and the content shares `pctWithMedia`, `pctWithLinks`,
`pctQuotes` and `pctLongForm` are all built from `ownPostsAnalysed` — the count
is repeated as `metricCoverage.contentShares` so you never have to guess the
denominator. `pctReposts` and `pctReplies` are shares of everything analysed,
because those two are true or false for every entry, and reposts still count in
`postsAnalysed` and in the posting frequency, because the account really did
publish them.

**3. A pinned post does not stretch the window.** Pinning keeps one post at the
top of a profile no matter how old it is. `dateRangeStart`, `dateRangeEnd`,
`daysCovered`, `postsPerDay` and `postsPerWeek` describe the continuous run of
recent posts, so an old pinned post cannot turn a six-week window into a
three-year one. It still counts in the totals and averages.

**The two engagement rates.** Engagements are `likes + reposts + replies +
quotes + bookmarks`.

- `engagementRateByViewsPct` = 100 × (engagements ÷ views), summed across the
  account's own posts **that carry a view count**, with both sides of the
  division taken from those same posts. This answers "of the people who saw a
  post, what share interacted".
- `engagementRateByFollowersPct` = 100 × (`avgEngagementsPerPost` ÷
  `followers`). This answers "how much interaction does a typical post draw,
  relative to the audience this account has built". It is the figure most
  influencer-marketing benchmarks use.

They are deliberately separate numbers and they are not comparable to each
other. Both are percentages, so `0.3978` means 0.3978%.

**Best day and hour.** `mostActiveDayOfWeek` and `mostActiveHourUtc` are where
the account posts most. `bestDayOfWeekByViews` and `bestHourUtcByViews` are
where its own posts averaged the most views, and only time slots holding more
than one post can win — a single lucky post at 3am is not a posting-time
insight. All times are UTC, and the full breakdowns are on the row so you can
convert and re-slice them yourself.

### Input

| Field | Type | Default | What it does |
| --- | --- | --- | --- |
| `profiles` | array of text | — | **Required.** The accounts to report on. An account name, an `@name` or a link to the profile all work. |
| `postsToAnalyse` | integer | `200` | How many recent posts each report is built from. Maximum 2,000. |
| `postedAfter` | text | — | Only analyse posts published on or after this date (`YYYY-MM-DD`). |
| `postedBefore` | text | — | Only analyse posts published on or before this date (`YYYY-MM-DD`). |
| `includeReposts` | boolean | `true` | Count reposts towards posting volume and the content mix. |
| `includeReplies` | boolean | `true` | Count replies. Turn off to report only on standalone posts. |
| `accountsAtOnce` | integer | `3` | How many accounts to work through at the same time. |
| `countryCode` | select | `us` | Which country to browse from. |

### Output fields

| Field | Description |
| --- | --- |
| `username`, `userId`, `displayName`, `profileUrl`, `bio`, `location`, `website`, `joinedAt` | Who the report is about. |
| `followers`, `following`, `postCount`, `isVerified`, `verifiedType`, `hasSubscriptionBadge` | Account size and badges. |
| `avatarUrl`, `bannerUrl`, `pinnedPostId` | Profile imagery and the pinned post. |
| `postsAnalysed`, `ownPostsAnalysed`, `repostsAnalysed` | How much the report is built on. |
| `dateRangeStart`, `dateRangeEnd`, `daysCovered` | The window the report covers. |
| `postsPerDay`, `postsPerWeek` | Publishing cadence across that window. |
| `totalLikes`, `totalReposts`, `totalReplies`, `totalQuotes`, `totalBookmarks`, `totalViews`, `totalEngagements` | Sums over the account's own posts. |
| `avgLikes`, `avgReposts`, `avgReplies`, `avgQuotes`, `avgBookmarks`, `avgViews`, `avgEngagementsPerPost` | Averages over the posts that carry each value. |
| `medianLikes`, `medianViews`, `maxLikes`, `maxViews` | Typical and best-case performance. |
| `engagementRateByViewsPct`, `engagementRateByFollowersPct` | The two rates, as percentages. |
| `metricCoverage`, `postsWithViewCount`, `postsWithoutViewCount` | How many posts stood behind each figure. |
| `postsByDayOfWeek`, `postsByHourUtc` | Full posting breakdown, every slot present. |
| `mostActiveDayOfWeek`, `mostActiveHourUtc` | Where the account posts most. |
| `avgViewsByDayOfWeek`, `avgViewsByHourUtc`, `bestDayOfWeekByViews`, `bestHourUtcByViews` | Where its posts performed best. |
| `pctWithMedia`, `pctWithLinks`, `pctQuotes`, `pctLongForm` | Content mix, as percentages of the account's own posts. |
| `pctReplies`, `pctReposts` | Reply and repost share, as percentages of every analysed post. |
| `topHashtags`, `topMentions`, `topDomains`, `languageMix` | Ranked `{ value, count }` lists. |
| `topPostsByViews`, `topPostsByLikes` | The five best posts on each measure, with link, date and numbers. |
| `unavailable`, `unavailableReason` | Set when an account cannot be reported on, so your input list keeps its shape. |
| `inputProfile`, `scrapedAt` | What you asked for, and when the report was built. |

### Pricing

This actor is **pay per account report**. You are charged once for each report
row that lands in your dataset, whatever the size of the account or the depth
of the analysis. There is no time-based charge and no charge for the individual
posts read to build the report.

An account that turns out to be private, suspended or missing is still returned
as a row so your list keeps its shape, and that row is charged the same as any
other. A weekly competitive sweep over 25 accounts is 25 rows per run.

### Limits & what this actor cannot do

- The report is built from an account's recent public posts, not its whole
  history. Deeper windows make the averages steadier but always describe recent
  behaviour rather than the account's lifetime.
- X publishes a limited window of recent public posts per account, so very
  large accounts return what X makes available rather than a complete history.
- Keyword search across all of X is not part of what X publishes openly. This
  actor works from the accounts you supply rather than a search term.
- Replies written by *other people* underneath a post are not publicly
  available, and neither are the lists of who follows an account. Follower and
  following counts are included.
- Protected (private) accounts are not publicly viewable. They are reported as
  unavailable rather than returned empty, and so are suspended, withheld and
  missing accounts — each with its own reason, so a suspended account is never
  confused with a handle that does not exist.
- Every engagement number is a snapshot at the moment of collection. A post
  keeps accumulating likes and views afterwards, so a report on very fresh
  posts will read lower than the same report a week later.
- X publishes view counts for most recent posts but not for every older one.
  Where X publishes none, the value is left empty rather than set to zero, and
  those posts sit outside `avgViews`, `medianViews` and the view-based
  engagement rate. The row tells you how many posts that was.
- Averages over a handful of posts are noisy. `postsAnalysed` and
  `metricCoverage` are on every row precisely so you can see when a figure is
  thin.
- All day and hour figures are in UTC.
- Speed depends on the size of the job and on X's own response times.
- X's terms govern automated access. You are responsible for using the data
  lawfully, in line with the source site's terms, and for handling any personal
  data in line with applicable privacy law.

### FAQ

**Do I need an X account?**
No. Nothing is required from you beyond the list of accounts you want reported
on.

**Does it need my login, password or a paid X subscription?**
No. None of those are used at any point.

**Can I analyse accounts I do not own?**
Yes — that is the main use. Everything in the report is computed from posts
that are already public on X, so competitor and influencer analysis works
exactly like analysis of your own account.

**Can I schedule it?**
Yes. Schedule it on Apify to run weekly or monthly over the same list and watch
the numbers move.

**Is the data complete?**
The report is complete for the window it covers, and the row states that window
and how many posts stood behind every figure. It is not a lifetime history, and
posts with no published view count are excluded from the view-based figures
rather than counted as zero.

**Why is the engagement rate different from the one my other tool shows?**
Because most tools quietly pick one of two definitions. This actor gives you
both — one against views and one against followers — and states the formula, so
you can match whichever your team already uses.

**How do I get the results into my tools?**
Export from Apify as CSV, Excel, JSON, XML or an HTML table, push into Google
Sheets, or pull them into your own system.

# Actor input Schema

## `profiles` (type: `array`):

The accounts to build a report for. Paste an account name, an @name, or a link to the profile — all three work. One report row is produced per account.

## `postsToAnalyse` (type: `integer`):

How many recent posts each report is built from, newest first. More posts make the averages steadier; fewer make the report focus on the most recent activity.

## `postedAfter` (type: `string`):

Only include posts published on or after this date (YYYY-MM-DD). Leave empty to analyse the most recent posts regardless of date.

## `postedBefore` (type: `string`):

Only include posts published on or before this date (YYYY-MM-DD). Leave empty for no upper bound.

## `includeReposts` (type: `boolean`):

Include posts the account reposted from someone else. They count towards posting volume and the repost share. Engagement averages and the content mix are always built from the account's own posts, because a repost carries neither the numbers nor the photos, links and long text of the post it passed on.

## `includeReplies` (type: `boolean`):

Include posts that are replies to another post. Turn this off to report only on standalone posts.

## `accountsAtOnce` (type: `integer`):

How many accounts to work through in parallel. Raise it for large lists.

## `countryCode` (type: `string`):

The country to browse from. Affects which posts X shows publicly in a few regions.

## Actor input object example

```json
{
  "profiles": [
    "nasa"
  ],
  "postsToAnalyse": 200,
  "postedAfter": "2026-01-01",
  "postedBefore": "2026-12-31",
  "includeReposts": true,
  "includeReplies": true,
  "accountsAtOnce": 3,
  "countryCode": "us"
}
```

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "profiles": [
        "nasa",
        "@OpenAI",
        "https://x.com/Nike"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("guezi/x-account-analytics").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = { "profiles": [
        "nasa",
        "@OpenAI",
        "https://x.com/Nike",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("guezi/x-account-analytics").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "profiles": [
    "nasa",
    "@OpenAI",
    "https://x.com/Nike"
  ]
}' |
apify call guezi/x-account-analytics --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,guezi/x-account-analytics"
        }
    }
}

```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/6h1fJL6ct3dcfprRB/builds/uZceq1B5p6Xb29bk7/openapi.json
