Google Reviews API - Complete Integration Guide

🎯 Overview

This API allows your Shopify app or website to fetch Google Reviews for any business on-demand. The API automatically caches data for 7 days per business to optimize API usage and provide fast responses.

Base URL: https://scraper.capula.co


📡 Main Endpoint

GET /api/reviews

Fetch Google Reviews for any business using its organizationId.

URL:

https://scraper.capula.co/api/reviews

📋 Request Parameters

Parameter Required Type Default Description
organizationId YES string - Google Maps organization ID
count No integer 10 Number of reviews to return (min: 1, max: 50)

🔍 How to Find organizationId

Method 1: From Google Maps URL (Easiest)

  1. Go to Google Maps: https://maps.google.com
  2. Search for your business (e.g., "Empire State Plumbing NY")
  3. Click on the business to open its profile
  4. Copy the URL from your browser

Example URL:

https://www.google.com/maps/place/Empire+State+Plumbing+Heating+%26+Air+Conditioning/@42.9354131,-73.8094899,17z/data=!3m1!4b1!4m6!3m5!1s0x89de0b0b3cdbe1d3:0x27519164cd8d3b5d!8m2!3d42.9354131!4d-73.806715!16s%2Fg%2F11b6g2tcd1
  1. Extract the organizationId - Look for the part that starts with 1s:
1s0x89de0b0b3cdbe1d3:0x27519164cd8d3b5d
  1. Remove the 1s prefix to get your organizationId:
0x89de0b0b3cdbe1d3:0x27519164cd8d3b5d

Method 2: Helper Endpoint (Coming Soon)

GET https://scraper.capula.co/api/search-business?query=Empire State Plumbing NY

Note: Currently returns instructions. Full search functionality coming soon.


📝 Examples

Example 1: Get 10 reviews

GET https://scraper.capula.co/api/reviews?organizationId=0x89de0b0b3cdbe1d3:0x27519164cd8d3b5d&count=10

Example 2: Get 20 reviews

GET https://scraper.capula.co/api/reviews?organizationId=0x89de0b0b3cdbe1d3:0x27519164cd8d3b5d&count=20

Example 3: Get maximum reviews (50)

GET https://scraper.capula.co/api/reviews?organizationId=0x89de0b0b3cdbe1d3:0x27519164cd8d3b5d&count=50

✅ Success Response

Status Code: 200 OK

Response Body:

{
  "data": [
    {
      "rating": 5,
      "comment": "I called for help with huge sump pump issues and \"Empire Plumbing\" sent me an awesome, knowledgeable, dependable young man (Logan Darling), who worked very hard and very clean, while eliminating all my sump pump issues. Big job so Logan had help, Michael (?)\\n\\nI feel both men did a beautiful job! I really could not be happier with the degree of professionalism I encountered from everyone at \"Empire Plumbing\".\\nThanks Logan!\\nThanks Michael!\\nAlisha and Everyone I spoke with (sorry can't remember).\\nDennis A. Moffre (homeowner)",
      "date": "2025-06-16T18:27:39.118Z",
      "author": null,
      "photos": [
        "https://lh3.googleusercontent.com/geougc-cs/AB3l90B37O5-RizlL4gp_RoiouWEkvtlPUYOy8NjhDMZeZdblwdoIYgp3pAjhCYd92m-Y7xw0rHmOu1JTQ9-nDcGtIC_Hq7UoO4afp2CiuhxekJwjr-DkTUBrTJ13F52Ootc5wY0rkCcndkYNjE"
      ],
      "owner_response": "Thank you so much, Dennis, for your detailed and kind feedback! We're thrilled to hear that Logan, Mike, and the rest of our team provided you with knowledgeable, dependable, and professional service."
    },
    {
      "rating": 5,
      "comment": "I was having issues with my central air unit at my new build house. The unit was installed by a contractor other than Empire State plumbing. Jimmy came out the same day i called and was extremely kind and professional. He had the issue fixed quickly and explained the whole process as he went. I'm very glad I called this company and am a lifelong customer now.",
      "date": "2025-07-07T19:50:50.771Z",
      "author": null,
      "photos": [
        "https://lh3.googleusercontent.com/geougc-cs/AB3l90DlJgCfxnx-5NqSF31tgSti1e8x4HWHpOGh43Mq7yYE6CULxoGXDzWehjwLI7kKNLcXRMemru8lY1AJWu7bjEh8_No8FhulySDqlO-Ejufa7KvT_x8E1DMhrwHqWqCXbpP8QmT23sAmJhg"
      ],
      "owner_response": "Eric, thank you for the amazing review! We're so glad Jimmy was able to help out quickly and make a great impression."
    }
  ],
  "count": 10,
  "organizationId": "0x89de0b0b3cdbe1d3:0x27519164cd8d3b5d",
  "cached": true,
  "scraped_at": "2025-10-09T01:13:45.123Z",
  "cache_expires_in_days": 6.9
}

