Welcome to the Jose Madrid Salsa developer docs — explore features, APIs, and deployment guides.
Jose Madrid SalsaJMS Docs

Google Reviews

Google Business reviews integration via the Places API

Google Reviews Integration

The platform displays Google Business reviews on the storefront by fetching them from the Google Places API (v1). Reviews are loaded server-side and cached via ISR to avoid client-side API calls.

Architecture

Two data paths serve reviews:

  1. Server component fetcher (lib/server/google-data.ts) -- Used by server components with ISR caching (2-hour revalidation)
  2. API route (app/api/reviews/google/route.ts) -- Client-accessible endpoint with 2-hour cache

Both call the same Google Places API endpoint.

Environment Variables

VariableDescriptionRequired
GOOGLE_PLACES_API_KEYServer-side Places API keyRecommended
NEXT_PUBLIC_GOOGLE_MAPS_API_KEYFallback if server key not setAlternative
GOOGLE_PLACE_IDGoogle Place ID for the businessRecommended
NEXT_PUBLIC_GOOGLE_PLACE_IDFallback public place IDAlternative
GOOGLE_PLACE_NAMEBusiness name for place search (defaults to "Jose Madrid Salsa")No

If no Place ID is configured, the API route will attempt to find it by searching for the business name via the Places Text Search API.

Setup

Find your Google Place ID

Search for your business on Google Maps and extract the Place ID from the URL, or use the Place ID Finder.

Enable the Places API

In Google Cloud Console, enable the Places API (New) for your project.

Configure environment variables

GOOGLE_PLACES_API_KEY=AIza...
GOOGLE_PLACE_ID=ChIJ...

API Call

The Places API v1 is called with specific field masks:

GET https://places.googleapis.com/v1/places/{placeId}
Headers:
  X-Goog-Api-Key: {apiKey}
  X-Goog-FieldMask: reviews,rating,userRatingCount

Data Types

type Review = {
  authorName: string
  rating: number
  text: string
  relativePublishTime: string | null
}

type ReviewsData = {
  reviews: Review[]
  totalRating: number
  totalReviews: number
}
  • authorName comes from review.authorAttribution.displayName
  • relativePublishTime is formatted as a readable date string (e.g., "March 15, 2026")
  • totalRating is the aggregate business rating
  • totalReviews is the total review count from userRatingCount

Caching

Server Component Fetcher

Uses Next.js ISR with next: { revalidate: 7200 } (2 hours):

const response = await fetch(url, {
  next: { revalidate: 7200 },
})

API Route

Uses Next.js route segment config:

export const revalidate = 7200 // 2 hours

Error Handling

Both implementations return empty data on failure rather than throwing:

return { reviews: [], totalRating: 0, totalReviews: 0 }

The API route returns HTTP 200 with empty reviews and an error message in the response body to prevent UI breakage.

Key Files

FilePurpose
lib/server/google-data.tsServer component data fetcher
app/api/reviews/google/route.tsClient-accessible reviews endpoint

How is this guide?

Edit on GitHub

Last updated on

On this page