# X Tweet Viral Score Analyzer with AI | $0.0003/Tweet (`xquik/x-tweet-viral-score-analyzer`) Actor

Check any tweet's viral score with AI, AI costs included. See why tweets go viral or flop, with every score beside real engagement, from $0.0003 per analyzed tweet on every Apify plan. World's fastest & cheapest X (Twitter) scraper service. Not affiliated with X Corp.

- **URL**: https://apify.com/xquik/x-tweet-viral-score-analyzer.md
- **Developed by:** [Xquik](https://apify.com/xquik) (community)
- **Categories:** Social media, AI, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 1 bookmarks
- **User rating**: 5.00 out of 5 stars

## Pricing

from $0.0003 / analyzed tweet

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.

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

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
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.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## 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.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

<p align="center">
  <strong>English</strong> ·
  <a href="https://github.com/Xquik-dev/x-twitter-scraper/blob/master/apify/x-tweet-viral-score-analyzer/README.es.md">Español</a> ·
  <a href="https://github.com/Xquik-dev/x-twitter-scraper/blob/master/apify/x-tweet-viral-score-analyzer/README.tr.md">Türkçe</a> ·
  <a href="https://github.com/Xquik-dev/x-twitter-scraper/blob/master/apify/x-tweet-viral-score-analyzer/README.zh-CN.md">简体中文</a> ·
  <a href="https://github.com/Xquik-dev/x-twitter-scraper/blob/master/apify/x-tweet-viral-score-analyzer/README.ja.md">日本語</a> ·
  <a href="https://github.com/Xquik-dev/x-twitter-scraper/blob/master/apify/x-tweet-viral-score-analyzer/README.ko.md">한국어</a> ·
  <a href="https://github.com/Xquik-dev/x-twitter-scraper/blob/master/apify/x-tweet-viral-score-analyzer/README.de.md">Deutsch</a> ·
  <a href="https://github.com/Xquik-dev/x-twitter-scraper/blob/master/apify/x-tweet-viral-score-analyzer/README.fr.md">Français</a> ·
  <a href="https://github.com/Xquik-dev/x-twitter-scraper/blob/master/apify/x-tweet-viral-score-analyzer/README.it.md">Italiano</a>
</p>

<table align="center"><tr><td align="center">
<a href="https://youtu.be/4UOSpoOoC3Y?t=367"><img src="https://img.youtube.com/vi/4UOSpoOoC3Y/maxresdefault.jpg" width="720" alt="Framer connects Xquik MCP to coding agents"></a><br>
<a href="https://youtu.be/4UOSpoOoC3Y?t=367">Watch how Framer uses Xquik scrapers with Claude Code, Codex, Cursor, and more, from 6:07.</a>
</td></tr></table>

Xquik is the world's fastest & cheapest X (Twitter) scraper service with the
most complete X data. X Tweet Viral Score Analyzer adds a Viral Score estimate &
a verdict to every tweet. Every other Apify Actor charges before filtering or
deduplicating. Xquik charges only for delivered, unique, filter-matching
results. AI costs are included in the per-tweet price. You pay no AI provider,
buy no tokens & bring no key.

Learn why tweets spread or flop & keep the original tweet data. **X Tweet Viral
Score Analyzer with AI** collects matching tweets. The AI rates 8 traits of each
post. The Actor turns those answers into a Viral Score estimate from 0 to 100 &
a verdict. Every row keeps real likes, reposts, replies & quotes, so you can
compare each estimate with what happened.

- **Viral Score per post** from fixed, published weights you can audit.
- **8 trait answers** show why a post scored high or low.
- **Hard stops** cap posts that read as spam, ragebait or generic machine copy.
- **Complete source records** with every field the tweet exposes.

The Viral Score is an estimate of how well the wording works. It does not
predict likes or views. It does not reproduce how X ranks posts.

### How to check a tweet's viral score

1. Add search terms, profile handles, tweet URLs or tweet IDs.
2. Set `maxItems` & the extraction filters your task needs.
3. Describe your audience in `analysis.context`, or leave the default.
4. Run the Actor & open the `Viral Score` dataset view.

```json
{
  "searchTerms": ["from:NASA -filter:replies -filter:retweets"],
  "maxItems": 150,
  "analysis": { "context": "Space fans & general readers." }
}
```

#### What the Actor answers

| Question    | Answer                                                    |
| ----------- | --------------------------------------------------------- |
| Hook        | 0 no hook, 1 clear opening, 2 sharp opening               |
| Clarity     | 0 confusing, 1 takes effort, 2 clear on first read        |
| Informative | 0 nothing new, 1 familiar point, 2 useful takeaway        |
| Funny       | 0 not funny, 1 mildly amusing, 2 funny enough to share    |
| Ragebait    | Probability that the post mainly provokes outrage         |
| AI written  | Probability that the text reads like generic machine copy |
| Spam        | Probability of spam, scam, giveaway or engagement farming |
| Reaction    | Share, reply, like, argue or ignore                       |

The AI-written answer judges style only. It does not establish who wrote the
post.

#### How the Actor computes the Viral Score

The Actor scales each 0-2 score to a share from 0 to 1. Then it adds points:

| Part                                      | Points         |
| ----------------------------------------- | -------------- |
| Hook                                      | up to 30       |
| Clarity                                   | up to 20       |
| Payoff, the higher of informative & funny | up to 30       |
| Reaction                                  | up to 20       |
| AI-written probability                    | minus up to 15 |

Reaction earns a share of its 20 points: share 1, reply 0.8, like 0.6, argue 0.4
& ignore 0. Hard stops then cap the score. Spam probability from 0.7 caps it
at 20. Ragebait probability from 0.7 caps it at 35. AI-written probability from
0.8 caps it at 60. The Actor rounds the result to a whole number.

| Verdict       | Score     |
| ------------- | --------- |
| `send_it`     | 70 to 100 |
| `edit_first`  | 40 to 69  |
| `sleep_on_it` | 0 to 39   |

`viral.weights` names the version of these rules, such as `viral_lite:1`. We
bump it whenever a weight, stop or threshold changes. The score is `null` when
the analysis failed, the Actor skipped it, or a default trait answer is missing.
The Actor never fills a missing score with a guess.

### Algorithm Score estimate

X published its ranking weights in the repository `xai-org/x-algorithm`, file
`home-mixer/params/param.rs`. The Actor applies 4 of them to the public counts
of each post:

| Count  | Weight |
| ------ | ------ |
| Like   | 0.5    |
| Reply  | 5      |
| Repost | 1      |
| Quote  | 5      |

`viral.algorithmWeightedSum` is the sum of each count times its weight.
`viral.algorithmScore` divides that sum by views & multiplies by 1,000. A post
without a view count uses followers instead. `viral.algorithmBasis` names the
divisor, `views` or `followers`. Compare scores with the same basis only.
`viral.weightsVersion` names the weights, such as
`x_algorithm_params:2026-09-18`.

Limits:

- X multiplies each weight by a probability it predicts for one viewer. The
  Actor multiplies by observed counts. The result is an estimate, not the score
  X computes.
- X publishes no weight for bookmarks or views. The sum leaves both out.
- X uses more signals than these 4, such as dwell time & shares. Public data
  does not show them.
- The score is `null` when a post has no views & no follower count.
- The AI never sees these counts. It reads the text & context only.

### Predicted against actual

The Actor compares each Viral Score with what happened.
`viral.actualEngagementRate` is `log10(1 + weighted sum per 1,000 followers)`.
The log limits the effect of one very large post. The rate is `null` when the
follower count is missing or 0.

The run summary's `viral.calibration` block reports:

- `comparedPosts`: posts with a Viral Score & an actual rate.
- `rankCorrelation`: a Spearman rank correlation from -1 to 1. It asks whether
  higher scores went with higher rates.
- `calibrationScore`: 100 times the correlation, floored at 0.
- `overperformers` & `underperformers`: up to 5 posts each, with tweet ID, URL,
  Viral Score, actual rate & `gap`.

`gap` is the standardized actual rate minus the standardized Viral Score. A post
enters a list when its gap reaches 1 standard deviation.

Limits:

- Fewer than 10 compared posts give a `null` calibration with the reason
  `too_few_posts`. Identical scores or rates give `no_variation`.
- The Actor groups rates into buckets 0.1 wide to keep memory flat. Posts in one
  bucket count as tied, so the correlation is approximate.
- The calibration describes one run. A low score can mean the posts differ in
  timing, topic or audience, not that the wording estimate failed.
- Young posts have not finished collecting engagement. Compare posts of similar
  age.

### Account report

The run summary's `viral.accounts` block reports each author handle:

- Post count, average Viral Score & average actual engagement rate.
- The best & worst post by Viral Score, with tweet ID & URL.
- Average Viral Score per bucket: posting hour in UTC, text length band, has
  media, has link & self-thread.

Text length bands are `short` to 80 characters, `medium` to 200, `long` to 280 &
`extended` above. A self-thread post replies to its own author.

Limits:

- The report lists the 50 handles with the most scored posts.
- The Actor follows the first 1,000 handles of a run. `untrackedPosts` counts
  scored posts from later handles & posts without a handle.
- A bucket with few posts says little. Check `posts` before you compare
  averages.
- Buckets show what went together in this run. They do not show cause.

### Leaderboard

The run summary's `viral.leaderboard` block ranks the handles of the account
report. `byViralScore` ranks by average Viral Score. `byActualEngagementRate`
ranks by average actual rate. Each list holds up to 20 handles with `rank`,
`posts` & `average`.

Limits:

- A handle needs at least 3 scored posts to rank.
- The rate list skips handles without a follower count.
- More posts, then the handle name, break ties.
- The leaderboard covers the posts of one run, not an account's whole history.

### Score a draft before you post

Paste your own text in `texts`. The Actor scores it & fetches nothing from X.

```json
{
  "texts": [
    "We shipped dark mode today. Try it and tell us what breaks.",
    "5 things we learned from 1,000 support tickets."
  ],
  "analysis": { "context": "Developers who use our app." }
}
```

- Each text becomes 1 row with `viralScore`, `viralVerdict` & `viral.stops`.
- `tweet.id` is `text:1`, `text:2` & so on, & `tweet.type` is `text`.
- A draft has no likes or views yet, so `viral.algorithmScore` stays `null`.
- Each analyzed text costs the same $0.0003 as an analyzed tweet.
- With `texts` set, the run analyzes only those texts. Run X targets separately.

### Pricing

AI costs are included in the per-tweet price. You pay no AI provider, buy no
tokens & bring no key.

From $0.0003 per successfully analyzed tweet, with no start fee. The price
includes collection & the Viral Score. The analysis allowance is 8 questions,
8,000 bytes per question definition & 12,000 bytes of context per tweet.
Extraction filters & deduplication run before analysis, so filtered-out &
duplicate rows are never analyzed or charged. Failed & skipped analyses &
diagnostic rows have no result charge. Apify bills platform usage separately.
The Pricing tab shows it.

### Input & output examples

The input above is copy-ready. Output rows look like this (abbreviated):

```json
{
  "tweet": { "id": "2100493544842494265", "text": "...", "likeCount": 12 },
  "viral": {
    "score": 74,
    "verdict": "send_it",
    "weights": "viral_lite:1",
    "stops": [],
    "algorithmScore": 8.5,
    "algorithmBasis": "views",
    "algorithmWeightedSum": 17,
    "actualEngagementRate": 0.7202,
    "weightsVersion": "x_algorithm_params:2026-09-18"
  },
  "viralScore": 74,
  "viralVerdict": "send_it",
  "viralAlgorithmScore": 8.5,
  "viralActualEngagementRate": 0.7202,
  "analysis": {
    "status": "succeeded",
    "answers": [
      { "questionId": "hook", "type": "score", "value": 2, "confidence": 0.84 },
      { "questionId": "spam", "type": "probability", "probability": 0.03 },
      {
        "questionId": "reaction",
        "type": "choice",
        "value": "share",
        "confidence": 0.7
      }
    ]
  }
}
```

Each result contains `tweet`, `analysis` & `viral`. Answers include types,
question versions & available probabilities. `viral.stops` lists the hard stops
that capped the score. A failed or skipped analysis keeps the collected tweet
with an empty answer list, a `reason` & a `null` score. Free diagnostics in the
key-value store explain invalid inputs, missing results & interrupted
collection. The run report separates collected rows, charged analyses & pending
charges.

### Run summary & flat answers

Each run writes an `analysis-summary` record to its key-value store & repeats it
under `results.analysisSummary` in the run report. It counts analyzed, failed &
skipped rows, sums engagement, and summarizes every question. Its `viral` block
reports `averageScore`, the count of each verdict, & how many rows the Actor
scored or left unscored. The same block holds `calibration`, `accounts` &
`leaderboard`, described above. Score questions report a mean & an
engagement-weighted mean. The `reaction` split shows how many tweets fall into
each reaction, & `top` lists the three most engaged tweets per reaction. An
empty run reports zero counts & a `null` average. Every row lists
`sourceDomains`, the hostnames it links to, & `cashtags` such as `$NVDA` found
in its text. With `monitor.baselineDatasetId` set, the summary's `monitor` block
counts comparison statuses & lists up to 50 changed rows.

Every result row also carries `viralScore`, `viralVerdict`,
`viralAlgorithmScore`, `viralActualEngagementRate` & `answers`, a flat map from
question ID to the chosen category, score, or probability. The `Viral Score`
dataset view & CSV or Excel exports show these columns beside the tweet, so
spreadsheets need no JSON parsing. Failed & skipped rows carry an empty map.

### Compare with an earlier run

Pass `monitor.baselineDatasetId`, the dataset ID of a completed earlier run with
the same analysis settings. Every row then gains a `monitor` object. Its status
is `first_run` without a baseline, `new_to_baseline` for tweets the earlier run
did not have, & `unchanged` or `changed` for tweets it had. `changes` lists each
trait decision that moved from `previous` to `current`. Decisions compare by
category, rounded score level, or yes/no at 0.5. A decision counts as changed in
three cases. The earlier category falls below 0.4 probability. A score moves at
least 0.6 levels. A yes/no probability lands at least 0.1 from the threshold.
Near-tie jitter between runs stays unchanged. Baselines above `maxBaselineRows`
(default 100,000) or from different settings stop the run before collection with
a diagnostic row.

### Task examples

Choose from 50 public tasks. Each starts from a real English search with a
bounded `maxItems` & the `Viral Score` dataset view. Some add audience context.
Edit the search or context before running.

- [Viral score of AI startup launch tweets](https://apify.com/xquik/x-tweet-viral-score-analyzer/examples/viral-score-of-ai-startup-launch-tweets)
- [Viral score of SaaS founder build in public posts](https://apify.com/xquik/x-tweet-viral-score-analyzer/examples/viral-score-of-saas-founder-build-in-public-posts)
- [Viral score of Product Hunt launch posts](https://apify.com/xquik/x-tweet-viral-score-analyzer/examples/viral-score-of-product-hunt-launch-posts)
- [Viral score of Developer tool announcements](https://apify.com/xquik/x-tweet-viral-score-analyzer/examples/viral-score-of-developer-tool-announcements)
- [Viral score of Open source release posts](https://apify.com/xquik/x-tweet-viral-score-analyzer/examples/viral-score-of-open-source-release-posts)
- [Viral score of Crypto project announcements](https://apify.com/xquik/x-tweet-viral-score-analyzer/examples/viral-score-of-crypto-project-announcements)
- [Viral score of Parenting humor posts](https://apify.com/xquik/x-tweet-viral-score-analyzer/examples/viral-score-of-parenting-humor-posts)
- [Viral score of Office humor posts](https://apify.com/xquik/x-tweet-viral-score-analyzer/examples/viral-score-of-office-humor-posts)
- [Viral score of Pet photo captions](https://apify.com/xquik/x-tweet-viral-score-analyzer/examples/viral-score-of-pet-photo-captions)
- [Viral score audit of NASA posts](https://apify.com/xquik/x-tweet-viral-score-analyzer/examples/viral-score-audit-of-nasa-posts)
- [Viral score audit of Duolingo posts](https://apify.com/xquik/x-tweet-viral-score-analyzer/examples/viral-score-audit-of-duolingo-posts)
- [Viral score audit of Wendy's posts](https://apify.com/xquik/x-tweet-viral-score-analyzer/examples/viral-score-audit-of-wendys-posts)

The remaining tasks cover more topics & brand accounts on the Actor page.

### FAQ & support

#### Does a high score mean a tweet will go viral?

No. The score estimates how well the wording works for a general reader. Timing,
audience size, media & luck also decide reach. Compare scores with the real
engagement counts on each row before you rely on them.

#### Can I use my own questions?

Yes. Custom `analysis.questions` replace the defaults: 1-8 `choice`, `score` or
`probability` questions with 2-255 categories or at least 2 ordered levels. The
Viral Score needs all 8 default questions, so custom questions leave it `null`.

#### Why did a row come back with `analysis.status` of `failed` or `skipped`?

The Actor collected & delivered the tweet, but the AI analysis did not complete.
`analysis.reason` names the cause, such as `context_limit` when the tweet & its
context exceed `maxContextBytes`, or `service_unavailable` after retries. These
rows carry no result charge & no score. Raise `maxContextBytes` (up to 12,000)
or rerun the affected IDs.

#### Does the analysis verify facts?

No. Answers describe what the post expresses & how the post frames it.
Probabilities express model confidence, not truth. Review important
classifications against the original tweet, which every row keeps.

#### Which languages work?

Extraction supports every language X serves. We validate analysis on English
customer scenarios first. Other supported languages return answers with the same
structure.

#### How do I limit cost?

Filters, deduplication & `maxItems` run before analysis, so the Actor analyzes &
charges only unique, filter-matching tweets. Use precise search operators, date
bounds & engagement floors, & start with a small `maxItems` to check answer
quality before a large run.

#### Where do I get help?

Open an issue on the Actor page or contact support@xquik.com with the run ID.
Free diagnostics in the key-value store explain empty, partial or interrupted
runs.

Xquik is an independent third-party service. Not affiliated with X Corp.
"Twitter" and "X" are trademarks of X Corp.

### Related Xquik Actors

Every Xquik Actor shares the same extraction engine, filter-first billing &
diagnostics. Pick the one that matches the data you need.

- [X Tweet Scraper](https://apify.com/xquik/x-tweet-scraper): Scrapes tweets
  from searches, profile timelines, Lists & tweet IDs with 50+ filters & flat
  exports. Use it when you need tweet data without analysis. From $0.00015 per
  row.
- [X Profile Scraper](https://apify.com/xquik/x-profile-scraper): Scrapes
  profiles plus their posts, replies, media & followers from handles, IDs or
  URLs. Use it when you start from accounts rather than searches. From $0.00015
  per row.
- [X Reply Scraper](https://apify.com/xquik/x-reply-scraper): Scrapes replies,
  comments & whole conversations under posts with 25+ filters. Use it when you
  need the discussion beneath tweets. From $0.00015 per row.
- [X Engagement Scraper](https://apify.com/xquik/x-engagement-scraper): Scrapes
  replies, quotes, retweeters & threads for post URLs or IDs in bulk. Use it
  when you measure who engaged with posts. From $0.00015 per row.
- [X Follower Scraper](https://apify.com/xquik/x-follower-scraper): Scrapes
  followers, following, List members, subscribers & Community members as profile
  rows. Use it when you need audience or member lists. From $0.00015 per
  profile.
- [X User Search Scraper](https://apify.com/xquik/x-user-search-scraper):
  Searches users by handle, bio & location with follower, verification, age &
  location filters. Use it when you build account lists from search. From
  $0.00015 per profile.
- [X List Scraper](https://apify.com/xquik/x-list-scraper): Scrapes List posts,
  members & followers from List URLs or IDs. Use it when a curated List defines
  your sources. From $0.00015 per row.
- [X Community Scraper](https://apify.com/xquik/x-community-scraper): Scrapes
  Community info, posts, searches, members & moderators. Use it when your
  sources are X Communities. From $0.00015 per row.
- [X Trends Scraper](https://apify.com/xquik/x-trends-scraper): Scrapes
  real-time trends by location with rank, volume, query & WOEID. Use it when you
  track what is trending where. From $0.00015 per trend.
- [X Article Scraper](https://apify.com/xquik/x-article-scraper): Scrapes
  long-form X Articles as Markdown & text with covers, authors, dates & metrics.
  Use it when you need article bodies, not tweets. From $0.00015 per article.
- [X Media Downloader](https://apify.com/xquik/x-media-downloader): Extracts or
  stores photos, videos & GIFs from posts or profiles with MP4 & metadata
  options. Use it when you need the media files themselves. From $0.00015 per
  media row.
- [X (Twitter) Brand Monitoring with AI Analysis](https://apify.com/xquik/x-twitter-brand-monitoring):
  Tracks brand mentions with AI relevance, sentiment & customer-experience
  answers & compares runs. Use it when you watch a brand over time. From $0.0003
  per analyzed tweet.
- [X Tweet Sentiment Analysis with AI](https://apify.com/xquik/x-tweet-sentiment-analysis):
  Labels attitude, intensity & sarcasm probability for every tweet with AI. Use
  it when you need general sentiment on any topic. From $0.0003 per analyzed
  tweet.
- [X (Twitter) Stock & Crypto AI Trading Signals](https://apify.com/xquik/x-twitter-stock-crypto-signals):
  Labels bullish, bearish, neutral or mixed stance, content type, conviction &
  asset relevance with AI. Use it when you follow stocks, crypto or trading
  talk. From $0.0003 per analyzed tweet.
- [X (Twitter) News Monitor with AI Analysis](https://apify.com/xquik/x-twitter-news-monitor):
  Labels news posts by format, source attribution & topic relevance with AI. Use
  it when you separate reporting from commentary. From $0.0003 per analyzed
  tweet.
- [X Tweet Classifier with AI Analysis](https://apify.com/xquik/x-twitter-tweet-classifier):
  Answers your own category, score & yes/no questions for every tweet with AI.
  Use it when the preset analyses do not fit your labels. From $0.0003 per
  analyzed tweet.

# Changelog

This Actor's version history is a separate document: https://apify.com/xquik/x-tweet-viral-score-analyzer/changelog.md

# Actor input Schema

## `startUrls` (type: `array`):

Add Tweet, profile, search, or List URLs as strings or {"url":"..."} objects. Profile URLs may use /with\_replies, /media, or best-effort /likes. Tweet URL batches recheck unresolved IDs once after partial responses. Example: \["https://x.com/elonmusk", "https://x.com/search?q=AI"]

## `searchTerms` (type: `array`):

Run multiple searches in one Actor run. Max Items applies across the run. Compatible account date windows share one bounded retrieval. Recent windows combine the profile timeline with author search. Historical windows use exact search. The Actor verifies raw date and unix-time operators before adding results. Example: from:elonmusk AI, #bitcoin lang:en

## `texts` (type: `array`):

Your own texts to analyze, such as draft tweets, replies or notes. The Actor fetches nothing from X for them. Each text becomes 1 row and costs the same as 1 analyzed tweet. When you set this field, the run analyzes only these texts.

## `maxItems` (type: `integer`):

Optional result cap across the whole run. Leave empty to use your Apify max total charge as the result limit when set. Without a spend cap, Xquik uses its built-in default. The Apify pricing box shows the current per-result price before the run starts. Diagnostic rows count toward this cap. The form starts at 1,000. A run can return 100,000 rows & more, so raise it for a full export.

## `analysis` (type: `object`):

Default questions rate hook, clarity, information, humor, ragebait, machine-like style, spam risk & the likely crowd reaction. The Viral Score needs all 8 default questions. Custom questions replace defaults & leave the score empty. Optional context describes your audience. Up to 8 questions. maxContextBytes defaults to 12000. Concurrency defaults to 4, with a maximum of 16.

## `monitor` (type: `object`):

Optional baselineDatasetId identifies a completed dataset from an earlier run of this Actor. Omit it for a first run. maxBaselineRows defaults to 100000, range 1-100000. Unreadable, changing or oversized baselines stop the run before collection. Keep analysis settings unchanged for comparable answers.

## `twitterContent` (type: `string`):

Search query using X advanced search syntax. Supports keywords, hashtags, exact phrases, boolean operators, and date or unix-time windows. The Actor verifies each returned tweet against requested time bounds. Example: web scraping OR #datascience

## `twitterHandles` (type: `array`):

X usernames for profile timelines and author search. Profile Tweets matches the Posts tab on X: posts, reposts & the author's replies to their own posts. Add Exclude replies under Tweet type filters for original posts only. Profile With Replies keeps target-authored posts and replies. Add usernames with or without @. Example: elonmusk, @nasa

## `profileUrls` (type: `array`):

Alias for Start URLs. Add profile URL strings or {"url":"..."} objects. Auto-route and profile modes combine the profile timeline with author search.

## `tweetIds` (type: `array`):

Tweet IDs to look up directly. Other sources in the same input run too, and Max Items applies across the run. Process up to 10,000 tweet IDs per run. Chunks of 100 run concurrently. Partial responses recheck unresolved IDs once. Example: 1846987139428634858

## `listIds` (type: `array`):

X list IDs to scrape through the dedicated list route. This is usually much faster than pasting list URLs into Start URLs or using the List ID search filter below. Example: 1748648376080666720

## `mode` (type: `string`):

Choose which tweets to collect. Tweet classification excludes standalone article extraction & user lists.

## `maxItemsPerTarget` (type: `integer`):

Optional cap for each target in multi-target modes.

## `queryType` (type: `string`):

Latest returns newest first. Top is relevance-ranked and not exhaustive. Latest + Top runs both passes concurrently, deduplicates before billing, and backfills unused capacity from either pass. Account timelines ignore this setting.

## `content` (type: `object`):

Build content filters without writing X search syntax.

## `users` (type: `object`):

Optional structured author, reply, mention, and list filters.

## `time` (type: `object`):

Optional structured time filters.

## `engagement` (type: `object`):

Optional structured engagement filters.

## `media` (type: `object`):

Optional structured media filters.

## `lang` (type: `string`):

Filter tweets by language using a 2-letter ISO 639-1 code. The Actor verifies returned tweets and continues paging past mismatches.

## `tweetTypes` (type: `object`):

Optional tweet type filters. Include only one type, or exclude replies, reposts or quote tweets.

## `geo` (type: `object`):

Optional structured location filters.

## `cards` (type: `object`):

Optional structured card filters.

## `sources` (type: `object`):

Optional structured source filters.

## `conversation_id` (type: `string`):

Only include tweets belonging to this conversation thread. Use the first tweet's ID in the thread.

## `conversationIds` (type: `array`):

Alias for one or more conversation\_id searches.

## `quoted_tweet_id` (type: `string`):

Only include tweets that quote this specific tweet ID.

## `quoted_user_id` (type: `string`):

Only include tweets that quote any tweet from this user ID.

## `filter:has_engagement` (type: `boolean`):

Only include tweets with at least one like, retweet, or reply.

## `include:nativeretweets` (type: `boolean`):

Include native retweets in results (excluded by default).

## `filter:twimg` (type: `boolean`):

Only include tweets containing twimg.com images.

## `filter:native_video` (type: `boolean`):

Only include tweets with natively uploaded video.

## `filter:vine` (type: `boolean`):

Only include tweets with Vine videos.

## `filter:consumer_video` (type: `boolean`):

Only include tweets with consumer-uploaded video.

## `filter:pro_video` (type: `boolean`):

Only include tweets with professionally produced video.

## `filter:spaces` (type: `boolean`):

Only include tweets containing a Spaces link.

## `filter:mentions` (type: `boolean`):

Only include tweets containing @mentions.

## `filter:hashtags` (type: `boolean`):

Only include tweets containing hashtags.

## `includeSearchTerms` (type: `boolean`):

Attach the first matching search term as `searchTerm` on each unique Tweet. Use it to identify which query produced each deduplicated result.

## `respectProfileSubpages` (type: `boolean`):

Honor profile subpage paths such as /with\_replies, /media, and /likes when routing profile URLs. /with\_replies returns target-authored posts and replies. The Actor excludes conversation context from other authors.

## `replyTweetIds` (type: `array`):

Tweet IDs whose direct replies to collect. The Actor combines 5 authenticated views, 3 ranking modes, every forward cursor module, labeled hidden-content branches, Top time partitions, and search. Nested replies never count as direct. Incomplete targets add a detailed diagnostic when capacity remains. Real replies always take priority.

## `quoteTweetIds` (type: `array`):

Tweet IDs to read with mode quotes.

## `threadTweetIds` (type: `array`):

Tweet IDs to read with mode thread.

## `from` (type: `string`):

Only include tweets sent by this username (without the @ symbol). Example: elonmusk

## `to` (type: `string`):

Only include tweets that are replies to this username (without @). Example: OpenAI

## `@` (type: `string`):

Only include tweets that mention this username (without @). Example: Google

## `since` (type: `string`):

Only include verified tweets on or after this date. Format: YYYY-MM-DD\_HH:MM:SS\_UTC. Example: 2026-01-01\_00:00:00\_UTC

## `until` (type: `string`):

Only include verified tweets before this date. Same format as Since Date. Example: 2026-04-01\_00:00:00\_UTC

## `since_time` (type: `string`):

Only include verified tweets on or after this unix timestamp (seconds). Example: 1704067200

## `until_time` (type: `string`):

Only include verified tweets before this unix timestamp (seconds). Example: 1711929600

## `within_time` (type: `string`):

Only include tweets from the last N time units. Example: 1d (1 day), 12h (12 hours), 30m (30 minutes), 60s (60 seconds)

## `since_id` (type: `string`):

Only include tweets with an ID greater than (posted after) this tweet ID.

## `max_id` (type: `string`):

Only include tweets with an ID less than (posted before) this tweet ID.

## `min_faves` (type: `integer`):

Only include tweets with at least this many likes. Set to 0 to disable.

## `-min_faves` (type: `integer`):

Only include tweets with at most this many likes. Set to 0 to disable.

## `min_retweets` (type: `integer`):

Only include tweets with at least this many retweets. Set to 0 to disable.

## `-min_retweets` (type: `integer`):

Only include tweets with at most this many retweets. Set to 0 to disable.

## `min_replies` (type: `integer`):

Only include tweets with at least this many replies. Set to 0 to disable.

## `-min_replies` (type: `integer`):

Only include tweets with at most this many replies. Set to 0 to disable.

## `filter:blue_verified` (type: `boolean`):

Only include tweets from X Premium (Blue) verified accounts.

## `filter:nativeretweets` (type: `boolean`):

Only include native retweets.

## `filter:replies` (type: `boolean`):

Only include reply tweets.

## `filter:quote` (type: `boolean`):

Only include quote tweets.

## `filter:media` (type: `boolean`):

Apply X's media search operator. Results usually include attached media, but X can also match media-like card content.

## `filter:images` (type: `boolean`):

Apply X's image search operator. Results usually include image media. X can also match card or link image content.

## `filter:videos` (type: `boolean`):

Apply X's video search operator. Results usually include native video media.

## `filter:links` (type: `boolean`):

Only include tweets containing external links.

## `filter:news` (type: `boolean`):

Only include tweets containing news article links.

## `filter:safe` (type: `boolean`):

Only include tweets marked as safe (excludes sensitive content).

## `near` (type: `string`):

Only include tweets geotagged near this place. Example: San Francisco

## `within` (type: `string`):

Radius for the Near Place filter. Format: integer + unit (km or mi), no spaces. Example: 10km, 25mi

## `geocode` (type: `string`):

Filter by exact coordinates in lat,long,radius format. Use no spaces. Give the radius in km or mi. Example: 37.7749,-122.4194,10km

## `list` (type: `string`):

Filter search results to Tweets from members of this X List. Use List IDs unless you need to combine this filter with other search operators.

## `url` (type: `string`):

Only include tweets containing this URL or domain. Example: github.com

## `card_name` (type: `string`):

Filter by poll or card type. Common values: poll2choice\_text\_only, poll3choice\_text\_only, poll4choice\_text\_only, poll2choice\_image, poll3choice\_image, poll4choice\_image.

## `includeRaw` (type: `boolean`):

API alias for Output Variant raw.

## `includeArticles` (type: `boolean`):

Deprecated compatibility input. Article data is already included when X provides it.

## `includeUnavailableFields` (type: `boolean`):

Deprecated compatibility input. Safe availability fields are already included when X provides them.

## `includeOriginalTweet` (type: `boolean`):

Deprecated compatibility input. Fetch source tweets separately with Tweet IDs.

## Actor input object example

```json
{
  "searchTerms": [
    "from:elonmusk AI",
    "#bitcoin lang:en"
  ],
  "texts": [
    "We shipped dark mode today. Try it and tell us what breaks."
  ],
  "maxItems": 1000,
  "analysis": {
    "targets": [],
    "context": "Judge each post as a general reader who does not follow the author."
  },
  "monitor": {
    "maxBaselineRows": 100000
  },
  "twitterContent": "web scraping OR #datascience",
  "twitterHandles": [
    "elonmusk",
    "@nasa"
  ],
  "tweetIds": [
    "1846987139428634858"
  ],
  "listIds": [
    "1748648376080666720"
  ],
  "mode": "legacy",
  "queryType": "Latest + Top",
  "lang": "en",
  "filter:has_engagement": false,
  "include:nativeretweets": false,
  "filter:twimg": false,
  "filter:native_video": false,
  "filter:vine": false,
  "filter:consumer_video": false,
  "filter:pro_video": false,
  "filter:spaces": false,
  "filter:mentions": false,
  "filter:hashtags": false,
  "includeSearchTerms": true,
  "respectProfileSubpages": false,
  "min_faves": 0,
  "-min_faves": 0,
  "min_retweets": 0,
  "-min_retweets": 0,
  "min_replies": 0,
  "-min_replies": 0,
  "filter:blue_verified": false,
  "filter:nativeretweets": false,
  "filter:replies": false,
  "filter:quote": false,
  "filter:media": false,
  "filter:images": false,
  "filter:videos": false,
  "filter:links": false,
  "filter:news": false,
  "filter:safe": false,
  "within": "10km",
  "geocode": "37.7749,-122.4194,10km",
  "includeRaw": false,
  "includeArticles": false,
  "includeUnavailableFields": false,
  "includeOriginalTweet": false
}
```

# Actor output Schema

## `scores` (type: `string`):

Flat table with the Viral Score, verdict & one column per trait answer beside each tweet.

## `results` (type: `string`):

Original tweets with analysis status, trait answers & question versions. Failed analyses remain available without a result charge.

## `diagnostics` (type: `string`):

Free actionable diagnostics for empty, partial, invalid, aborted, or recovered runs. Real results remain in the dataset.

## `runReport` (type: `string`):

Outcome, completion reason, counts, pages, duration, and privacy-safe anomalies.

# 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 = {
    "searchTerms": [
        "(AI agent OR coding agent OR agentic AI) (launch OR release OR benchmark OR open source) lang:en -filter:nativeretweets"
    ],
    "maxItems": 1000,
    "analysis": {
        "targets": [],
        "context": "Judge each post as a general reader who does not follow the author."
    },
    "monitor": {
        "maxBaselineRows": 100000
    },
    "queryType": "Latest + Top",
    "includeSearchTerms": true
};

// Run the Actor and wait for it to finish
const run = await client.actor("xquik/x-tweet-viral-score-analyzer").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 = {
    "searchTerms": ["(AI agent OR coding agent OR agentic AI) (launch OR release OR benchmark OR open source) lang:en -filter:nativeretweets"],
    "maxItems": 1000,
    "analysis": {
        "targets": [],
        "context": "Judge each post as a general reader who does not follow the author.",
    },
    "monitor": { "maxBaselineRows": 100000 },
    "queryType": "Latest + Top",
    "includeSearchTerms": True,
}

# Run the Actor and wait for it to finish
run = client.actor("xquik/x-tweet-viral-score-analyzer").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 '{
  "searchTerms": [
    "(AI agent OR coding agent OR agentic AI) (launch OR release OR benchmark OR open source) lang:en -filter:nativeretweets"
  ],
  "maxItems": 1000,
  "analysis": {
    "targets": [],
    "context": "Judge each post as a general reader who does not follow the author."
  },
  "monitor": {
    "maxBaselineRows": 100000
  },
  "queryType": "Latest + Top",
  "includeSearchTerms": true
}' |
apify call xquik/x-tweet-viral-score-analyzer --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,xquik/x-tweet-viral-score-analyzer"
        }
    }
}
```

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/81EuQ3h6dgXIUuSU9/builds/ndkhts3xgWlZyiN0r/openapi.json
