Stocktwits Scraper - Messages, Sentiment & Trending avatar

Stocktwits Scraper - Messages, Sentiment & Trending

Pricing

from $1.20 / 1,000 message or profile records

Go to Apify Store
Stocktwits Scraper - Messages, Sentiment & Trending

Stocktwits Scraper - Messages, Sentiment & Trending

Scrape Stocktwits message streams with bull/bear sentiment labels, bodies, likes, replies, cashtags and author stats for any symbol. Trending symbols, user profiles and full reply threads. Incremental monitoring, resume and MCP export.

Pricing

from $1.20 / 1,000 message or profile records

Rating

0.0

(0)

Developer

Abot API

Abot API

Maintained by Community

Actor stats

2

Bookmarked

1

Total users

1

Monthly active users

4 days ago

Last modified

Categories

Share

Stocktwits Scraper: Message Streams, Sentiment & Trending Symbols

Stocktwits Scraper turns Stocktwits, the trader social platform, into a clean sentiment and message data feed. Pull one or more tickers' message streams with the crowd's own Bullish or Bearish sentiment tags, open any message's public reply thread, read a trader's profile and recent posts, or grab the current trending symbols list. Every message record carries the body, the author, the sentiment tag the author chose, likes, reply counts and the cashtags and symbols it mentions. Point it at tickers, usernames, message links or pasted Stocktwits links, then export to JSON, CSV or Excel, or pull the results straight into your app through the API.

Why This Scraper?

  • Ready-made sentiment dataset: each message carries the sentiment label its own author chose, Bullish, Bearish or untagged, no inference needed.
  • One schema, four record kinds: symbol streams, user messages, thread replies and profiles all land in the same fields, filtered by the kind column.
  • Reply threads on demand: turn on reply fetching and get every reply the site returns for a message, each with its own author and sentiment, with no cap on the actor's side.
  • Trending symbols and profiles: the current trending list with watchlist counts, and user profiles with follower, following and idea counts.
  • Five ways to point it: tickers, usernames, message links or IDs, pasted Stocktwits links, or the current trending list, no URL building required.
  • Incremental monitoring: recurring runs on the same input report only NEW, UPDATED, REAPPEARED or EXPIRED records, with resume support for interrupted runs.

Use Cases

  • Sentiment and quant researchers: build a bullish or bearish crowd sentiment series per ticker for signal research or backtesting.
  • Community and social teams: track trending symbols and message volume to see what traders are talking about right now.
  • Trust and safety reviewers: pull the full public reply thread around one message for moderation or dispute review.
  • Growth and influencer tracking: monitor a trader's profile, follower count and idea count over time.
  • Alerting and monitoring bots: schedule recurring runs with incremental mode and get only the new or changed messages since last time.

Data You Get

Sample shape: values are illustrative placeholders, not from a live record.

