How to Automate Social Proof Screenshots for Your Website

T
Test User
Feb 25, 2026
6 min read

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

  1. Always link to the original source — screenshots without attribution look fake
  2. Use element selectors when possible to capture just the relevant portion, not the full page
  3. Set appropriate dimensions — oversized screenshots waste bandwidth
  4. Enable retina mode for crisp display on high-DPI screens
  5. Handle failures gracefully — if a capture fails, keep the previous version
  6. Respect rate limits — batch your captures and space them out
  7. Cache aggressively — social proof doesn't change by the minute
  8. 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.

Related Posts