# Stocktwits Scraper (`insights_data/stocktwits-scraper`) Actor

Scrape Stocktwits for live stock & crypto messages, bullish/bearish sentiment, price targets, and trending symbols. Extract trader chatter and market mood — no API key. Export JSON/CSV for sentiment analysis, dashboards, and trading research.

- **URL**: https://apify.com/insights_data/stocktwits-scraper.md
- **Developed by:** [Insights Data](https://apify.com/insights_data) (community)
- **Features:** Limited permissions
- **Stats:** 2 total users, 2 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.10 / 1,000 results

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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

### 📈 What is Stocktwits Scraper?

Track retail investor sentiment and run your own market sentiment analysis on stocks and crypto with **Stocktwits Scraper**. It is made for traders, analysts, quant researchers and data scientists who want public Stocktwits messages, Bullish and Bearish tags, price targets and trending symbols as clean, structured data instead of copying posts by hand. Enter one or more tickers (or usernames), pick a mode and click **Start**. No coding, no login and no Stocktwits API key needed.

Stocktwits is a financial social media network where traders post short messages about tickers. Stocktwits Scraper is a stock sentiment scraper that turns those posts into structured records you can download, schedule and plug into your own tools.

- **Measure the mood on your watchlist:** collect stock market sentiment data from the Bullish and Bearish tags on the tickers you care about.
- **Financial sentiment analysis and NLP:** export labeled financial text as a sentiment analysis dataset for your own models.
- **Research trading signals:** use message volume, sentiment and engagement as inputs for your own backtests.
- **Compare earnings sentiment:** run it before and after a company reports and compare the Bullish and Bearish mix on its ticker.
- **Stock market research:** check which Stocktwits trending stocks are ranked today and read the AI summary Stocktwits shows for each one.
- **Monitor a watchlist on a schedule:** monitor mode returns only messages you haven't collected yet, so each run adds just the new posts.

**A Stocktwits API alternative for batch data:** give it tickers or usernames, start a run, and fetch the structured records through the Apify API. It is not the official Stocktwits API and not a live feed: each run collects the messages that are on Stocktwits when it reads them.

#### What can Stocktwits Scraper do?

- 📈 **Read the Stocktwits stream for any ticker:** `symbol` mode collects the latest Stocktwits messages for stock and crypto tickers like `AAPL` or `BTC.X`.
- 👤 **Collect a trader's posts:** `user` mode reads the public messages of any username.
- 🔥 **Read the trending Stocktwits feed:** `trending` mode reads the site-wide feed of trending messages.
- 📊 **Get Stocktwits trending symbols:** ranked tickers with a trending score, Stocktwits' own AI summary and fundamentals such as sector, market cap and P/E ratio.
- 🎯 **Filter results** by sentiment, minimum likes, asset class (stocks or crypto), content type (top, links, charts, videos), or only messages with a price target.
- 👁️ **Run a Stocktwits monitor:** monitor mode remembers the newest message per ticker, per user or for the trending feed, and returns only newer ones next time.
- ⚡ **Bulk input:** paste many tickers or usernames at once. They are processed in parallel, and results appear in the dataset while the run is still going.
- 📦 **Export** to JSON, CSV, Excel, XML or HTML, run it via API, schedule and monitor runs, and connect it to Make, Zapier, Google Sheets and more.

***

### 🗂️ What data can Stocktwits Scraper extract?

Whether you use it as a Stocktwits message scraper for a watchlist or to follow traders, each message becomes one flat record. The table lists the main fields with their exact dataset names; a few extra author and media fields are included too.

| Data | Fields |
|---|---|
| 📝 Message | `messageId`, `body`, `createdAt`, `url`, `isDiscussion`, `sourceTitle`, `sourceUrl` |
| ⭐ Sentiment | `sentiment` (Bullish / Bearish), `sentimentScore` (1, -1 or 0) |
| 📌 Price target | `hasPriceTarget`, `priceTarget`, `priceTargetCurrency`, `priceTargetDate`, `priceTargetStartingPrice`, `priceTargetCurrentPrice`, `priceTargetSentiment`, `priceTargetStatus`, `priceTargetIsHit`, `priceTargetAccuracy` |
| 📉 Price since post | `hasPriceSincePost`, `priceSincePostCapturedAt`, `priceSincePostSnapshots` |
| 👍 Engagement | `likeCount`, `likesTotal`, `replyCount`, `reshareCount`, `isReply`, `isReshare`, `inReplyToMessageId` |
| 👤 Author | `userId`, `username`, `userName` (display name), `userFollowers`, `userFollowing`, `userIdeas`, `userOfficial`, `userJoinDate`, `userAvatarUrl` |
| 🏷️ Symbols | `symbols`, `symbolsDetailed` (title, exchange, watchlist count and more for each ticker), `symbolPrices` |
| 📸 Media and links | `mediaItems`, `mediaUrl`, `mediaCount`, `chartUrl`, `links`, `hashtags`, `mentionedUsernames` |
| 🔥 Trending context (optional) | `trending`, `trendingRank`, `trendingScore`, `trendingAiSummary` |
| 🧾 Record info | `recordType` (`message`, `trendingSymbol` or `meta`), `sourceQuery` (the ticker, user or feed the record came from), `scrapedAt`, `isNewSinceLastRun` (currently always `true`, see Known issues) |
| 📊 Trending symbols mode | `rank`, `symbol`, `title`, `exchange`, `trendingScore`, `aiSummary`, `sector`, `industry`, `marketCap`, `peRatio`, `eps`, `beta`, `high52Week`, `low52Week`, `watchlistCount` |

A few fields explained:

- `likeCount` and `likesTotal` both show the message's total likes. The `minLikes` filter checks `likesTotal`.
- `userIdeas` is the "ideas" count Stocktwits reports for the author.
- Stocktwits sentiment is tagged by the author, so `sentiment` is `null` when the author added no tag (`sentimentScore` is then `0`).
- Price-target fields are filled only when a price-target prediction is attached to the message, which is true for a minority of posts.
- Trending context fields are filled only when you turn on **Enrich with trending context**.

#### What data can't Stocktwits Scraper extract?

- Private messages or anything behind a login
- Full user profile pages as separate records (you get the author fields attached to each message)
- Keyword or full-text search across Stocktwits (the input is tickers, usernames or the trending feeds)
- Full reply threads (you get reply and reshare counts and parent message IDs)

***

### 🔍 How to scrape Stocktwits messages and sentiment

1. [Create a free Apify account](https://console.apify.com/sign-up) using your email.
2. Open [Stocktwits Scraper](https://apify.com/insights_data/stocktwits-scraper).
3. The input is prefilled with `AAPL` and `TSLA` in `symbol` mode, so you can click **Start** right away for a test run. For your own watchlist, replace the tickers in **Stock / crypto symbols** (crypto tickers need the `.X` suffix, for example `BTC.X`), or switch **Scraping mode** to `user` and add names in **Stocktwits usernames**.
4. Click **Start**. Results appear in the **Output** tab while the run is going.
5. Download the results in JSON, CSV, Excel, XML or HTML, or fetch them through the API.

***

### 💲 How much does it cost to scrape Stocktwits?

Stocktwits Scraper uses **pay-per-event** pricing. The bill for a run has three parts:

| 💲 Part | Price |
|---|---|
| 🔢 Results | $0.003 per result, which is **$3.00 per 1,000 results** on the Free plan (lower on paid plans, see below) |
| ▶️ Actor start | $0.00005 for each GB of memory the run uses, charged once when the run starts. At the default memory of 1 GB, that's **$0.00005 per run** |
| ⚙️ Apify platform usage | The computing resources the run uses, paid on top of the event prices. It depends on the run, so there is no fixed price |

**What counts as a result:** each saved message, and each ranked ticker in `trending-symbols` mode. Progress records (see `includeMeta`) are not charged.

| Apify plan | Price per result | Price per 1,000 results |
|---|---|---|
| 🆓 Free | $0.003 | $3.00 |
| 🌱 Starter | $0.0027 | $2.70 |
| 📶 Scale | $0.0024 | $2.40 |
| 🏢 Business and higher | $0.0021 | $2.10 |

The plan discount applies to the result price only. The start fee is the same on every plan, and platform usage is billed at your Apify plan's own rates.

Examples at Free plan prices (results plus the start event at the default 1 GB of memory; platform usage comes on top):

- 1,000 results: 1,000 × $0.003 + $0.00005 = **$3.00005**
- 100 results: 100 × $0.003 + $0.00005 = **$0.30005**
- 20 results: 20 × $0.003 + $0.00005 = **$0.06005**

If you change the run memory, the start event is $0.00005 × the number of GB. To see your real total including platform usage, do a small test run and read the cost on the run page. See the [pricing tab](https://apify.com/insights_data/stocktwits-scraper/pricing) for the current details.

#### Is scraping Stocktwits free?

You can try it on the [Apify Free plan](https://apify.com/pricing), which gives you $5 in monthly credit. Free-plan runs work the same as paid runs. The credit is used up by your results plus platform usage together, so set a maximum charge limit when you start a run and do a small test run first.

***

### ⬇️ Stocktwits Scraper input

Only **Scraping mode** (`mode`) is required. In `symbol` mode you also add tickers in `symbols`, and in `user` mode you add `usernames`; the `trending` and `trending-symbols` modes need neither. All other fields have defaults.

| Mode | What it collects |
|---|---|
| `symbol` | The Stocktwits stream of each ticker in `symbols` |
| `user` | The public posts of each username in `usernames` |
| `trending` | The site-wide trending message feed |
| `trending-symbols` | The Stocktwits trending tickers ranked today, with fundamentals and AI summaries |

Here's the input the Actor is prefilled with. It collects up to 20 of the latest messages for each of `AAPL` and `TSLA`:

```json
{
    "mode": "symbol",
    "symbols": ["AAPL", "TSLA"],
    "maxMessages": 20
}
```

See the [input tab](https://apify.com/insights_data/stocktwits-scraper/input-schema) for a full description of all fields.

#### Stock / crypto symbols (`symbols`)

Enter tickers one per line or paste a list. A leading `$` is removed and tickers are upper-cased for you. Stocktwits crypto tickers use the `.X` suffix, so add `BTC.X` or `ETH.X` next to your stock tickers to collect crypto sentiment data in the same run.

- ✅ Good: `BTC.X`
- ❌ Bad: `BTC`

> ⚠️ Without `.X`, you get messages for a different, non-crypto instrument. The Actor never guesses the suffix for you.

#### Max messages / symbols (`maxMessages`)

The default is **20**. It limits how many messages are **saved**, not how many are scanned: the Actor keeps reading the feed until it has saved that many matching messages or the feed ends. In `symbol` and `user` modes the limit applies **per ticker or user**. In `trending` mode it is the total for the run, and in `trending-symbols` mode it is the number of ranked tickers saved.

Valid values are 0 to 10,000. Larger values make the run fail with an input error, even though the form accepts them. `0` = no count limit set by you; the run still stops at the end of the feed, the spending limit, or an internal safety limit.

- ✅ Good: `20`
- ❌ Bad: `50000`

#### Monitor mode (`onlyNewMessages` and `monitorStoreName`)

Turn on **Monitor mode — only new messages** to get only messages newer than your last run, tracked separately per ticker, per user, or for the trending feed. The **Monitor checkpoint name** (default `stocktwits-monitor`) keeps track of what you have already collected. The first run with a new name scrapes normally and saves the checkpoint.

- ✅ Good: `"monitorStoreName": "tech-watchlist"` for one watchlist and another name for the next
- ❌ Bad: reusing one name for unrelated watchlists you want to track separately

> ⚠️ The checkpoint moves to the newest message seen, even if a filter dropped that message. Monitor mode works in `symbol`, `user` and `trending` modes and has no effect in `trending-symbols` mode.

#### Filters (`sentimentFilter`, `minLikes`, `assetClassFilter`, `onlyPriceTargets`, `filter`)

- `sentimentFilter`: **Any** (the default, no filter), `Bullish`, `Bearish`, or `None` (untagged messages only)
- `minLikes`: drop messages with fewer total likes (`likesTotal`); `0` turns it off
- `assetClassFilter`: **Both** (the default), `STOCKS` or `CRYPTO`, based on whether a message's tickers end in `.X`
- `onlyPriceTargets`: keep only messages that carry a price-target prediction
- `filter` (**Stream content filter**): `all` (the default), `top`, `links`, `charts` or `videos`

The first four are checked after messages are read: every message is still scanned and only matches are saved. With strict filters, the Actor scans more of the feed to reach `maxMessages`, and you get fewer results if the feed runs out first.

`filter` works differently: it narrows the feed itself before it is read. For example, `top` reads only Stocktwits' top messages, and `charts` reads only messages with a chart, so other messages are never scanned.

> ⚠️ These filters, **Enrich with trending context** (`includeTrendingSymbolDetails`) and monitor mode apply to the message modes only. They are ignored in `trending-symbols` mode.

#### Other options

- `includeTrendingSymbolDetails`: adds `trending`, `trendingRank`, `trendingScore` and `trendingAiSummary` to each message. If the Stocktwits trending list can't be loaded, the run continues with `trending` set to `false`.
- `maxId`: continue backward (older messages) from a message ID. It applies to **every** target in the run, so use it with a single ticker or user.
- `includeRawData`: attach the original source object to each record as `raw`.
- `legacyKeyAliases` (on by default): also add snake_case copies of some fields, such as `message_id` and `user_id`.
- `includeMeta` (on by default): add one Progress record per target with scan counts. These records are not charged.
- `proxyConfiguration`: off by default. The Actor can use Apify Proxy. If Stocktwits starts blocking requests, the run switches its connection settings on its own and keeps going. You can also turn Apify Proxy on from the start.

***

### ⬆️ Stocktwits Scraper output

Results are saved to the dataset while the run is still going. Open the **Output** or **Storage** tab to see them as a table or JSON in four views: **Overview** (all record types together), **Messages**, **Trending Symbols** and **Progress**. You can pick only the fields you need. For a one-off Stocktwits data download, export them as JSON, CSV, Excel, XML or HTML. A combined JSON file of all records, including Progress records, is also saved in the run's key-value store under the key `OUTPUT`.

#### JSON example

Results for the input example above. The values are illustrative examples, not from a real run, and only some fields are shown:

```json
{
    "recordType": "message",
    "messageId": 600000001,
    "body": "$AAPL holding support into earnings, adding a few shares.",
    "createdAt": "2026-10-07T13:45:12Z",
    "sentiment": "Bullish",
    "sentimentScore": 1,
    "likeCount": 12,
    "replyCount": 3,
    "reshareCount": 1,
    "isReshare": false,
    "isReply": false,
    "hasPriceTarget": false,
    "hasPriceSincePost": false,
    "symbols": ["AAPL"],
    "symbolsDetailed": [
        { "symbol": "AAPL", "title": "Apple Inc.", "exchange": "NASDAQ" }
    ],
    "symbolPrices": [{ "symbol": "AAPL", "price": 250.1 }],
    "userId": 1234567,
    "username": "example_trader",
    "userName": "Example Trader",
    "userFollowers": 850,
    "userFollowing": 120,
    "userIdeas": 4200,
    "userOfficial": false,
    "userJoinDate": "2019-03-14",
    "links": [],
    "hashtags": [],
    "mentionedUsernames": [],
    "likesTotal": 12,
    "url": "https://stocktwits.com/example_trader/message/600000001",
    "sourceQuery": { "kind": "symbol", "value": "AAPL" },
    "isNewSinceLastRun": true,
    "scrapedAt": "2026-10-07T13:50:03.120Z"
}
```

With the default settings, each message also carries snake_case copies of some fields (for example `message_id`, `created_at`, `user_id`). Turn off `legacyKeyAliases` if you don't need them.

#### Trending symbols example

With `"mode": "trending-symbols"`, each record is one ranked ticker (illustrative values, some fields shown):

```json
{
    "recordType": "trendingSymbol",
    "rank": 1,
    "symbol": "NVDA",
    "title": "NVIDIA Corporation",
    "exchange": "NASDAQ",
    "trendingScore": 9.1,
    "aiSummary": "Short AI summary of why the ticker is trending today.",
    "sector": "Technology",
    "industry": "Semiconductors",
    "marketCap": 3500000000000,
    "peRatio": 45.2,
    "scrapedAt": "2026-10-07T13:50:03.120Z"
}
```

#### Progress example

With `includeMeta` on (the default), the **Progress** view shows one record per target. `messagesScanned` counts every message read, and `messagesReturned` counts the ones saved after your filters (illustrative values):

```json
{
    "recordType": "meta",
    "target": { "kind": "symbol", "value": "AAPL" },
    "messagesScanned": 45,
    "messagesReturned": 20,
    "hasMoreResults": true,
    "nextMaxId": 599999950,
    "reachedMaxMessages": true,
    "scrapedAt": "2026-10-07T13:50:04.010Z"
}
```

***

### 💡 Tips and advanced usage

#### How many results can you scrape with Stocktwits Scraper?

`maxMessages` allows up to 10,000 saved messages per ticker or user (or in total in the trending modes). The real number depends on how many messages Stocktwits has for a ticker or user, on your filters, and on your spending limit. A quick test run shows what you can expect for your use case.

#### How to get cheaper results

- Start with the default `maxMessages` of 20 and raise it once you're happy with the output.
- Use filters to save only the messages you need; you pay per saved result. Strict filters make the Actor scan more of the feed to fill `maxMessages`, so the run itself can take longer.
- Use monitor mode on scheduled runs so you don't collect the same messages again.

#### Run it on a schedule

A daily watchlist check takes three steps in Apify Console:

1. **Save your input as a task.** Fill in your tickers, for example `AAPL`, `NVDA`, `TSLA` and `BTC.X`, turn on **Monitor mode — only new messages** (`onlyNewMessages`) and give the watchlist its own **Monitor checkpoint name** (`monitorStoreName`), such as `tech-watchlist`. Then save the input as a new task.
2. **Add a schedule.** Open **Schedules**, create a schedule (for example every day after the US market close, or every hour on weekdays) and add your task to it.
3. **Compare runs.** Each scheduled run has its own dataset with only the messages posted since the last run. Add up `sentimentScore` per ticker in each run (1 = Bullish, -1 = Bearish, 0 = no tag) to see how the mood moves from day to day.

> ⚠️ Monitor runs still save at most `maxMessages` per ticker (default 20), and the checkpoint moves to the newest message seen. If a busy ticker gets more new posts between two runs, the ones not saved are not collected later, so raise `maxMessages` or schedule runs more often.

For `trending-symbols` mode, monitor mode has no effect: schedule a daily run and compare the `rank` and `trendingScore` of each ticker across runs instead.

#### Build a Stocktwits sentiment dataset

Combine `sentimentFilter`, `minLikes` and `assetClassFilter` with a schedule and monitor mode. Each run adds only new, labeled messages, so your Stocktwits dataset keeps growing for model training or backtesting.

#### Known issues

- `sinceId` (**Resume after message ID**) currently has no effect. Use monitor mode to get only newer messages.
- `maxId` applies to every target in the run, not just one. Use it with a single ticker or user.
- The `isNewSinceLastRun` field is currently always `true`. Use monitor mode to get only new messages.

***

### 🔌 Stocktwits Scraper integrations and API

#### Can I use Stocktwits Scraper as a Stocktwits sentiment API?

Yes, in a run-then-fetch way. The [Apify API](https://docs.apify.com/api/v2) lets you start runs, schedule them and fetch their results, so you can use it as a stock sentiment API for your own apps. Results come from the runs you start or schedule, not from a live stream. Use the `apify-client` [NPM package](https://apify.com/insights_data/stocktwits-scraper/api/javascript) for Node.js or the `apify-client` [PyPI package](https://apify.com/insights_data/stocktwits-scraper/api/python) for Python. See the [API tab](https://apify.com/insights_data/stocktwits-scraper/api) for ready-to-use code.

#### Stocktwits API Python example

Install the client with `pip install apify-client`, then run the input example above from your own Stocktwits Python script. Replace `<YOUR_API_TOKEN>` with the API token from your Apify Console settings:

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_API_TOKEN>")
run = client.actor("insights_data/stocktwits-scraper").call(run_input={
    "mode": "symbol",
    "symbols": ["AAPL", "TSLA"],
    "maxMessages": 20,
})

for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)
```

#### Can I integrate Stocktwits Scraper with other apps?

Yes. Connect Stocktwits Scraper with almost any cloud service through [Apify integrations](https://apify.com/integrations): **Make, Zapier, Slack, Google Sheets, Google Drive, Airbyte, GitHub, LangChain** and more. Use [webhooks](https://docs.apify.com/integrations/webhooks) to trigger actions whenever a run finishes. Three workflows that fit the schedule above:

- **Google Sheets sentiment log:** add the Google Sheets integration to your scheduled task. After each successful run, the new messages are added to a sheet, where a pivot table of `sentimentScore` by ticker and day gives you a simple sentiment chart.
- **Slack alert for Bearish posts:** make a second task with `sentimentFilter` set to `Bearish`, `minLikes` set to `5` and monitor mode on with its own checkpoint name (so each run only has new posts), schedule it hourly, and connect the Slack integration so your channel gets a message after each run.
- **Make, Zapier or n8n pipeline:** trigger on "run succeeded", fetch the dataset items of that run and send them to your database or dashboard.

#### Can I use Stocktwits Scraper with AI agents (MCP)?

Yes. Connect Stocktwits Scraper to Claude and other AI assistants through the Apify MCP server, then ask your assistant to collect the latest messages for a ticker and summarize the Bullish and Bearish mix. Open the [MCP tab](https://apify.com/insights_data/stocktwits-scraper/api/mcp) for setup steps.

***

### 🧰 Other market research and social sentiment scrapers

Insights Data, the developer of Stocktwits Scraper, also maintains these Actors. They collect data from other websites, not from Stocktwits, and fit next to it for investor research and social trend tracking:

- 🚀 [Y Combinator Scraper](https://apify.com/insights_data/y-combinator-scraper): company profiles, founders, open roles, press and Launch YC posts from the YC directory, built for lead gen, recruiting and deal sourcing
- 🔥 [X (Twitter) Trends Scraper](https://apify.com/insights_data/twitter-trends-scraper): trending hashtags and topics on X for worldwide, 50+ countries and 400+ cities, with rank, rank change and hours trending
- 📰 [Google News Scraper](https://apify.com/insights_data/google-news-scraper): headlines, publisher, publish date and the real article URL by search term, topic or link, with date, country and language filters
- 🧵 [Search Threads By Keywords](https://apify.com/insights_data/search-threads-by-keywords): Threads posts by keyword, #hashtag, phrase or @username with likes, replies, reposts and author followers

***

### ❓ FAQ

#### Is it legal to scrape Stocktwits?

Scraping publicly available data is generally legal, but you are responsible for how you use it. Stocktwits Scraper collects only public content and nothing behind a login. You should respect personal data rules (for example, GDPR), collect personal data only with a legitimate reason, and take the [Stocktwits Terms of Service](https://stocktwits.com/about/legal/terms) into account. This is not legal advice; if you're unsure, ask a lawyer.

#### How does Stocktwits Scraper work?

Think of it as a Stocktwits crawler that works like a person scrolling through a feed, only faster. You pick a mode and give tickers or usernames. It reads each public feed newest first, turns every message into a flat record, applies your filters and saves the matching records to the dataset right away. In `trending-symbols` mode it collects today's ranked trending tickers instead.

#### Why use Stocktwits data for stock sentiment analysis?

Stocktwits sentiment analysis is popular because authors tag their own posts as Bullish or Bearish, so you get labeled data without manual tagging.

- **Event studies:** compare the social media sentiment stocks attract before and after earnings or news. For the headlines behind a move, [Google News Scraper](https://apify.com/insights_data/google-news-scraper) collects news by search term with publisher and publish date.
- **Crypto research:** follow `BTC.X`, `ETH.X` and other coins next to your stock tickers.
- **NLP and AI:** train or test models on short, labeled financial posts.
- **Price-target tracking:** collect each Stocktwits price target with its status and accuracy.
- **Discovery:** find active tickers in `trending-symbols` mode, then collect their full message streams. To see what is trending on X at the same time, [X (Twitter) Trends Scraper](https://apify.com/insights_data/twitter-trends-scraper) returns trending hashtags and topics with rank and hours trending.

#### Why am I getting fewer results than expected?

- The feed ran out: `maxMessages` is a maximum, and a ticker or user may have fewer matching messages, especially with strict filters (`sentimentFilter`, `minLikes`, `assetClassFilter`, `onlyPriceTargets`).
- Monitor mode returns only messages newer than your last run with the same checkpoint name.
- Check the ticker format: crypto tickers need `.X`. Tickers or usernames that don't exist are skipped.
- Your spending limit may have been reached; the run then stops and keeps the results already saved.

#### What if a run fails or a ticker is missing?

- **The run failed:** read the run's status message first. Invalid input, such as `symbol` mode with no tickers or a `maxMessages` value outside the allowed range, stops the run, and the status message says why.
- **A ticker or username is missing:** the log shows a line saying the target was not found on Stocktwits and was skipped, while the other targets continue. With Progress records on (the default), that target usually appears in the **Progress** view with `messagesScanned` set to `0`.
- **Following a run:** while it runs, the status message shows how many targets are processed and how many messages are saved so far. The combined `OUTPUT` file in the key-value store holds every record of the run, including Progress records.
- **Still stuck?** Report it on the [Issues tab](https://apify.com/insights_data/stocktwits-scraper/issues/open) with a link to the run.

#### Do I need a Stocktwits account or API key?

No. This Stocktwits extractor collects public data without a login or key. You only need an Apify account to run it.

***

### 📧 Support and feedback

Found a bug or have a feature request? Please create an issue on the [Issues tab](https://apify.com/insights_data/stocktwits-scraper/issues/open).

Need a **custom solution**, a private sentiment feed or more data? Contact us at hello.insights.data@gmail.com.

Built and maintained by [Insights Data](https://apify.com/insights_data).

# Changelog

This Actor's version history is a separate document: https://apify.com/insights_data/stocktwits-scraper/changelog.md

# Actor input Schema

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

What to scrape:<br>📈 <strong>symbol</strong> — messages for one or more stock/crypto tickers<br>👤 <strong>user</strong> — the public post history of one or more Stocktwits users<br>🔥 <strong>trending</strong> — the site-wide trending-messages feed<br>📊 <strong>trending-symbols</strong> — today's ranked trending tickers with AI summaries

## `symbols` (type: `array`):

✨ One ticker per line, bulk-paste supported. Used in <strong>symbol</strong> mode. e.g. <code>AAPL</code>, <code>TSLA</code>. Crypto tickers need their own <code>.X</code> suffix — <code>BTC.X</code>, <code>ETH.X</code> (a bare <code>BTC</code> resolves to a different, non-crypto instrument, so it is never guessed for you). A leading <code>$</code> is stripped automatically.

## `usernames` (type: `array`):

One username per line (no <code>@</code>), bulk-paste supported. Used in <strong>user</strong> mode.

## `maxMessages` (type: `integer`):

Stop after this many messages per symbol/user (or total, for trending & trending-symbols modes). <code>0</code> = unlimited, up to Stocktwits' own API limits. Start low (20-50) to test before scaling up.

## `sentimentFilter` (type: `string`):

Only keep messages with this user-tagged sentiment. Leave on "Any" to keep everything. Roughly 30-50% of messages carry a sentiment tag at all.

## `minLikes` (type: `integer`):

Drop messages with fewer likes than this. Handy for surfacing only the higher-engagement posts.

## `assetClassFilter` (type: `string`):

Only keep messages about stocks or only about crypto, based on whether a message's symbols end in <code>.X</code>.

## `filter` (type: `string`):

Narrow a symbol/user/trending stream to a specific content type before it's even paged through.

## `includeTrendingSymbolDetails` (type: `boolean`):

Tag every message with its primary symbol's current trending-list standing (rank, score, AI summary) — one extra request per run, shared across every target, not one per message.

## `onlyNewMessages` (type: `boolean`):

Turn ON to only fetch messages newer than the last time this Actor ran with the same 'Monitor checkpoint name' below. Perfect for a scheduled run that checks in every few hours without re-scraping what it already saw.

## `monitorStoreName` (type: `string`):

Name of the checkpoint that remembers the last-seen message per target between runs. Use a different name to track separate watchlists independently.

## `onlyPriceTargets` (type: `boolean`):

When ON, only messages carrying a Stocktwits Predict™ price-target prediction are saved. Every message is still scanned either way (there's no server-side filter for this) — it only changes what gets pushed to your dataset.

## `sinceId` (type: `integer`):

Advanced: manually resume a single-target run forward from a specific message ID instead of starting from the newest message. Leave empty for normal use.

## `maxId` (type: `integer`):

Advanced: manually resume a single-target run backward (older messages) from a specific message ID. Leave empty for normal use.

## `includeRawData` (type: `boolean`):

Attach the raw decoded message/symbol object to every record, verbatim — handy for power users and debugging, or if a field isn't mapped yet.

## `legacyKeyAliases` (type: `boolean`):

Also emit snake_case aliases (message_id, price_target, user_id, ...) alongside the primary camelCase keys, for pipelines expecting either style.

## `includeMeta` (type: `boolean`):

Emit one bookkeeping record per target (recordType "meta") with scan counts and pagination status — visible in its own dataset view.

## `concurrency` (type: `integer`):

How many symbols/usernames are paginated at the same time.

## `httpMaxConcurrency` (type: `integer`):

Hard cap on how many HTTP requests are ever in flight at once, across every target combined.

## `requestDelaySecs` (type: `number`):

A polite minimum pace shared across every concurrent request. Raise this if you see a lot of retry/backoff activity in the log.

## `maxRetries` (type: `integer`):

How many times one failed/blocked request is retried (with backoff) before it's given up on. The residential proxy tier always gets at least 3 attempts.

## `requestTimeoutSecs` (type: `integer`):

How long to wait for a single response before treating it as failed.

## `proxyConfiguration` (type: `object`):

🚦 Default is NO proxy — the Actor talks to Stocktwits directly. If a request ever gets rejected or blocked, it automatically escalates step-by-step: 🚫 no proxy → 🖥️ datacenter proxy → 🏠 residential proxy (retrying up to 3× on residential), then sticks with residential for the rest of the run. Every escalation is logged clearly. Force a tier yourself here if you already know what you need.

## Actor input object example

```json
{
  "mode": "symbol",
  "symbols": [
    "AAPL",
    "TSLA",
    "BTC.X"
  ],
  "usernames": [
    "jimcramer"
  ],
  "maxMessages": 20,
  "sentimentFilter": "",
  "minLikes": 0,
  "assetClassFilter": "",
  "filter": "all",
  "includeTrendingSymbolDetails": false,
  "onlyNewMessages": false,
  "monitorStoreName": "stocktwits-monitor",
  "onlyPriceTargets": false,
  "includeRawData": false,
  "legacyKeyAliases": true,
  "includeMeta": true,
  "concurrency": 5,
  "httpMaxConcurrency": 4,
  "requestDelaySecs": 0.34,
  "maxRetries": 3,
  "requestTimeoutSecs": 30,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

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

Every scraped record together, in scrape order.

## `messages` (type: `string`):

Only message records — text, sentiment, engagement, symbols, author and price-target fields.

## `trendingSymbols` (type: `string`):

Only trending-symbol records (mode 'trending-symbols') — rank, score, AI summary and fundamentals.

## `progress` (type: `string`):

Per-target bookkeeping: how many messages were scanned and saved for each symbol/user.

## `outputJson` (type: `string`):

Every record from this run in a single combined JSON array — the classic output.json shape — saved to the run's key-value store under the 'OUTPUT' key.

# 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 = {
    "mode": "symbol",
    "symbols": [
        "AAPL",
        "TSLA"
    ],
    "usernames": [
        "jimcramer"
    ],
    "maxMessages": 20,
    "monitorStoreName": "stocktwits-monitor",
    "proxyConfiguration": {
        "useApifyProxy": false
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("insights_data/stocktwits-scraper").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 = {
    "mode": "symbol",
    "symbols": [
        "AAPL",
        "TSLA",
    ],
    "usernames": ["jimcramer"],
    "maxMessages": 20,
    "monitorStoreName": "stocktwits-monitor",
    "proxyConfiguration": { "useApifyProxy": False },
}

# Run the Actor and wait for it to finish
run = client.actor("insights_data/stocktwits-scraper").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 '{
  "mode": "symbol",
  "symbols": [
    "AAPL",
    "TSLA"
  ],
  "usernames": [
    "jimcramer"
  ],
  "maxMessages": 20,
  "monitorStoreName": "stocktwits-monitor",
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}' |
apify call insights_data/stocktwits-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,insights_data/stocktwits-scraper"
        }
    }
}
```

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/pvb9gswzYg1jHWo9w/builds/2qP87yeg6fx38acHt/openapi.json
