Skip to main content
← Back to blog
by Engineering
sentimentcryptotutorial

Build a Twitter Sentiment Analysis Tool with XCROP API

Why Twitter Sentiment Matters in Crypto

Crypto markets are driven by narratives, and narratives live on Twitter. Before a token pumps or dumps, the sentiment shift is visible in tweets — hours or even days before price action. A twitter sentiment analysis API lets you quantify this shift programmatically.

Professional trading desks have been using social sentiment tools for years. With XCROP's search API, you can build your own crypto sentiment twitter tracker without expensive data providers or complex scraping infrastructure.

Architecture Overview

The system is simple:

1. Collect — Use XCROP Search API to fetch recent tweets about a token
2. Score — Run each tweet through a sentiment scorer (keyword-based or LLM)
3. Aggregate — Calculate overall sentiment (bullish / bearish / neutral)
4. Act — Use the score as a trading signal or monitoring alert
XCROP Search API ──→ Tweet Collection ──→ Sentiment Scorer ──→ Dashboard/Alert
     ($BTC)           (100 tweets)        (bull/bear/neutral)    (score: +0.72)

Step 1: Collecting Tweets with XCROP Search

The /v2/search endpoint lets you search for tweets by keyword, hashtag, or cashtag. For crypto sentiment, cashtags like $BTC or $ETH work best.

PYTHON
import requests
import os

API_KEY = os.environ["XCROP_API_KEY"]
BASE = "https://xcrop.io/api/v2"
HEADERS = {"Authorization": "Bearer " + API_KEY}

def search_tweets(query, count=50, sort="latest"):
    """Search tweets using XCROP API."""
    response = requests.post(
        BASE + "/search",
        headers=HEADERS,
        json={
            "query": query,
            "count": count,
            "sort": sort
        }
    )
    if response.status_code == 200:
        return response.json()["data"]
    print("Error: " + str(response.status_code))
    return []

# Fetch latest tweets about Bitcoin
tweets = search_tweets("$BTC", count=100)
print("Collected " + str(len(tweets)) + " tweets about $BTC")

Filtering for Quality

Not all tweets are useful for sentiment. Filter out spam, bots, and low-engagement noise:

PYTHON
def filter_quality_tweets(tweets, min_likes=5, min_followers=100):
    """Filter tweets for quality signals."""
    filtered = []
    for tweet in tweets:
        likes = tweet["metrics"]["likes"]
        followers = tweet["author"].get("followers_count", 0)

        # Skip low-engagement tweets (likely bots or spam)
        if likes < min_likes:
            continue

        # Skip accounts with very few followers
        if followers < min_followers:
            continue

        # Skip retweets (we want original opinions)
        if tweet["text"].startswith("RT @"):
            continue

        filtered.append(tweet)

    return filtered

quality_tweets = filter_quality_tweets(tweets)
print("Quality tweets: " + str(len(quality_tweets)) + " / " + str(len(tweets)))

Step 2: Keyword-Based Sentiment Scoring

The simplest approach uses keyword matching. It's fast, requires no external APIs, and works surprisingly well for crypto:

PYTHON
# Sentiment keyword dictionaries
BULLISH_WORDS = [
    "bullish", "moon", "pump", "buy", "long", "accumulate",
    "breakout", "rally", "ath", "all time high", "undervalued",
    "loading", "aping", "send it", "wagmi", "diamond hands",
    "higher high", "support holding", "reversal", "bottomed",
    "green candle", "massive", "explosive", "parabolic"
]

BEARISH_WORDS = [
    "bearish", "dump", "sell", "short", "crash", "overvalued",
    "rug", "scam", "dead", "rekt", "ngmi", "paper hands",
    "lower low", "resistance", "breakdown", "topped",
    "red candle", "liquidated", "capitulation", "bleeding"
]

def score_sentiment(text):
    """Score a tweet's sentiment from -1 (bearish) to +1 (bullish)."""
    text_lower = text.lower()
    bull_count = sum(1 for word in BULLISH_WORDS if word in text_lower)
    bear_count = sum(1 for word in BEARISH_WORDS if word in text_lower)

    total = bull_count + bear_count
    if total == 0:
        return 0.0  # neutral

    # Score from -1 to +1
    score = (bull_count - bear_count) / total
    return round(score, 2)