Response Fields:

Field Type Description
data array Array of Google reviews
data[].rating integer Star rating (1-5)
data[].comment string Review text/comment
data[].date string When review was published (ISO 8601)
data[].author string/null Reviewer's name (may be null for privacy)
data[].photos array URLs to review photos (if any)
data[].owner_response string/null Business owner's response (if any)
count integer Number of reviews returned
organizationId string The business organization ID
cached boolean true if served from cache, false if freshly scraped
scraped_at string When the data was originally scraped
cache_expires_in_days float Days remaining until cache expires

❌ Error Responses

Missing organizationId (400 Bad Request)

{
  "error": "Missing parameter",
  "message": "The \"organizationId\" parameter is required",
  "example": "/api/reviews?organizationId=0x89de0b0b3cdbe1d3:0x27519164cd8d3b5d&count=10",
  "help": "Find organizationId from Google Maps URL or use Google Maps Place ID"
}

Invalid Count (400 Bad Request)

{
  "error": "Invalid count",
  "message": "Count must be between 1 and 50",
  "provided": 100
}

Organization Not Found (404 Not Found)

{
  "error": "No reviews found",
  "message": "Could not fetch reviews for organization 0xinvalidid",
  "organizationId": "0xinvalidid"
}

API Error (500 Internal Server Error)

{
  "error": "API request failed",
  "message": "Google Reviews API returned status 403",
  "organizationId": "0x89de0b0b3cdbe1d3:0x27519164cd8d3b5d"
}

🔄 Caching Behavior (IMPORTANT!)

How 7-Day Caching Works:

  1. First Request: When you request an organizationId for the first time (or after 7 days), the API will:
  2. Fetch fresh data from Google Reviews
  3. Save it to cache
  4. Return "cached": false
  5. This counts as 1 API request

  6. Subsequent Requests (within 7 days): All requests for the same organizationId will:

  7. Serve data from cache (instant response)
  8. Return "cached": true
  9. This does NOT count as an API request

  10. After 7 Days: The cache expires and the next request will fetch fresh data again.

Why 7 Days vs 24 Hours (Instagram)?

Staying Within API Limits:

Example Scenario: - Website A requests reviews for "Starbucks NYC" → 1 API request (fresh scrape) - Website A requests again 2 days later → 0 API requests (cached) - Website B requests "Starbucks NYC" 5 days later → 0 API requests (cached) - Website A requests after 8 days → 1 API request (cache expired, fresh scrape) - Total API requests used: 2


💻 Code Examples

JavaScript (Fetch API)

async function getGoogleReviews(organizationId, count = 10) {
  const url = `https://scraper.capula.co/api/reviews?organizationId=${organizationId}&count=${count}`;

  try {
    const response = await fetch(url);
    const data = await response.json();

    if (response.ok) {
      console.log(`Got ${data.count} reviews for business ${data.organizationId}`);
      console.log(`Cached: ${data.cached}`);
      console.log(`Cache expires in: ${data.cache_expires_in_days} days`);

      // Use the reviews
      data.data.forEach(review => {
        console.log(`⭐ ${review.rating}/5 - ${review.comment.substring(0, 100)}...`);
        console.log(`📅 ${review.date}`);

        if (review.owner_response) {
          console.log(`💬 Owner: ${review.owner_response.substring(0, 100)}...`);
        }

        if (review.photos.length > 0) {
          console.log(`📷 Photos: ${review.photos.length}`);
        }
      });

      return data.data;
    } else {
      console.error('Error:', data.error, data.message);
      return null;
    }
  } catch (error) {
    console.error('Request failed:', error);
    return null;
  }
}

// Usage:
getGoogleReviews('0x89de0b0b3cdbe1d3:0x27519164cd8d3b5d', 10);

JavaScript (Axios)

const axios = require('axios');

