To integrate Replit with Sprout Social, create an API application in the Sprout Social developer portal to get OAuth 2.0 credentials, store them in Replit Secrets (lock icon π), and call the Sprout Social API v1 from your Python or Node.js server to publish content, retrieve engagement data, and pull social analytics reports. Use Autoscale deployment for publishing automation workflows.
Why Connect Replit to Sprout Social?
Sprout Social sits at the intersection of social publishing, engagement management, and analytics β making it the preferred platform for marketing teams that need all three in one place. Its API exposes the core capabilities: managing profiles across Twitter, Facebook, Instagram, LinkedIn, and Pinterest, publishing and scheduling posts, retrieving incoming messages for engagement workflows, and pulling detailed analytics including post performance, audience growth, and competitor benchmarking.
Connecting your Replit app to Sprout Social enables integration patterns that the native Sprout interface does not support: triggering post creation from product events, pulling social analytics into a custom data warehouse, routing incoming messages to your CRM for customer service follow-up, and building custom reporting dashboards tailored to your specific KPIs. These are the use cases that enterprise social teams pay for in expensive third-party integrations, which you can build directly with the Sprout API.
Replit's Secrets system (lock icon π in the sidebar) keeps your Sprout Social access token encrypted and accessible only to server-side code. The Sprout Social API access token grants full access to your connected social profiles including the ability to post content β it must never appear in client-side JavaScript or be shared publicly. Store it in Replit Secrets and access it only from your Replit backend server.
Integration method
You connect Replit to Sprout Social by registering an application in the Sprout Social developer portal to get OAuth 2.0 credentials, storing the access token in Replit Secrets, and calling the Sprout Social API v1 from your server-side Python or Node.js code. The Sprout Social API uses Bearer token authentication. The base URL is https://api.sproutsocial.com/v1.
Prerequisites
- A Replit account with a Python or Node.js project created
- A Sprout Social account on a plan that includes API access (Professional or Advanced)
- Access to the Sprout Social developer portal at developer.sproutsocial.com
- At least one social profile connected to your Sprout Social account
- Python 3.10+ or Node.js 18+ (both available on Replit by default)
Step-by-step guide
Create a Sprout Social App and Get an Access Token
Create a Sprout Social App and Get an Access Token
Visit developer.sproutsocial.com and sign in with your Sprout Social account. Navigate to 'My Apps' and click 'Create New Application'. Fill in the app name, description, and website URL. For the callback URL, enter your deployed Replit URL plus a callback path (e.g., https://your-app.replit.app/oauth/callback). After creating the app, Sprout Social provides a Client ID and Client Secret. The OAuth 2.0 flow for Sprout Social uses a standard authorization code flow. You can generate an access token directly from the developer portal for personal or testing use β look for the 'Access Token' section on your app's detail page and click 'Generate Token'. This bypasses the full OAuth flow and gives you a long-lived token suitable for server-to-server integrations. Copy the access token. Open your Replit project and click the lock icon π in the left sidebar. Add the following Secrets: - SPROUT_ACCESS_TOKEN: your generated access token - SPROUT_CLIENT_ID: your app client ID (needed for OAuth flows) - SPROUT_CLIENT_SECRET: your app client secret The Sprout Social API base URL is https://api.sproutsocial.com/v1. All requests use Bearer token authentication in the Authorization header.
Pro tip: Sprout Social API access requires the Professional or Advanced plan β the Standard plan does not include API access. Check your plan in Sprout Social under Account Settings > Subscription to confirm API access is available.
Expected result: Your Sprout Social access token and credentials are stored in Replit Secrets. A test call to GET /profile returns your connected social profiles.
Retrieve Profiles and Analytics Data in Python
Retrieve Profiles and Analytics Data in Python
The Sprout Social API v1 uses standard Bearer token authentication β include your access token in the Authorization header for every request. The base URL is https://api.sproutsocial.com/v1. To identify which profiles and networks you have connected, start with GET /profile which returns all customer profiles linked to your Sprout Social account. Each profile has a customer_profile_id that you use in subsequent API calls. The Analytics API provides post-level and profile-level performance metrics. Profile analytics use GET /metrics/profile/{id}/{metric} where the metric can be impressions, engagements, followers, or other network-specific metrics. The reporting endpoints accept date range parameters and return time series data. The Python code below demonstrates how to list connected profiles, fetch profile-level analytics for a date range, and retrieve the top-performing posts by engagement. The response format is consistent JSON with data and paging objects.
1import os2import requests3from datetime import datetime, timedelta4from typing import Optional56ACCESS_TOKEN = os.environ["SPROUT_ACCESS_TOKEN"]7BASE_URL = "https://api.sproutsocial.com/v1"89HEADERS = {10 "Authorization": f"Bearer {ACCESS_TOKEN}",11 "Content-Type": "application/json"12}1314def get_profiles() -> list:15 """Get all customer profiles connected to the Sprout Social account."""16 response = requests.get(f"{BASE_URL}/profile", headers=HEADERS)17 response.raise_for_status()18 data = response.json()19 return data.get("data", {}).get("customer_profiles", [])2021def get_profile_analytics(profile_id: str, metrics: list,22 start_date: str, end_date: str) -> dict:23 """24 Get analytics for a specific profile.25 metrics: list of metric names (e.g., ['impressions', 'engagements', 'followers_gained'])26 Dates in YYYY-MM-DD format.27 """28 params = {29 "start": f"{start_date}T00:00:00",30 "end": f"{end_date}T23:59:59",31 "fields": ",".join(metrics)32 }33 response = requests.get(34 f"{BASE_URL}/metrics/customer/{profile_id}",35 params=params,36 headers=HEADERS37 )38 response.raise_for_status()39 return response.json()4041def get_sent_posts(profile_ids: list, limit: int = 20) -> list:42 """Retrieve recently published posts across specified profiles."""43 params = {44 "customer_profile_ids[]": profile_ids,45 "count": limit,46 "statuses[]": ["sent"]47 }48 response = requests.get(f"{BASE_URL}/message/", params=params, headers=HEADERS)49 response.raise_for_status()50 return response.json().get("data", {}).get("messages", [])5152def get_inbox_messages(profile_ids: list = None,53 status: str = "all", limit: int = 25) -> list:54 """Fetch incoming messages from the Sprout Social inbox."""55 params = {56 "count": limit,57 "status": status # 'new', 'in_progress', 'completed', 'all'58 }59 if profile_ids:60 params["customer_profile_ids[]"] = profile_ids6162 response = requests.get(f"{BASE_URL}/inbox/", params=params, headers=HEADERS)63 response.raise_for_status()64 return response.json().get("data", {}).get("messages", [])6566# Example usage67if __name__ == "__main__":68 profiles = get_profiles()69 print(f"Connected profiles: {len(profiles)}")70 for profile in profiles:71 name = profile.get('name_for_display', 'Unknown')72 network = profile.get('network_type', 'unknown')73 profile_id = profile.get('customer_profile_id')74 print(f" {name} ({network}): ID {profile_id}")7576 if profiles:77 end_date = datetime.now().strftime("%Y-%m-%d")78 start_date = (datetime.now() - timedelta(days=7)).strftime("%Y-%m-%d")79 profile_id = profiles[0]['customer_profile_id']80 print(f"\nFetching 7-day analytics for profile {profile_id}...")81 analytics = get_profile_analytics(82 profile_id,83 ['impressions', 'engagements', 'followers_gained'],84 start_date,85 end_date86 )87 print(f"Analytics: {analytics}")Pro tip: Sprout Social profile IDs (customer_profile_ids) are long integers. Always fetch them dynamically via GET /profile rather than hardcoding them β profile IDs can change if a social account is disconnected and reconnected.
Expected result: Running the script prints all connected social profiles with their network types and IDs, and fetches 7-day analytics for the first profile.
Publish and Schedule Posts with Node.js
Publish and Schedule Posts with Node.js
The Sprout Social API supports creating messages (posts) that can be published immediately or scheduled for a future time. The message creation endpoint is POST /message/ and accepts a payload with the message text, the target profile IDs, and an optional send_time for scheduled posting. Each message must specify the customer_profile_ids (the Sprout Social profile IDs you want to post to), the message text, and an optional image URL for image posts. The API returns the created message with a message_id that you can use to check status or update the post before it is published. The Express server below exposes endpoints for immediate publishing and scheduled posting. It also includes a scheduling helper that converts human-readable times to the ISO 8601 format that Sprout Social expects. Install dependencies with 'npm install express axios' in the Replit shell.
1const express = require('express');2const axios = require('axios');34const app = express();5app.use(express.json());67const ACCESS_TOKEN = process.env.SPROUT_ACCESS_TOKEN;8const BASE_URL = 'https://api.sproutsocial.com/v1';910const sprout = axios.create({11 baseURL: BASE_URL,12 headers: {13 'Authorization': `Bearer ${ACCESS_TOKEN}`,14 'Content-Type': 'application/json'15 }16});1718// Get all connected profiles19app.get('/profiles', async (req, res) => {20 try {21 const { data } = await sprout.get('/profile');22 const profiles = data.data?.customer_profiles || [];23 const simplified = profiles.map(p => ({24 id: p.customer_profile_id,25 name: p.name_for_display,26 network: p.network_type27 }));28 res.json(simplified);29 } catch (err) {30 console.error('Profiles error:', err.response?.data || err.message);31 res.status(500).json({ error: err.message });32 }33});3435// Publish a post immediately or scheduled36app.post('/publish', async (req, res) => {37 const { profileIds, message, imageUrl, scheduledAt } = req.body;38 if (!profileIds || !message) {39 return res.status(400).json({ error: 'profileIds and message are required' });40 }4142 try {43 const payload = {44 customer_profile_ids: Array.isArray(profileIds) ? profileIds : [profileIds],45 message_content: [46 {47 type: 'text',48 text: message49 }50 ]51 };5253 if (imageUrl) {54 payload.message_content.push({55 type: 'image',56 url: imageUrl57 });58 }5960 if (scheduledAt) {61 // scheduledAt should be ISO 8601: 2025-04-01T14:00:00Z62 payload.scheduled_send_time = scheduledAt;63 }6465 const { data } = await sprout.post('/message/', payload);66 const messageId = data.data?.id;67 res.json({ success: true, messageId, scheduled: !!scheduledAt });68 } catch (err) {69 console.error('Publish error:', err.response?.data || err.message);70 res.status(500).json({ error: err.message, detail: err.response?.data });71 }72});7374// Get analytics for a profile75app.get('/analytics/:profileId', async (req, res) => {76 const { start, end } = req.query;77 const endDate = end || new Date().toISOString().split('T')[0];78 const startDate = start || new Date(Date.now() - 7 * 86400000).toISOString().split('T')[0];7980 try {81 const { data } = await sprout.get(82 `/metrics/customer/${req.params.profileId}`,83 {84 params: {85 start: `${startDate}T00:00:00`,86 end: `${endDate}T23:59:59`,87 fields: 'impressions,engagements,followers_gained'88 }89 }90 );91 res.json(data);92 } catch (err) {93 console.error('Analytics error:', err.response?.data || err.message);94 res.status(500).json({ error: err.message });95 }96});9798app.get('/health', (req, res) => res.json({ status: 'ok' }));99100app.listen(3000, '0.0.0.0', () => {101 console.log('Sprout Social integration server running on port 3000');102});Pro tip: Sprout Social's scheduled_send_time must be in ISO 8601 format with timezone (e.g., '2025-04-01T14:00:00Z'). Publishing immediately requires omitting the scheduled_send_time field entirely β do not pass null or an empty string.
Expected result: The server starts and GET /profiles returns your connected social profiles. POST /publish with profileIds and message creates a post in Sprout Social's outbox.
Deploy and Set Up Webhook Subscriptions
Deploy and Set Up Webhook Subscriptions
Sprout Social supports webhook subscriptions that notify your Replit server when specific events occur β a new message arrives in the inbox, a post is published, a message is tagged, or a conversation status changes. Webhooks enable real-time integrations without polling the API continuously. To configure webhooks, go to your Sprout Social developer application settings and add a webhook endpoint URL under the 'Webhooks' section. Select the event types you want to receive. Sprout Social sends a POST request to your endpoint with the event data in JSON format. Your endpoint must respond with HTTP 200 within 5 seconds. Deploy your Replit app before registering the webhook URL. Click 'Deploy' and choose Autoscale for publishing automation services, or Reserved VM for a dedicated inbox monitoring service that cannot afford cold-start delays. After deployment, copy the stable replit.app URL and register it as the webhook endpoint in your Sprout Social developer app settings.
1from flask import Flask, request, jsonify2import os3import hmac4import hashlib56app = Flask(__name__)7WEBHOOK_SECRET = os.environ.get("SPROUT_WEBHOOK_SECRET", "")89def verify_sprout_signature(payload: bytes, signature: str) -> bool:10 """Verify the Sprout Social webhook signature."""11 if not WEBHOOK_SECRET or not signature:12 return True # Skip if no secret configured13 expected = hmac.new(14 WEBHOOK_SECRET.encode(),15 payload,16 hashlib.sha25617 ).hexdigest()18 return hmac.compare_digest(f"sha256={expected}", signature)1920@app.route('/sprout/webhook', methods=['POST'])21def sprout_webhook():22 signature = request.headers.get('X-Sprout-Signature', '')23 if not verify_sprout_signature(request.data, signature):24 return jsonify({'error': 'Invalid signature'}), 4032526 data = request.get_json(force=True)27 if not data:28 return jsonify({'error': 'No data'}), 4002930 event_type = data.get('event_type', 'unknown')31 print(f"Sprout webhook: {event_type}")3233 if event_type == 'message.inbound.new':34 message = data.get('message', {})35 sender = message.get('sender', {}).get('name', 'Anonymous')36 network = message.get('network_type', 'unknown')37 text = message.get('text', '')38 print(f"New message from {sender} on {network}: {text[:100]}")39 # Route to CRM, create support ticket, notify team4041 elif event_type == 'message.sent':42 message = data.get('message', {})43 print(f"Post published: {message.get('id')}")4445 return jsonify({'status': 'received'}), 2004647@app.route('/health', methods=['GET'])48def health():49 return jsonify({'status': 'ok'}), 2005051if __name__ == '__main__':52 app.run(host='0.0.0.0', port=3000)Pro tip: Sprout Social webhook payloads can be large when they include full message content and user profile data. Log only the fields you need rather than the entire payload to keep your Replit deployment logs readable.
Expected result: Your deployed Replit server receives Sprout Social webhook events and logs the event type. The /health endpoint returns 200 to confirm the server is live.
Common use cases
Content Calendar Automation from Product Events
When your product has a new release, a major customer milestone, or a company announcement, your Replit server creates a draft post in Sprout Social for each connected social network and schedules them for the optimal posting times. Marketing teams review and approve posts in Sprout without manually writing content for each platform.
Build a Flask endpoint that receives product announcement data (title, description, image URL) and creates a scheduled post in Sprout Social for Twitter and LinkedIn using the SPROUT_ACCESS_TOKEN from Replit Secrets, scheduled for the next business day at 9 AM.
Copy this prompt to try it in Replit
Social Engagement CRM Integration
A Replit server polls the Sprout Social inbox API for incoming messages and mentions, matches them to existing customer records in your CRM by username or email, and creates support tickets or conversation threads when a new social message arrives. This routes social media customer service through your existing support workflow.
Write a Node.js script that fetches unread messages from the Sprout Social inbox, filters for messages with negative sentiment tags, and creates a HubSpot support ticket for each one including the original social message text and customer profile URL.
Copy this prompt to try it in Replit
Weekly Cross-Channel Analytics Report
A Replit Python script runs every Monday morning and pulls the previous week's social analytics from all connected Sprout Social profiles: total impressions, engagement rate, follower growth, and best-performing posts. The script formats the data into a structured report and sends it to a Slack channel or email distribution list.
Create a Python script that fetches Sprout Social profile analytics for the past 7 days, calculates total impressions and average engagement rate across all connected networks, and formats the results as a weekly summary report.
Copy this prompt to try it in Replit
Troubleshooting
API returns 401 Unauthorized on all requests
Cause: The Bearer token in the Authorization header is invalid, expired, or was revoked in the Sprout Social developer portal. Tokens generated from the developer portal are long-lived but can be revoked manually.
Solution: Verify the SPROUT_ACCESS_TOKEN in Replit Secrets matches the token shown in your Sprout Social developer app settings. If the token was revoked, generate a new one from the developer portal and update the Secret. Test with a simple GET /profile call first.
1# Python: quick auth test2import requests, os3response = requests.get(4 'https://api.sproutsocial.com/v1/profile',5 headers={'Authorization': f"Bearer {os.environ['SPROUT_ACCESS_TOKEN']}"}6)7print(response.status_code, response.text[:300])POST /message/ returns 400 with 'invalid profile IDs'
Cause: The customer_profile_ids in the post payload do not match any profiles connected to the account, or the IDs were hardcoded and the social accounts were disconnected and reconnected (which generates new IDs).
Solution: Always fetch profile IDs dynamically via GET /profile before creating messages. Store them in memory or a database rather than hardcoding them. Profile IDs change when social accounts are disconnected and reconnected.
1# Python: fetch and use profile IDs dynamically2profiles = get_profiles()3profile_ids = [p['customer_profile_id'] for p in profiles]4print(f"Publishing to profiles: {profile_ids}")Analytics endpoint returns empty data for recent dates
Cause: Sprout Social analytics typically have a 24-48 hour lag. Data for today or yesterday may not be available yet. Additionally, analytics are only available for dates after the social profiles were connected to Sprout Social.
Solution: Use a date range ending 2 days before today to ensure data availability. For real-time metrics, check if Sprout Social offers a real-time dashboard API β historical analytics endpoints always have a lag.
1from datetime import datetime, timedelta2# Use data ending 2 days ago for availability3end_date = (datetime.now() - timedelta(days=2)).strftime('%Y-%m-%d')4start_date = (datetime.now() - timedelta(days=9)).strftime('%Y-%m-%d')Webhook is registered but no events are being received
Cause: The webhook URL points to a development Replit session that is not active, or the webhook endpoint is returning non-200 responses that caused Sprout to disable it.
Solution: Deploy your app to get a stable URL and re-register the webhook with the deployed URL. Check your deployment logs for errors that would cause non-200 responses. Sprout Social may disable webhooks after repeated delivery failures.
Best practices
- Store SPROUT_ACCESS_TOKEN in Replit Secrets (lock icon π) β this token can publish to all your connected social accounts and must never appear in client-side code.
- Fetch customer_profile_ids dynamically via GET /profile rather than hardcoding them β profile IDs change when social accounts are disconnected and reconnected.
- Request the minimum set of scopes when creating your Sprout Social app β use read-only scopes for analytics-only integrations to reduce risk if the token is compromised.
- Use scheduled_send_time for non-urgent posts to allow Sprout Social's optimal timing recommendations to take effect β do not publish everything immediately.
- Handle the 24-48 hour analytics lag by using date ranges that end at least 2 days before today for analytics queries.
- Deploy your Replit app before registering webhook endpoints with Sprout Social β stable deployment URLs prevent dead webhook registrations.
- Return HTTP 200 from your webhook handler within 5 seconds, even if internal processing takes longer β use async processing and acknowledge immediately.
- Use Autoscale deployment for publishing automation and Autoscale or Reserved VM for inbox monitoring, depending on how critical real-time response is for your workflow.
Alternatives
Hootsuite covers a broader range of social networks and has more extensive scheduling features, making it better for teams that primarily need cross-platform scheduling rather than deep analytics.
Later is a better alternative if your focus is visual content planning and Instagram-first scheduling, with a simpler interface and lower cost than Sprout Social's analytics-heavy platform.
SocialBee is better for content recycling and category-based posting strategies at a lower price point, while Sprout Social's strength is deeper analytics and enterprise-grade listening tools.
Frequently asked questions
How do I store my Sprout Social access token in Replit?
Click the lock icon π in the left sidebar of your Replit project. Add SPROUT_ACCESS_TOKEN with your access token from the Sprout Social developer portal. Access it in Python with os.environ['SPROUT_ACCESS_TOKEN'] or in Node.js with process.env.SPROUT_ACCESS_TOKEN. Never include this token in client-side JavaScript.
Does Replit work with Sprout Social on the free plan?
No. Sprout Social API access requires the Professional or Advanced plan β the Standard plan does not include API access. Check your plan in Sprout Social under Account Settings > Subscription. Replit's free tier supports outbound API calls once you have API access, but always-on deployment for webhooks requires Replit's paid plan.
How do I find my Sprout Social profile IDs?
Call GET https://api.sproutsocial.com/v1/profile with your Bearer token. The response includes all connected social profiles with their customer_profile_id, name, and network type. Use these IDs when publishing posts or fetching analytics β do not hardcode them as they can change when social accounts are reconnected.
Can I schedule social media posts via the Sprout Social API from Replit?
Yes. Add a scheduled_send_time field to the POST /message/ payload in ISO 8601 format (e.g., '2025-04-01T14:00:00Z'). The post will appear in Sprout Social's publishing calendar and be sent at the specified time. Omit scheduled_send_time entirely to publish immediately.
How do I receive Sprout Social inbox messages in my Replit app?
Register a webhook endpoint in your Sprout Social developer app settings pointing to your deployed Replit URL. Select 'message.inbound.new' as the event type. Sprout Social will POST to your endpoint when new messages arrive in the inbox. You can also poll GET /inbox/ on a schedule if webhooks are not available on your plan.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation