How to Automate Social Proof Screenshots for Your Website
Social proof drives conversions. Testimonials, reviews, tweet mentions, and case study metrics all signal trust. But keeping those screenshots fresh and accurate is a nightmare when done manually.
In this guide, you'll learn how to automate social proof screenshots using an API — capturing live reviews, tweets, and testimonials programmatically and displaying them on your site without lifting a finger.
Why Automate Social Proof?
Manual screenshots go stale fast. A glowing tweet from six months ago might be deleted. A 4.8-star rating might now be 4.9. Manually updating these images is tedious and error-prone.
Automated screenshots solve this by:
- Staying current — capture live pages on a schedule
- Scaling effortlessly — handle dozens of sources without manual work
- Looking consistent — same dimensions, quality, and style every time
- Being verifiable — link back to the original source
Types of Social Proof You Can Capture
Before diving into the technical implementation, consider what's worth capturing:
| Source | What to Capture | Update Frequency | |--------|----------------|-----------------| | Twitter/X mentions | Individual tweets praising your product | Daily | | G2/Capterra reviews | Star ratings and review snippets | Weekly | | Google Reviews | Business rating and recent reviews | Weekly | | GitHub stars | Repository star count and trending status | Daily | | Product Hunt | Launch day results and upvotes | Once (after launch) | | App Store ratings | Rating badge and review highlights | Weekly |
Setting Up Automated Captures with ToolCenter API
The ToolCenter Screenshot API makes this straightforward. Here's how to capture a tweet as social proof:
Capturing a Tweet
curl -X POST "https://toolcenter.dev/api/v1/screenshot" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://twitter.com/user/status/123456789",
"width": 550,
"height": 400,
"format": "png",
"wait_for": ".tweet-text",
"hide_cookie_banners": true
}'
The wait_for parameter ensures the tweet content is fully rendered before capture. The hide_cookie_banners option removes distracting consent popups.
Capturing a Google Reviews Widget
const axios = require('axios');
const fs = require('fs');
async function captureGoogleReviews(placeUrl) {
const response = await axios.post('https://toolcenter.dev/api/v1/screenshot', {
url: placeUrl,
width: 800,
height: 600,
format: 'png',
wait_for: '.review-dialog-list',
delay: 2000 // Allow reviews to load
}, {
headers: {
'Authorization': 'Bearer YOUR_API_KEY',
'Content-Type': 'application/json'
},
responseType: 'arraybuffer'
});
fs.writeFileSync('google-reviews.png', response.data);
console.log('Reviews screenshot saved');
}
Capturing a G2 Rating Badge
import requests
def capture_g2_badge(product_slug):
"""Capture G2 review badge for a product."""
response = requests.post(
'https://toolcenter.dev/api/v1/screenshot',
headers={
'Authorization': 'Bearer YOUR_API_KEY',
'Content-Type': 'application/json'
},
json={
'url': f'https://www.g2.com/products/{product_slug}/reviews',
'selector': '.star-wrapper', # Capture just the rating section
'format': 'png',
'retina': True # 2x resolution for crisp display
}
)
if response.status_code == 200:
with open(f'{product_slug}-g2-badge.png', 'wb') as f:
f.write(response.content)
print(f'G2 badge saved for {product_slug}')
else:
print(f'Error: {response.status_code}')
Building an Automated Pipeline
For production use, you'll want a scheduled pipeline that refreshes screenshots automatically. Here's a complete Node.js solution:
const axios = require('axios');
const fs = require('fs').promises;
const path = require('path');
const API_BASE = 'https://toolcenter.dev/api/v1';
const API_KEY = process.env.TOOLCENTER_API_KEY;
// Define your social proof sources
const sources = [
{
name: 'tweet-testimonial-ceo',
url: 'https://twitter.com/happycustomer/status/123456789',
width: 550,
height: 350,
wait_for: '[data-testid="tweetText"]',
schedule: 'daily'
},
{
name: 'g2-rating',
url: 'https://www.g2.com/products/yourproduct/reviews',
selector: '.paper--box',
width: 400,
height: 300,
schedule: 'weekly'
},
{
name: 'github-stars',
url: 'https://github.com/yourorg/yourrepo',
selector: '.starring-container',
width: 300,
height: 80,
schedule: 'daily'
},
{
name: 'producthunt-badge',
url: 'https://www.producthunt.com/posts/yourproduct',
selector: '.kittyBadge',
width: 250,
height: 54,
schedule: 'once'
}
];
async function captureScreenshot(source) {
try {
const payload = {
url: source.url,
width: source.width,
height: source.height,
format: 'png',
hide_cookie_banners: true
};
if (source.selector) payload.selector = source.selector;
if (source.wait_for) payload.wait_for = source.wait_for;
const response = await axios.post(`${API_BASE}/screenshot`, payload, {
headers: {
'Authorization': `Bearer ${API_KEY}`,
'Content-Type': 'application/json'
},
responseType: 'arraybuffer',
timeout: 30000
});
const outputPath = path.join('./social-proof', `${source.name}.png`);
await fs.writeFile(outputPath, response.data);
console.log(`✅ Captured: ${source.name}`);
return true;
} catch (error) {
console.error(`❌ Failed: ${source.name} — ${error.message}`);
return false;
}
}
async function refreshAll() {
await fs.mkdir('./social-proof', { recursive: true });
const results = await Promise.all(
sources.map(source => captureScreenshot(source))
);
const succeeded = results.filter(Boolean).length;
console.log(`\nRefreshed ${succeeded}/${sources.length} screenshots`);
}
refreshAll();
Scheduling with Cron
Run this pipeline on a schedule using cron:
# Refresh social proof screenshots daily at 6 AM
0 6 * * * cd /var/www/yoursite && node capture-social-proof.js >> /var/log/social-proof.log 2>&1
Or integrate it into your CI/CD pipeline so screenshots refresh on every deployment.
Displaying Social Proof on Your Site
Once captured, display the screenshots with proper attribution:
<section class="social-proof">
<h2>What People Are Saying</h2>
<div class="proof-grid">
<a href="https://twitter.com/user/status/123"
target="_blank"
rel="noopener"
class="proof-card">
<img src="/social-proof/tweet-testimonial-ceo.png"
alt="Customer testimonial on Twitter"
loading="lazy"
width="550"
height="350" />
<span class="proof-source">View on Twitter →</span>
</a>
<a href="https://www.g2.com/products/yourproduct"
target="_blank"
rel="noopener"
class="proof-card">
<img src="/social-proof/g2-rating.png"
alt="G2 rating and reviews"
loading="lazy"
width="400"
height="300" />
<span class="proof-source">See all reviews on G2 →</span>
</a>
</div>
</section>
<style>
.proof-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 2rem;
padding: 2rem 0;
}
.proof-card {
border: 1px solid #e2e8f0;
border-radius: 12px;
overflow: hidden;
transition: transform 0.2s, box-shadow 0.2s;
text-decoration: none;
}
.proof-card:hover {
transform: translateY(-2px);
box-shadow: 0 8px 25px rgba(0,0,0,0.1);
}
.proof-card img {
width: 100%;
height: auto;
}
.proof-source {
display: block;
padding: 0.75rem 1rem;
color: #4a6cf7;
font-size: 0.875rem;
font-weight: 500;
}
</style>
Advanced: Freshness Indicators
Add timestamps to show visitors that your proof is current:
async function captureWithMetadata(source) {
const success = await captureScreenshot(source);
if (success) {
const metadata = {
name: source.name,
captured_at: new Date().toISOString(),
source_url: source.url,
file: `${source.name}.png`
};
const metaPath = path.join('./social-proof', 'metadata.json');
let existing = [];
try {
existing = JSON.parse(await fs.readFile(metaPath, 'utf-8'));
} catch (e) { /* first run */ }
const index = existing.findIndex(m => m.name === source.name);
if (index >= 0) existing[index] = metadata;
else existing.push(metadata);
await fs.writeFile(metaPath, JSON.stringify(existing, null, 2));
}
}
Then render the timestamp on your page:
// Show "Updated 2 hours ago" next to each screenshot
function getTimeAgo(dateStr) {
const seconds = Math.floor((Date.now() - new Date(dateStr)) / 1000);
if (seconds < 3600) return `${Math.floor(seconds / 60)} minutes ago`;
if (seconds < 86400) return `${Math.floor(seconds / 3600)} hours ago`;
return `${Math.floor(seconds / 86400)} days ago`;
}
Best Practices
- Always link to the original source — screenshots without attribution look fake
- Use element selectors when possible to capture just the relevant portion, not the full page
- Set appropriate dimensions — oversized screenshots waste bandwidth
- Enable retina mode for crisp display on high-DPI screens
- Handle failures gracefully — if a capture fails, keep the previous version
- Respect rate limits — batch your captures and space them out
- Cache aggressively — social proof doesn't change by the minute
- Add alt text for accessibility — describe what the screenshot shows
Conclusion
Automating social proof screenshots keeps your marketing pages fresh and trustworthy without manual effort. With the ToolCenter Screenshot API, you can set up a pipeline in under an hour that captures testimonials, reviews, and mentions from across the web — and keeps them current automatically.
The key is treating social proof like any other data pipeline: define your sources, automate the capture, schedule refreshes, and display with proper attribution. Your conversion rates will thank you.