async function getGoogleReviews(organizationId, count = 10) {
  try {
    const response = await axios.get('https://scraper.capula.co/api/reviews', {
      params: {
        organizationId: organizationId,
        count: count
      }
    });

    console.log(`Got ${response.data.count} reviews`);
    console.log(`Cached: ${response.data.cached}`);

    return response.data.data;

  } catch (error) {
    if (error.response) {
      console.error('Error:', error.response.data.error);
      console.error('Message:', error.response.data.message);
    } else {
      console.error('Request failed:', error.message);
    }
    return null;
  }
}

// Usage:
getGoogleReviews('0x89de0b0b3cdbe1d3:0x27519164cd8d3b5d', 10);

Python (Requests)

import requests

def get_google_reviews(organization_id, count=10):
    url = 'https://scraper.capula.co/api/reviews'
    params = {
        'organizationId': organization_id,
        'count': count
    }

    try:
        response = requests.get(url, params=params)
        response.raise_for_status()

        data = response.json()
        print(f"Got {data['count']} reviews")
        print(f"Cached: {data['cached']}")
        print(f"Cache expires in: {data['cache_expires_in_days']} days")

        for review in data['data']:
            print(f"⭐ {review['rating']}/5")
            print(f"💬 {review['comment'][:100]}...")
            print(f"📅 {review['date']}")

            if review['owner_response']:
                print(f"💼 Owner: {review['owner_response'][:100]}...")

            print("---")

        return data['data']

    except requests.exceptions.HTTPError as e:
        error_data = e.response.json()
        print(f"Error: {error_data.get('error')}")
        print(f"Message: {error_data.get('message')}")
        return None
    except Exception as e:
        print(f"Request failed: {e}")
        return None

# Usage:
get_google_reviews('0x89de0b0b3cdbe1d3:0x27519164cd8d3b5d', 10)

PHP

<?php

function getGoogleReviews($organizationId, $count = 10) {
    $url = 'https://scraper.capula.co/api/reviews?' . http_build_query([
        'organizationId' => $organizationId,
        'count' => $count
    ]);

    $response = file_get_contents($url);
    $data = json_decode($response, true);

    if ($data) {
        echo "Got {$data['count']} reviews\\n";
        echo "Cached: " . ($data['cached'] ? 'yes' : 'no') . "\\n";

        foreach ($data['data'] as $review) {
            echo "⭐ {$review['rating']}/5\\n";
            echo "💬 {$review['comment']}\\n";
            echo "📅 {$review['date']}\\n";

            if (!empty($review['owner_response'])) {
                echo "💼 Owner: {$review['owner_response']}\\n";
            }

            echo "---\\n";
        }

        return $data['data'];
    }

    return null;
}

// Usage:
getGoogleReviews('0x89de0b0b3cdbe1d3:0x27519164cd8d3b5d', 10);
?>

cURL (Command Line)

# Get 10 reviews
curl "https://scraper.capula.co/api/reviews?organizationId=0x89de0b0b3cdbe1d3%3A0x27519164cd8d3b5d&count=10"

# Get 20 reviews with pretty JSON
curl "https://scraper.capula.co/api/reviews?organizationId=0x89de0b0b3cdbe1d3%3A0x27519164cd8d3b5d&count=20" | jq

🎨 Displaying Reviews in Your Shopify App

Basic Reviews Display

<div id="reviews-container"></div>

<script>
async function displayReviews(organizationId) {
  const response = await fetch(`https://scraper.capula.co/api/reviews?organizationId=${organizationId}&count=10`);
  const data = await response.json();

  const container = document.getElementById('reviews-container');

  data.data.forEach(review => {
    const reviewEl = document.createElement('div');
    reviewEl.className = 'review';
    reviewEl.innerHTML = `
      <div class="rating">${'⭐'.repeat(review.rating)}</div>
      <p class="comment">${review.comment}</p>
      <p class="date">${new Date(review.date).toLocaleDateString()}</p>
      ${review.owner_response ? `<div class="owner-response">
        <strong>Business Response:</strong> ${review.owner_response}
      </div>` : ''}
      ${review.photos.length > 0 ? `<div class="photos">
        ${review.photos.map(p => `<img src="${p}" alt="Review photo" />`).join('')}
      </div>` : ''}
    `;
    container.appendChild(reviewEl);
  });
}

// Usage:
displayReviews('0x89de0b0b3cdbe1d3:0x27519164cd8d3b5d');
</script>