# Test it
print(score_sentiment("BTC looking bullish, breakout incoming"))   # +1.0
print(score_sentiment("This is going to dump hard, sell now"))      # -1.0
print(score_sentiment("BTC at 95k, interesting price action"))      # 0.0

Step 3: LLM-Based Sentiment (Optional)

For more nuanced analysis, use an LLM to classify sentiment. This catches sarcasm, context, and complex opinions that keyword matching misses:

PYTHON
from openai import OpenAI

llm = OpenAI()

def score_sentiment_llm(text):
    """Use LLM for nuanced sentiment scoring."""
    response = llm.chat.completions.create(
        model="gpt-4o-mini",
        messages=[
            {
                "role": "system",
                "content": (
                    "Score the crypto sentiment of this tweet. "
                    "Return ONLY a number from -1.0 (very bearish) "
                    "to +1.0 (very bullish). 0 = neutral."
                )
            },
            {"role": "user", "content": text}
        ],
        max_tokens=10
    )
    try:
        return float(response.choices[0].message.content.strip())
    except ValueError:
        return 0.0

> Tip: The keyword approach is free and fast — use it for real-time monitoring. Reserve LLM scoring for daily summaries or high-stakes analysis where accuracy matters most.

Step 4: Complete Sentiment Analysis Tool

Here's the full working script that ties everything together:

PYTHON
import requests
import os
from datetime import datetime

API_KEY = os.environ["XCROP_API_KEY"]
BASE = "https://xcrop.io/api/v2"
HEADERS = {"Authorization": "Bearer " + API_KEY}

BULLISH_WORDS = [
    "bullish", "moon", "pump", "buy", "long", "accumulate",
    "breakout", "rally", "ath", "undervalued", "loading",
    "wagmi", "diamond hands", "reversal", "bottomed", "parabolic"
]

BEARISH_WORDS = [
    "bearish", "dump", "sell", "short", "crash", "overvalued",
    "rug", "scam", "rekt", "ngmi", "breakdown", "topped",
    "liquidated", "capitulation", "bleeding"
]

def search_tweets(query, count=100):
    response = requests.post(
        BASE + "/search",
        headers=HEADERS,
        json={"query": query, "count": count, "sort": "latest"}
    )
    if response.status_code == 200:
        return response.json()["data"]
    return []

def score_sentiment(text):
    text_lower = text.lower()
    bull = sum(1 for w in BULLISH_WORDS if w in text_lower)
    bear = sum(1 for w in BEARISH_WORDS if w in text_lower)
    total = bull + bear
    if total == 0:
        return 0.0
    return round((bull - bear) / total, 2)

