A customer complains on Twitter. Your social-listening tool catches it. Your warehouse connects it to their $200K account in Salesforce. That's the difference between a tweet and a churn signal.
Most companies either don't do social listening or do it in a siloed tool that nobody checks. The ones that do it well treat social data the same way they treat any other data source: it lands in the warehouse, gets enriched, and joins everything else.
What social listening actually captures
At its core, social listening monitors public conversations about your brand, competitors, and industry across:
- Social platforms — Twitter/X, LinkedIn, Facebook, Instagram, TikTok
- Forums — Reddit, Quora, Stack Overflow, niche communities
- Review sites — G2, TrustRadius, Capterra, Glassdoor
- News — press articles, blog posts, podcasts (transcribed)
- Comments — YouTube, blog comments, app store reviews
For each mention, you capture:
- Content — what was said
- Sentiment — positive, negative, neutral (model-scored)
- Author — who said it (when identifiable)
- Channel — where it was said
- Reach — estimated audience size
- Engagement — likes, shares, replies, comments
- Classification — earned, owned, or paid media
The pipeline
Social APIs / Scrapers ──→ Cloud Function ──→ BigQuery
Review site APIs ──→ Cloud Function ──→ BigQuery
News API ──→ Cloud Function ──→ BigQuery
│
▼
dbt models (clean, classify, score sentiment)
│
▼
Dashboard + Alerts + CRM enrichment
Staging: normalize mentions
-- models/staging/stg_social__mentions.sql
SELECT
mention_id,
platform,
author_name,
author_handle,
content_text,
published_at,
url AS mention_url,
estimated_reach,
engagement_count,
sentiment_score, -- from NLP model: -1 to 1
CASE
WHEN sentiment_score > 0.3 THEN 'positive'
WHEN sentiment_score < -0.3 THEN 'negative'
ELSE 'neutral'
END AS sentiment_label,
CASE
WHEN LOWER(content_text) LIKE '%@warehows%'
OR LOWER(author_handle) = 'warehows' THEN 'owned'
WHEN is_ad = TRUE THEN 'paid'
ELSE 'earned'
END AS media_type
FROM {{ source('social', 'raw_mentions') }}
WHERE content_text IS NOT NULLEnrichment: connect to CRM
This is where social listening becomes actionable:
-- models/intermediate/int_social__crm_enriched.sql
SELECT
m.*,
c.contact_id,
c.company_name,
d.deal_id,
d.deal_amount,
d.deal_stage,
CASE
WHEN d.deal_amount > 100000 AND m.sentiment_label = 'negative'
THEN 'HIGH_PRIORITY'
WHEN d.deal_amount > 50000 AND m.sentiment_label = 'negative'
THEN 'MEDIUM_PRIORITY'
ELSE 'STANDARD'
END AS alert_priority
FROM {{ ref('stg_social__mentions') }} m
LEFT JOIN {{ ref('stg_hubspot__contacts') }} c
ON LOWER(m.author_handle) = LOWER(c.twitter_handle)
OR LOWER(m.author_name) = LOWER(CONCAT(c.first_name, ' ', c.last_name))
LEFT JOIN {{ ref('stg_hubspot__deals') }} d
ON c.contact_id = d.contact_id
AND d.deal_stage NOT IN ('closed_lost', 'closed_won')When a negative mention comes from someone with an open $200K deal, that's not a social media problem — it's a revenue problem. Route it to the account owner immediately.
Mart: aggregate for reporting
-- models/marts/mart_social_overview.sql
SELECT
DATE_TRUNC(published_at, WEEK) AS week,
platform,
media_type,
sentiment_label,
COUNT(*) AS mentions,
SUM(estimated_reach) AS total_reach,
SUM(engagement_count) AS total_engagement,
COUNT(CASE WHEN alert_priority = 'HIGH_PRIORITY' THEN 1 END) AS high_priority_alerts
FROM {{ ref('int_social__crm_enriched') }}
GROUP BY 1, 2, 3, 4What to actually do with it
Social listening data is useful in four ways:
1. Churn prevention
Negative mentions from existing customers, especially high-value ones, are early churn signals. Most CRM systems have no visibility into what customers say publicly. The warehouse bridges that gap.
Set up an alert: when a customer with an active deal or subscription posts something negative, notify the account owner within the hour.
2. Product feedback at scale
We built this for a client processing 50K+ customer reviews. Individual reviews are anecdotal. 50K reviews, classified by topic and sentiment, are a product roadmap.
-- What are customers complaining about most?
SELECT
topic_cluster, -- LLM-classified topic
COUNT(*) AS mentions,
AVG(sentiment_score) AS avg_sentiment,
COUNT(CASE WHEN sentiment_label = 'negative' THEN 1 END) AS negative_count
FROM {{ ref('int_social__classified') }}
WHERE published_at >= CURRENT_DATE - 90
GROUP BY 1
ORDER BY negative_count DESC3. Competitive monitoring
Track competitor mentions alongside your own. Rising positive sentiment for a competitor + declining sentiment for you = a problem that won't show up in your revenue numbers for 6 months.
4. Campaign measurement
Did that brand campaign generate conversation? Social listening gives you earned media impact — mentions, reach, sentiment — that paid media dashboards can't capture.
The honest take
Social listening has real limitations:
- Not every conversation is public. Slack channels, email threads, and phone calls are where most B2B decisions happen. Social listening only captures the visible tip.
- Sentiment models are imperfect. Sarcasm, industry jargon, and context-dependent language confuse even good NLP models. Expect 70-80% accuracy, not 95%.
- Volume varies by industry. B2C brands with consumer audiences get thousands of mentions. B2B niche companies might get 10 a month. If your volume is low, don't over-index on individual mentions.
- Vanity metrics are tempting. Total mentions and reach feel impressive but mean nothing without sentiment and business context. Ten negative mentions from customers matter more than 1,000 neutral mentions from bots.
The value isn't in the volume of data. It's in connecting social signals to business outcomes — revenue, churn, pipeline. That connection only exists in your warehouse.
We build social-listening pipelines that connect public conversations to CRM data, deal values, and customer health scores — so a tweet becomes a signal, not noise. Book a discovery call if your social data is sitting in a tool nobody checks.