Working Python code to run sentiment analysis with the Claude API in 2026. Zero-shot classifier, custom sentiment scales, aspect-based analysis, and batch processing patterns.
Claude's language understanding makes it an accurate zero-shot sentiment classifier — no training data or fine-tuning required. This guide covers every sentiment analysis pattern from simple positive/negative to aspect-level JSON extraction.
pip install anthropic
import anthropic
import json
client = anthropic.Anthropic()
def analyze_sentiment(text: str) -> dict:
response = client.messages.create(
model="claude-haiku-4-5-20251001", # cheapest model — sufficient for sentiment
max_tokens=128,
temperature=0, # deterministic output
system=(
"You are a sentiment classifier. "
"Return ONLY valid JSON with this schema: "
'{"sentiment": "positive"|"negative"|"neutral", "confidence": 0.0-1.0}'
),
messages=[{"role": "user", "content": f"Classify the sentiment of: {text}"}],
)
return json.loads(response.content[0].text)
# Example
result = analyze_sentiment("The delivery was fast but the product broke after two days.")
print(result)
# {"sentiment": "negative", "confidence": 0.82}
def analyze_sentiment_detailed(text: str) -> dict:
response = client.messages.create(
model="claude-haiku-4-5-20251001",
max_tokens=256,
temperature=0,
system=(
"You are a sentiment analyst. Return ONLY valid JSON: "
'{"score": 1-5, "label": "very negative"|"negative"|"neutral"|"positive"|"very positive", '
'"confidence": 0.0-1.0, "rationale": "one sentence"}'
),
messages=[{"role": "user", "content": text}],
)
return json.loads(response.content[0].text)
result = analyze_sentiment_detailed(
"I've been using this app for months. It's mostly fine but crashes weekly and support ignores tickets."
)
print(result)
# {"score": 2, "label": "negative", "confidence": 0.88,
# "rationale": "Crashes and unresponsive support outweigh functional adequacy."}
def aspect_sentiment(text: str, aspects: list[str]) -> dict:
aspect_list = ", ".join(aspects)
response = client.messages.create(
model="claude-sonnet-4-6", # better reasoning for multi-aspect
max_tokens=512,
temperature=0,
system=(
"You are an aspect-based sentiment analyst. "
"Return ONLY valid JSON: a dict mapping each aspect to "
'{"sentiment": "positive"|"negative"|"neutral"|"not_mentioned", "evidence": "quote or null"}'
),
messages=[{
"role": "user",
"content": f"Aspects to evaluate: {aspect_list}
Review: {text}"
}],
)
return json.loads(response.content[0].text)
review = (
"The camera takes stunning photos in daylight but struggles at night. "
"Battery lasts two days easily. The price is steep for what you get."
)
result = aspect_sentiment(review, ["camera", "battery", "price", "design"])
# {
# "camera": {"sentiment": "positive", "evidence": "takes stunning photos in daylight"},
# "battery": {"sentiment": "positive", "evidence": "lasts two days easily"},
# "price": {"sentiment": "negative", "evidence": "steep for what you get"},
# "design": {"sentiment": "not_mentioned", "evidence": null}
# }
import anthropic
client = anthropic.Anthropic()
reviews = [
"Great product, fast shipping!",
"Broke after a week. Very disappointed.",
"Average quality, nothing special.",
# ... thousands more
]
# Build batch requests
requests = [
{
"custom_id": f"review-{i}",
"params": {
"model": "claude-haiku-4-5-20251001",
"max_tokens": 64,
"temperature": 0,
"system": 'Return ONLY JSON: {"sentiment": "positive"|"negative"|"neutral"}',
"messages": [{"role": "user", "content": text}],
},
}
for i, text in enumerate(reviews)
]
# Submit batch (50% cheaper than real-time, processes within 24h)
batch = client.messages.batches.create(requests=requests)
print(f"Batch ID: {batch.id}") # poll this later
# Poll for results
import time
while True:
status = client.messages.batches.retrieve(batch.id)
if status.processing_status == "ended":
break
time.sleep(60)
results = {}
for result in client.messages.batches.results(batch.id):
if result.result.type == "succeeded":
data = json.loads(result.result.message.content[0].text)
results[result.custom_id] = data["sentiment"]
print(results)
def financial_sentiment(headline: str) -> dict:
"""Classify financial news headlines as bullish / bearish / neutral."""
response = client.messages.create(
model="claude-haiku-4-5-20251001",
max_tokens=64,
temperature=0,
system=(
"You are a financial news sentiment analyst. "
'Return ONLY JSON: {"sentiment": "bullish"|"bearish"|"neutral", "confidence": 0.0-1.0}'
),
messages=[{"role": "user", "content": headline}],
)
return json.loads(response.content[0].text)
print(financial_sentiment("Fed signals rate pause amid cooling inflation"))
# {"sentiment": "bullish", "confidence": 0.79}
| Method | Accuracy (nuanced) | Cost | Speed | Best for |
|---|---|---|---|---|
| Claude Haiku | High — handles irony, context, domain jargon | $0.25/M tokens | ~200ms/call | Reviews, support tickets, financial news |
| VADER | Low-medium — fails on sarcasm | Free | <1ms | Social media, simple positive/negative volume |
| TextBlob | Low — English only, lexicon-based | Free | <1ms | Basic prototyping only |
| Fine-tuned BERT | High in-domain, low out-of-domain | GPU cost | ~20ms (GPU) | Single domain with >10K labeled examples |
Use the Claude API Cost Calculator to estimate cost at your review volume. For a general-purpose classifier (multi-class, not just sentiment), see the text classification guide. For bulk document summarization, see the summarization guide.