FieldExample
kind"message" (also "reply", "symbol", "user")
recordId"m:900000001"
messageId900000001
url"https://stocktwits.com/sampletrader/message/900000001"
body"Sample trading note about the sample company. $SAMPLE looking ready for a breakout."
createdAt"2027-01-15T19:30:24Z"
sentiment"Bullish" (also "Bearish", or "None" for untagged)
likes12 (also as likeCount; repliesCount/replyCount and reshares/reshareCount likewise)
repliesCount3
cashtags / mentionedUsers["SAMPLE"] / ["othersample"]
symbols[{"symbol": "SAMPLE", "title": "Sample Company Inc", "exchange": "NYSE"}]
authorUsername / authorName"sampletrader" / "Sample Trader"
authorFollowers / authorIdentity / authorOfficial420 / "User" / false
chartUrl / mediaUrl / sourceTitlemessage records: attached chart image, first media file and posting app name, when present
sourceLabel{"id": 1, "title": "Sample App", "url": "https://example.com"} (the posting client, passed through as reported upstream)
symbolContext"SAMPLE" (symbols and url modes: which ticker stream the message came from)
parentMessageId / inReplyToMessageId / isReshare / isReply / isDiscussion / conversationParentMessageIdthread flags, and the parent message id on replies and conversation messages
symbol / symbolTitle / exchange / region / watchlistCount / trendingRanksymbol records: "SAMPLE" / "Sample Company Inc" / "NYSE" / "US" / 18500 / 4 (rank only on trending results)
userId / username / profileUrluser records: 4200001 / "sampletrader" / "https://stocktwits.com/sampletrader"
followers / following / ideasuser records: 420 / 85 / 312
priceTarget / priceTargetCurrency / priceTargetDate / priceTargetStartDate / priceTargetStartingPrice / priceTargetCurrentPricemessage records that carry a structured price target only (priceTargetCurrency only when the site states it)
userName / userAvatarUrl / userFollowers / userFollowing / userIdeas / userOfficial / userJoinDatemessage records: the author block
symbolDisplay / title / logoUrl / rank / trendingScore / trendSummary / marketCapsymbol records (rank, trendingScore, trendSummary and marketCap on the trending list); sector, industry and instrumentClass too when the site gives them
scrapedAtevery record: when this run produced it
changeType / changedFields / firstSeenAt / lastSeenAtincremental mode only

Symbol records read from a fallback symbol page can also carry sector, industry, instrumentClass, and a quoteLast / quoteChangePercent / quotePreviousClose snapshot. Trending records carry sentimentChange and volumeChange when the site reports them.

How to Use

  1. Pick a mode: symbols (ticker message streams), trending (the current trending list, no input needed), users (profiles and recent messages), threads (one message and its full reply thread), or url (paste Stocktwits links).
  2. Fill in the field for that mode: tickers, usernames, message links or IDs, or pasted links, and set the stream order and sentiment filter if you want to narrow the messages returned.
  3. Turn on Fetch reply threads if you also want every returned message's public replies (this adds a per-thread surcharge), then set Max items to control run size and cost.
  4. Click Start, then download the dataset as JSON, CSV or Excel, or read it through the API.

URL mode and the links it accepts. Paste any of these (the field ships with one example of each, so a run with the field untouched now reads all of them instead of nothing):

LinkWhat you get
stocktwits.com/symbol/SAMPLE (also www.)the ticker's message stream
stocktwits.com/symbol/SAMPLE?filter=topthe same stream ordered by engagement
stocktwits.com/symbol/SAMPLE/sentiment or /newsthe ticker's message stream (same rows as the plain symbol page, so not part of the default list)
stocktwits.com/symbol/SAMPLE.X (crypto)the coin's own stream, not the stock with the same letters
stocktwits.com/symbol/BRK.B (share class)that class's own stream (BRK.B, BF.B, BRK.A), not the bare letters
stocktwits.com/sampletraderthe profile and recent messages
stocktwits.com/sampletrader/message/900000001the message and its reply thread
stocktwits.com/topic/samplethe topic's message stream
stocktwits.com/sentiment/trending or /markets/trendingthe trending symbols list

Links that fit none of these are skipped with a warning in the log. Older /messages/ links and bare numeric message ids are still accepted. Message links in results now use the working /message/ form. Records already tracked by an incremental baseline are not re-billed for that URL correction.

A ticker's sentiment stream:

{
"mode": "symbols",
"symbols": ["AAPL", "TSLA"],
"sentiment": "bullish",
"maxItems": 100
}

The current trending symbols:

{
"mode": "trending",
"maxItems": 0
}

A profile and its recent messages:

{
"mode": "users",
"usernames": ["sampletrader"],
"maxItems": 50
}

A message and its full reply thread:

{
"mode": "threads",
"messageUrls": ["https://stocktwits.com/sampletrader/message/900000001"],
"maxItems": 0
}

Run it from your code

Python:

from apify_client import ApifyClient
client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("abotapi/stocktwits-com-scraper").call(run_input={
"mode": "symbols", "symbols": ["AAPL"], "sentiment": "bullish"})
for message in client.dataset(run["defaultDatasetId"]).iterate_items():
print(message["authorUsername"], message["sentiment"], message["body"])

JavaScript:

import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: '<YOUR_APIFY_TOKEN>' });
const run = await client.actor('abotapi/stocktwits-com-scraper').call({ mode: 'symbols', symbols: ['AAPL'] });
const { items } = await client.dataset(run.defaultDatasetId).listItems();

Or connect it to Make, Zapier, n8n, Google Sheets or webhooks from the Integrations tab.

Reply threads and the surcharge

Turn on Fetch reply threads in Symbols, Users or URL mode to also read each returned message's full conversation and emit every public reply as its own reply record. Threads mode needs no toggle: the thread is the surface you asked for, so it never charges a surcharge. The actor sets no reply cap and returns every reply the site serves in its one thread read; on very large threads the site itself serves only part of the conversation (about 500 replies were returned for a 1,269 reply message). The read bills one detail-enrichment event plus one more per started block of 10 replies (a 25 reply thread bills 3), and a run level breaker stops thread fetching for the rest of a run once threads keep failing, so base records still ship. A suppressed incremental record never triggers a thread read or its charge.

Max items and the per scope budget

Max items defaults to 20 and the schema caps it at 100000 (the same ceiling applies to Max messages per target); 0 means no limit and the run stops only when the streams run out. When a mode has several targets (several tickers, usernames, thread links or pasted URLs), each target's share is Max items divided by the number of targets (at least 1), so one busy ticker cannot use up the whole run. A profile record, a thread's parent message and fetched replies count toward the run total but not toward a target's share, so with a small Max items and many targets the last targets can get nothing; raise Max items or use 0 in that case. The trending list is about 30 symbols, so use 0 to get the whole list. Large, active symbol streams can run for a long time under 0, so set a limit when you do not need the full history.

Resume and recurring updates

  • Resume (resumeFromRunId): paste a previous run ID or dataset ID and the actor skips every record already collected there, so you do not pay twice for a large pull.
  • Incremental mode (incrementalMode): for scheduled monitoring of the same input. The first run reports every record NEW; later runs report NEW, UPDATED and REAPPEARED. Compared: message text, sentiment, cashtags and symbols, author name and identity, and profile or symbol details. Excluded from comparison (still present in the output with their live values): likes, repliesCount, reshares, likeCount, replyCount, reshareCount, userFollowers, userFollowing, userIdeas, priceTargetCurrentPrice, rank, trendingScore, trendSummary, marketCap, scrapedAt, mentionedUsers, authorFollowers, watchlistCount, trendingRank, sentimentChange, volumeChange and the live quote fields, so a counter tick never marks a record UPDATED. Add your own with Ignore fields when detecting changes (ignoreFieldsForChanges): top-level names or dotted paths such as symbols.exchange for nested fields. Changing that list never causes a one-time wave of UPDATED rows, because stored records are re-compared under the current list. emitUnchanged and emitExpired are off by default; turning them on returns, and bills, extra rows. EXPIRED detection only fires once a run has scanned its whole input without stopping early on a limit or a failed read, so a capped or partial run never tombstones records that are still there. With Fetch reply threads on, replies are only read for messages that ship in that run: a message that is unchanged since the last run does not get its thread re-read, so new replies under it are not picked up, and its earlier replies can be reported EXPIRED if Emit expired is on. Keep Emit expired off when you monitor reply threads.

Send results into your apps (MCP connectors)

Optionally pipe the scraped results into the apps you already use, via Model Context Protocol (MCP) connectors. This is an extra delivery step after the scrape: the Apify dataset is never changed.