With Star Rating Component

function StarRating({ rating }) {
  return (
    <div className="star-rating">
      {[1, 2, 3, 4, 5].map(star => (
        <span key={star} className={star <= rating ? 'filled' : 'empty'}>
          ⭐
        </span>
      ))}
    </div>
  );
}

function ReviewCard({ review }) {
  return (
    <div className="review-card">
      <StarRating rating={review.rating} />
      <p className="comment">{review.comment}</p>
      <p className="date">{new Date(review.date).toLocaleDateString()}</p>

      {review.owner_response && (
        <div className="owner-response">
          <strong>Business Response:</strong>
          <p>{review.owner_response}</p>
        </div>
      )}

      {review.photos.length > 0 && (
        <div className="review-photos">
          {review.photos.map((photo, i) => (
            <img key={i} src={photo} alt="Review" />
          ))}
        </div>
      )}
    </div>
  );
}

🔧 Testing the API

Test Health Endpoint

https://scraper.capula.co/health

Response:

{
  "status": "healthy",
  "timestamp": "2025-10-09T01:13:45Z"
}

Test Reviews Endpoint

https://scraper.capula.co/api/reviews?organizationId=0x89de0b0b3cdbe1d3:0x27519164cd8d3b5d&count=5

📊 Monitoring Your Usage

Check Cache Status

The API response includes helpful fields to monitor cache usage:

{
  "cached": true,
  "scraped_at": "2025-10-09T01:13:45Z",
  "cache_expires_in_days": 6.5
}

Best Practices for Shopify Apps

  1. Store organizationId in your database for each merchant
  2. Don't make repeated requests for the same business within 7 days
  3. Cache the response in your Shopify app's database
  4. Check cached field to know if you're using API quota
  5. Monitor cache_expires_in_days to schedule refreshes efficiently
  6. Handle errors gracefully (business not found, rate limits, etc.)

🚀 Shopify Integration Workflow

Step 1: Store Business Organization ID

When merchant sets up your app:

// In your Shopify app setup
const merchantSettings = {
  businessName: "Empire State Plumbing",
  googleMapsUrl: "https://www.google.com/maps/place/...",
  organizationId: "0x89de0b0b3cdbe1d3:0x27519164cd8d3b5d", // Extracted from URL
  reviewsEnabled: true
};

// Save to your database
await saveMerchantSettings(merchantSettings);

Step 2: Fetch Reviews On-Demand

// When customer views product/page with reviews
async function loadReviews(merchantId) {
  const settings = await getMerchantSettings(merchantId);

  if (settings.reviewsEnabled) {
    const response = await fetch(
      `https://scraper.capula.co/api/reviews?organizationId=${settings.organizationId}&count=10`
    );

    const data = await response.json();

    // Cache locally for even faster access
    await cacheReviews(merchantId, data.data);

    return data.data;
  }
}

Step 3: Display Reviews

<!-- In your Shopify theme liquid template -->
<div class="google-reviews">
  <h3>Customer Reviews</h3>
  <div id="reviews-list"></div>
</div>

<script>
  loadReviews('{{ shop.id }}').then(reviews => {
    displayReviews(reviews);
  });
</script>

⚠️ Important Notes

1. Cache Duration

2. organizationId Format

3. Review Privacy

4. Owner Responses

5. Count Limits


🆘 Troubleshooting

"organizationId not found" error

Slow response times

"API request failed" error

No owner_response field


📞 Support

API Status: https://scraper.capula.co/health Main Documentation: https://scraper.capula.co/docs Shopify Guide: https://scraper.capula.co/docs/shopify Base URL: https://scraper.capula.co

For technical support or API issues, check the RapidAPI dashboard or contact your system administrator.


🚀 Quick Start Checklist


📈 Response Time Expectations

Scenario Response Time
Cached data (within 7 days) <100ms
Fresh scrape (first time) 5-10 seconds
Business not found ~3-5 seconds

✨ Summary

One endpoint does everything:

GET https://scraper.capula.co/api/reviews?organizationId={id}&count={num}

That's it! The API handles: - ✅ Fetching reviews from Google Maps - ✅ Caching for 7 days - ✅ Parsing ratings, comments, photos - ✅ Including owner responses - ✅ Rate limit management - ✅ Error handling

Your Shopify app just makes a simple HTTP GET request and receives ready-to-display Google Reviews.