Guide

Composables

useReviews() and useReviewSchema() — reactive, type-safe review data and Schema.org JSON-LD.

useReviews()

The useReviews() composable is auto-imported and provides reactive access to your review data.

Basic Usage

<script setup lang="ts">
const { reviews, aggregate, pending } = useReviews()
</script>

<template>
  <div v-if="pending">Loading...</div>
  <div v-else>
    <p>Average: {{ aggregate?.average }} ({{ aggregate?.total }} reviews)</p>
    <div v-for="review in reviews" :key="review.id">
      <strong>{{ review.author.name }}</strong> — {{ review.rating }}/5
      <p>{{ review.text }}</p>
    </div>
  </div>
</template>

Options

const { reviews, aggregate, sources, nextPageToken, totalAvailable, pending, error, refresh } = useReviews({
  provider: 'google',    // 'google' | 'trustpilot' | 'serpapi' | 'outscraper' | 'bookingcom' | 'mock' | 'all'
  limit: 20,
  language: 'en',
  sort: 'newest',
  minRating: 3,
  pageToken: undefined,  // pagination token from a previous response
  immediate: true        // fetch on mount (default: true)
})

Return Values

PropertyTypeDescription
reviewsComputedRef<NormalizedReview[]>Array of normalized reviews
aggregateComputedRef<AggregateRating | null>Average, total, and star distribution
sourcesComputedRef<{ provider, count, average }[]>Per-provider breakdown
nextPageTokenComputedRef<string | undefined>Token for fetching next page (single-provider only)
totalAvailableComputedRef<number | undefined>Total reviews on the platform (single-provider only)
pendingRef<boolean>Loading state
errorRef<Error | null>Error state
refresh() => Promise<void>Manually re-fetch reviews

Provider-Specific Fetch

const { reviews: googleReviews } = useReviews({ provider: 'google' })
const { reviews: tpReviews } = useReviews({ provider: 'trustpilot' })
const { reviews: mockReviews } = useReviews({ provider: 'mock' })

// All configured providers (aggregated)
const { reviews: allReviews } = useReviews({ provider: 'all' })

Pagination

nextPageToken and totalAvailable are available in single-provider mode. Pass the token back as pageToken to fetch the next page:

const page1 = useReviews({ provider: 'serpapi', limit: 10 })

// When ready to load next page:
const page2 = useReviews({
  provider: 'serpapi',
  limit: 10,
  pageToken: page1.nextPageToken.value
})
nextPageToken is undefined in aggregated mode (provider: 'all').

Lazy Load

const { reviews, refresh: loadReviews } = useReviews({
  provider: 'all',
  immediate: false  // don't fetch on mount
})

// Trigger manually — e.g. on button click or intersection observer
await loadReviews()

useReviewSchema()

useReviewSchema() auto-injects a <script type="application/ld+json"> block into your page <head> with Schema.org structured data. This enables Google rich snippets — star ratings appearing in search results.

Basic Usage

<script setup lang="ts">
const { reviews, aggregate } = useReviews()

useReviewSchema(reviews, aggregate, {
  name: 'Grand Hotel Istanbul',
})
</script>

Options

useReviewSchema(reviews, aggregate, {
  name: 'Grand Hotel Istanbul',          // required
  description: 'Luxury hotel in Istanbul',
  url: 'https://example.com',
  image: 'https://example.com/hotel.jpg',
  type: 'Hotel',                         // Schema.org @type, default: 'LocalBusiness'
})
OptionTypeRequiredDescription
namestringYesBusiness/entity name
descriptionstringNoShort description
urlstringNoCanonical page URL
imagestringNoBusiness image URL
typestringNoSchema.org @type (default: 'LocalBusiness')

Common type values: Hotel, Restaurant, TouristAttraction, LocalBusiness.

Generated Output

The composable generates an AggregateRating entry plus up to 20 individual Review entries — Google's minimum for rich snippet eligibility:

{
  "@context": "https://schema.org",
  "@type": "Hotel",
  "name": "Grand Hotel Istanbul",
  "aggregateRating": {
    "@type": "AggregateRating",
    "ratingValue": "4.5",
    "reviewCount": 120,
    "bestRating": 5,
    "worstRating": 1
  },
  "review": [
    {
      "@type": "Review",
      "author": { "@type": "Person", "name": "Ahmet Y." },
      "datePublished": "2025-03-20",
      "reviewBody": "Harika bir otel deneyimi...",
      "reviewRating": { "@type": "Rating", "ratingValue": 5, "bestRating": 5, "worstRating": 1 }
    }
  ]
}

Returns

const { schema } = useReviewSchema(reviews, aggregate, { name: 'My Business' })
// schema is a ComputedRef<Record<string, unknown> | null>

Server API Routes

The module automatically registers these Nitro server routes:

RouteDescription
GET /api/_reviewsFetch from all configured providers (aggregated)
GET /api/_reviews/:providerFetch from a specific provider

Query Parameters

ParamTypeDescription
limitnumberMax reviews to return
languagestringLanguage filter (e.g. tr, en)
sortstringSort order (provider-specific)
minRatingnumberMinimum rating filter (1-5)
pageTokenstringPagination token (single-provider only)