def analyze_token(token):
    """Run full sentiment analysis on a token."""
    print("Analyzing sentiment for " + token + "...")
    print("-" * 50)

    tweets = search_tweets(token, count=100)
    if not tweets:
        print("No tweets found.")
        return

    # Filter quality tweets
    quality = [t for t in tweets if t["metrics"]["likes"] >= 3]
    print("Tweets collected: " + str(len(tweets)))
    print("Quality tweets: " + str(len(quality)))
    print()

    # Score each tweet
    scores = []
    bullish_tweets = []
    bearish_tweets = []

    for tweet in quality:
        score = score_sentiment(tweet["text"])
        scores.append(score)

        if score > 0:
            bullish_tweets.append(tweet)
        elif score < 0:
            bearish_tweets.append(tweet)

    # Calculate aggregates
    if not scores:
        print("No scorable tweets found.")
        return

    avg_score = round(sum(scores) / len(scores), 3)
    bullish_pct = round(len(bullish_tweets) / len(quality) * 100, 1)
    bearish_pct = round(len(bearish_tweets) / len(quality) * 100, 1)
    neutral_pct = round(100 - bullish_pct - bearish_pct, 1)

    # Determine overall sentiment
    if avg_score > 0.2:
        sentiment = "BULLISH"
    elif avg_score < -0.2:
        sentiment = "BEARISH"
    else:
        sentiment = "NEUTRAL"

    # Print report
    print("===== SENTIMENT REPORT: " + token + " =====")
    print("Timestamp: " + datetime.now().strftime("%Y-%m-%d %H:%M UTC"))
    print("Overall: " + sentiment + " (score: " + str(avg_score) + ")")
    print()
    print("Distribution:")
    print("  Bullish: " + str(bullish_pct) + "% (" + str(len(bullish_tweets)) + " tweets)")
    print("  Neutral: " + str(neutral_pct) + "%")
    print("  Bearish: " + str(bearish_pct) + "% (" + str(len(bearish_tweets)) + " tweets)")
    print()

    # Top bullish tweets
    if bullish_tweets:
        bullish_tweets.sort(key=lambda t: t["metrics"]["likes"], reverse=True)
        print("Top Bullish Tweets:")
        for t in bullish_tweets[:3]:
            author = t["author"]["username"]
            likes = t["metrics"]["likes"]
            print("  @" + author + " (" + str(likes) + " likes): " + t["text"][:100])
        print()

    # Top bearish tweets
    if bearish_tweets:
        bearish_tweets.sort(key=lambda t: t["metrics"]["likes"], reverse=True)
        print("Top Bearish Tweets:")
        for t in bearish_tweets[:3]:
            author = t["author"]["username"]
            likes = t["metrics"]["likes"]
            print("  @" + author + " (" + str(likes) + " likes): " + t["text"][:100])

    return {
        "token": token,
        "sentiment": sentiment,
        "score": avg_score,
        "bullish_pct": bullish_pct,
        "bearish_pct": bearish_pct,
        "tweet_count": len(quality)
    }

# Analyze multiple tokens
tokens = ["$BTC", "$ETH", "$SOL"]
results = []
for token in tokens:
    result = analyze_token(token)
    if result:
        results.append(result)
    print()

# Summary table
if results:
    print("=" * 50)
    print("MULTI-TOKEN SENTIMENT SUMMARY")
    print("=" * 50)
    for r in results:
        emoji = "+" if r["score"] > 0 else ""
        print(
            r["token"].ljust(8)
            + r["sentiment"].ljust(10)
            + (emoji + str(r["score"])).ljust(8)
            + "Bull:" + str(r["bullish_pct"]) + "%"
        )

Run it:

BASH
export XCROP_API_KEY="your_key"
python sentiment_analyzer.py

Example output:

===== SENTIMENT REPORT: $BTC =====
Timestamp: 2026-02-12 14:30 UTC
Overall: BULLISH (score: 0.342)

Distribution:
  Bullish: 52.3% (34 tweets)
  Neutral: 33.8%
  Bearish: 13.8% (9 tweets)

Use Cases

Trading Signals

Use sentiment score as one input in a trading strategy. A sustained shift from neutral to bullish across multiple tokens often precedes market moves.

Community Monitoring

Track sentiment for your own project's token. A sudden bearish spike might indicate FUD you need to address.

Alerts on Sentiment Shifts

Combine with a polling loop to get notified when sentiment flips:

PYTHON
import time

previous_sentiment = {}

def check_sentiment_shift(token):
    result = analyze_token(token)
    if not result:
        return

    prev = previous_sentiment.get(token)
    if prev and prev != result["sentiment"]:
        print("[ALERT] " + token + " sentiment shifted: " + prev + " -> " + result["sentiment"])

    previous_sentiment[token] = result["sentiment"]

# Poll every 5 minutes
while True:
    for token in ["$BTC", "$ETH", "$SOL"]:
        check_sentiment_shift(token)
    time.sleep(300)

Credit Usage

Search: 15 credits per tweet returned
Analyzing 100 tweets per token = 1,000 credits per analysis
Monitoring 5 tokens every 5 minutes = ~1.4M credits/day
Recommended: Pro plan ($9.9/mo, 2M credits) for periodic analysis, plus Pay-as-you-go top-up packs (credits never expire) for continuous monitoring

Next Steps

Pair with [KOL tracking](/blog/crypto-kol-tracking-twitter) to weight sentiment by influencer authority
Add historical sentiment tracking with a database for trend analysis
Build a dashboard with charts showing sentiment over time
Explore the [Trending endpoint](/blog/tracking-trending-topics) to discover which tokens to analyze