What gets written to the connector: a condensed, human readable summary of each record, not the full JSON. Each item becomes one entry with a title and its key fields flattened to plain text. The complete record always stays in the Apify dataset.

  1. Authorize a connector once under Apify, Settings, Integrations (Notion, Linear, Airtable, or Apify).
  2. Select it in the "Pipe results into your apps" input field. (If the picker is empty, you have not authorized a connector yet.)
  3. For Notion, also set notionParentPageUrl to the page where items should be created.

The connection is mediated by Apify's MCP proxy, so this actor never sees your third party credentials. Leave the field empty to skip.

Input Parameters

ParameterTypeDefaultDescription
modestringsymbolssymbols, trending (trending symbols), trending-messages (the site-wide trending message stream), users, threads, or url. symbol, user and trending-symbols are accepted as aliases of symbols, users and trending.
symbolsarray["AAPL"]Symbols mode: one ticker per line, $ optional. Share classes (BRK.A, BRK.B, BRK.C) and crypto tickers (BTC.X) keep their dotted suffix. Foreign exchange suffixes such as .TO, .HK or .L (for example VOD.L) are not supported: the entry is skipped with a warning in the log. Crypto tickers entered here used to read the same-letter stock stream (BTC); they now read the coin stream (BTC.X), so a saved incremental Symbols-mode task with such a ticker starts a new baseline on its next run.
sortstringallSymbols mode stream order: all (newest first) or top (the site's engagement order).
usernamesarray["Stocktwits"]Users mode: one username per line, @ optional.
messageUrlsarray(none)Threads mode: one message per line, as a link or a bare numeric ID.
startUrlsarraysampleURL mode: Stocktwits links to read, one per line.
sentimentstringallKeep only bullish, bearish or untagged (none) messages; applies to every mode that returns messages.
fetchRepliesbooleanfalseAlso read each returned message's full reply thread (surcharge per 10 replies).
onlyPriceTargetsbooleanfalseKeep only messages that carry a structured price target; the others are skipped before they reach the dataset, so they are never billed. Scanning stops after 100 pages per target when targets are rare.
maxMessagesinteger(none)Cap per symbol, user, link or the trending stream. To take N from each of several targets set it to N and raise Max items (or use 0).
maxItemsinteger20Stop after this many records (0 = no limit).
resumeFromRunIdstring(none)Continue one interrupted run without returning records already collected there.
incrementalModebooleanfalseReturn only new and changed records on scheduled runs over the same input.
stateKeystring(none)Name or share an incremental mode monitoring campaign.
ignoreFieldsForChangesstring[][]Incremental mode only. Extra field names (or dotted paths) that never trigger UPDATED.
emitUnchangedbooleanfalseAlso return (and bill) unchanged records.
emitExpiredbooleanfalseAlso return (and bill) records no longer found, after a complete scan.
mcpConnectorsarray(none)Optional: send a summary of each record to apps you authorized under Integrations.
notionParentPageUrlstring(none)Notion connector only: page under which item pages are created.
maxNotifyListingsinteger50Cap on items written to each connector per run (1 to 1000).
proxyConfigurationobjectApify ProxyConnection settings. Requires a plan with proxy access.

Output Example

Sample shape: values are illustrative placeholders, not from a live record.

{
"kind": "message",
"recordId": "m:900000001",
"messageId": 900000001,
"url": "https://stocktwits.com/sampletrader/message/900000001",
"body": "Sample trading note about the sample company. $SAMPLE looking ready for a breakout.",
"createdAt": "2027-01-15T19:30:24Z",
"sentiment": "Bullish",
"likes": 12,
"repliesCount": 3,
"reshares": 0,
"cashtags": ["SAMPLE"],
"symbols": [{ "symbol": "SAMPLE", "title": "Sample Company Inc", "exchange": "NYSE" }],
"mentionedUsers": ["othersample"],
"authorUsername": "sampletrader",
"authorName": "Sample Trader",
"authorFollowers": 420,
"authorIdentity": "User",
"authorOfficial": false,
"sourceLabel": { "id": 1, "title": "Sample App", "url": "https://example.com" },
"symbolContext": "SAMPLE"
}

Output views

The Output tab and the dataset offer these views: All records, Messages, Trending symbols, User profiles, Changes (incremental) (change type, changed fields, first and last seen) and Price targets (messages with a structured price target). When the run ends, a run summary is saved under the OUTPUT key of the key-value store.

Plan Requirement

The site sits behind a browser-fingerprint check, and the actor reads it through Apify Proxy. Measured: through ordinary datacenter connections the pages and data feeds answer normally, so the default setting works and no residential connection is needed. The actor rotates connections automatically when one fails. Your Apify plan needs proxy access: on a plan without it, the run stops within seconds with this message: "The proxy connection was refused for this account, so no page could be read. Your Apify plan does not include proxy access; a paid plan is required: https://apify.com/pricing. If you entered your own proxy URLs, check that their credentials are valid." It does not quietly return zero rows.

FAQ

How much does it cost?

You pay per record returned, and a reply thread read adds a surcharge only when you turn on Fetch reply threads. Pricing is pay per event: one event per record returned (the main charge), one reply thread event per message whose thread is read plus one per started block of 10 replies, and a small actor start event per GB of memory. The Pricing tab always shows the current rates for your plan. Use Max items to cap the cost of any run.

This actor collects only publicly available messages, profiles and the trending list; the site answers the same data anonymously, with no login required. You are responsible for how you use the data: follow Stocktwits' terms and the laws that apply to you, and get legal advice before any commercial redistribution.

Can I get only new or changed messages on a schedule?

Yes. Schedule the actor from the Schedules tab with the same input and turn on Incremental mode. Later runs then return only NEW, UPDATED and REAPPEARED records; unchanged ones are skipped unless you also turn on Emit unchanged.

What is the difference between Threads mode and turning on Fetch reply threads?

Threads mode reads one specific message you name and its public reply thread; no toggle needed, the thread is the surface you asked for. Fetch reply threads is an add on switch for Symbols and Users mode: turn it on and every returned message also gets its own thread read, with its replies added as their own records, at a surcharge.

Why did my run fail instead of returning an empty dataset?

If a run returns no records and at least one read was refused or not found, the run fails with a clear message instead of quietly reporting a dataset with zero records, so "nothing matched" is never confused with "nothing could be read". A message that exists but has no replies is returned on its own (the log notes it has no replies; it is not treated as missing). A ticker, username or message that does not exist is reported in the log and skipped, and the run still succeeds if anything else was returned; but when it is the only target, the run fails, so check the spelling first.

Can I use it with AI agents or MCP?

Yes. Call it from any Apify integration or MCP client, and use the connector field to push results into the apps you authorized.

πŸ”— More scrapers you might like

Pair this actor with these related scrapers from the same team:

πŸ“± Mastodon
From $1/1K. Scrape trending Mastodon profiles and related posts from any Mastodon...
πŸ“± TikTok Profile, Hashtag, Search, Video & Trending Scraper
Scrape TikTok without login. Extract profiles, bios, follower stats and videos; search by...
🧩 TikTok Comments Scraper
Scrape comments from TikTok videos using one or more video URLs or IDs. Extract comment...
πŸ“± Reddit⚑ Lightning
From $1/1K. Scrape Reddit posts, comments, and media from any subreddit or user profile -...
πŸ“± Lemon8 Profile Scraper
Scrape Lemon8 user profiles with automated multi-profile discovery. Extract profile data...
🎬 Twitch ALL IN ONE URL
From $1/1K. Scrape Twitch data at scale, including channels, live streams, clips, VODs...

πŸ‘‰ Browse all abotapi scrapers

πŸ’¬ Support

  • 🐞 Found a bug or a missing field? Open a ticket on the Issues tab. We usually reply within hours.
  • πŸ› οΈ Need another site, extra fields or a private build? Email contact@abotapi.com.
  • ⭐ Enjoying it? A quick review on the actor page helps other users find it.