@reviewshield/react-widget
v1.1.2
Published
ReviewShield – embeddable Google reviews React component
Downloads
56
Maintainers
Readme
@reviewshield/react-widget
Embeddable Google Reviews widget for React — powered by the ReviewShield proxy API. Display authentic Google Business reviews on any website without exposing your Google API key.
Table of Contents
- Features
- How It Works
- Prerequisites
- Installation
- Step-by-Step Setup Guide
- Usage
- Props Reference
- Customisation
- Individual Exports
- TypeScript Types
- Accessibility & Compliance
- FAQ
- Contact & Technical Support
Features
| Feature | Details |
| ------------------------------ | ------------------------------------------------------------------ |
| 🚀 Drop-in component | Single <ReviewShield /> component renders everything |
| 🔒 Secure by design | Your Google API key stays server-side; never exposed to browsers |
| 🌐 Origin validation | Each API key is locked to your whitelisted domain(s) |
| ⚡ Cache-first | Reviews are cached for 24 hours — minimal API calls, maximum speed |
| 🎨 Grid & Carousel layouts | Responsive grid or horizontal scroll carousel, out of the box |
| 💀 Skeleton loading | Animated placeholder cards while reviews load |
| ❌ Error & empty states | Friendly fallback UI with a one-click retry button |
| 🔍 JSON-LD Schema Markup | Auto-injected AggregateRating + Review structured data for SEO |
| ♿ Accessible | Full ARIA labels, semantic HTML, and schema.org microdata |
| ✅ ACCC compliant | Mandatory "View all reviews on Google" link included automatically |
| 🎯 Minimum rating filter | Show only reviews above a star threshold |
| 🪝 Headless hook | useReviews() hook for fully custom UI |
| 📦 Tree-shakeable | ESM + CJS dual build via tsup |
How It Works
Your Website ReviewShield Proxy API Google Places API
────────────── ───────────────────────── ─────────────────
<ReviewShield POST /api/reviews Fetches live
apiKey="rs_live_…" ───▶ • Validates API key ───▶ Google Business
proxyUrl="https://…" • Checks domain whitelist reviews
/> • Enforces rate limit
• Returns cached reviews ◀───
◀───── (24h TTL)The widget never contacts Google directly. All requests go through your ReviewShield proxy, which holds the Google Places API key securely on the server.
Prerequisites
| Requirement | Details | | --------------------------------- | ------------------------------------------------------------------------------------------------------- | | React | ≥ 18 | | Node.js | ≥ 18 | | Tailwind CSS | v3+ — required for the widget's styles to render correctly | | A ReviewShield API key | Obtained from the ReviewShield dashboard (see Step 2) | | A deployed ReviewShield proxy | The proxy API handles all Google API calls (see Step 3) |
Installation
# npm
npm install @reviewshield/react-widget
# yarn
yarn add @reviewshield/react-widget
# pnpm
pnpm add @reviewshield/react-widgetPeer dependencies —
reactandreact-dom(≥ 18) must already be installed in your project. The package bundlestailwind-mergeautomatically; no extra setup is needed.
Step-by-Step Setup Guide
Step 1 — Install the package
npm install @reviewshield/react-widgetStep 2 — Create your API key
Sign up or log in to the ReviewShield Dashboard at the URL provided to you by your account manager.
Note: The exact dashboard URL will be confirmed by the ReviewShield team. Contact [email protected] if you have not received it.
Navigate to API Keys → New Key.
Enter a name for the key (e.g.
My Website Production).Add your website's domain to the Allowed Domains whitelist (e.g.
mywebsite.com). Requests from any other origin will be rejected.Copy the generated key — it looks like
rs_live_xxxxxxxxxxxxxxxx.
⚠️ Keep this key private. Do not commit it to source control. Use environment variables (see Step 4).
Step 3 — Configure the proxy URL
The proxyUrl is the base URL of the deployed ReviewShield proxy API that sits between your widget and Google's Places API.
- If you are using the hosted ReviewShield service, your proxy URL will be provided in the dashboard.
- If you are self-hosting the proxy (
apps/proxy-apiin this monorepo), deploy it to Vercel (or any Node.js host) and use that deployment URL.
# Example proxy URL
https://your-proxy.vercel.appStep 4 — Store your API key safely
Store the API key in an environment variable so it is never hard-coded:
# .env.local (Next.js / Vite / Create React App)
NEXT_PUBLIC_REVIEWSHIELD_API_KEY=rs_live_xxxxxxxxxxxxxxxx
NEXT_PUBLIC_REVIEWSHIELD_PROXY_URL=https://your-proxy.vercel.appFor Next.js, prefix with
NEXT_PUBLIC_to expose the variable client-side.
For Vite, prefix withVITE_.
For Create React App, prefix withREACT_APP_.
Step 5 — Add the widget to your page
import { ReviewShield } from "@reviewshield/react-widget";
export default function ReviewsSection() {
return (
<ReviewShield
apiKey={process.env.NEXT_PUBLIC_REVIEWSHIELD_API_KEY!}
proxyUrl={process.env.NEXT_PUBLIC_REVIEWSHIELD_PROXY_URL}
googleMapsUrl="https://g.page/r/YOUR_GOOGLE_PLACE_ID/review"
layout="grid"
themeColor="#16A34A"
minRating={4}
/>
);
}That's it! The widget will automatically:
- Fetch reviews from your proxy
- Show skeleton cards while loading
- Render a responsive grid of review cards
- Include a "View all reviews on Google" link
- Inject JSON-LD structured data for SEO
Usage
Basic usage
import { ReviewShield } from "@reviewshield/react-widget";
<ReviewShield
apiKey="rs_live_abc123"
proxyUrl="https://your-proxy.vercel.app"
/>;Full example with all props
import { ReviewShield } from "@reviewshield/react-widget";
<ReviewShield
apiKey="rs_live_abc123"
proxyUrl="https://your-proxy.vercel.app"
layout="carousel" // "grid" | "carousel"
minRating={4} // Only show 4 and 5 star reviews
themeColor="#16A34A" // Brand colour for stars and avatar backgrounds
googleMapsUrl="https://g.page/r/YOUR_PLACE_ID/review"
className="my-8 px-4" // Extra CSS classes on the outer <section>
reviewCardClassName="border-2" // Extra CSS classes on each review card
/>;Carousel layout
<ReviewShield
apiKey="rs_live_abc123"
proxyUrl="https://your-proxy.vercel.app"
layout="carousel"
themeColor="#2563EB"
googleMapsUrl="https://g.page/r/YOUR_PLACE_ID/review"
/>Headless usage with useReviews hook
Build a completely custom UI using the underlying data hook:
import { useReviews, StarRating } from "@reviewshield/react-widget";
function MyCustomReviews() {
const { reviews, isLoading, error, refetch } = useReviews({
apiKey: "rs_live_abc123",
proxyUrl: "https://your-proxy.vercel.app",
minRating: 3,
});
if (isLoading) return <p>Loading reviews…</p>;
if (error) return <button onClick={refetch}>Retry</button>;
return (
<ul>
{reviews.map((review) => (
<li key={review.id}>
<strong>{review.authorName}</strong>
<StarRating rating={review.rating} themeColor="#16A34A" />
<p>{review.text}</p>
</li>
))}
</ul>
);
}Props Reference
<ReviewShield />
| Prop | Type | Default | Required | Description |
| --------------------- | ---------------------- | ---------------------- | -------- | --------------------------------------------------------------------------- |
| apiKey | string | — | ✅ | Your ReviewShield API key (rs_live_…) |
| proxyUrl | string | Current origin | ❌ | Base URL of the ReviewShield proxy API |
| layout | "grid" \| "carousel" | "grid" | ❌ | Display layout for the review cards |
| minRating | number (1–5) | 1 | ❌ | Hide reviews with a rating below this value |
| themeColor | string | "#4F46E5" | ❌ | Brand colour applied to stars and avatar backgrounds (any valid CSS colour) |
| googleMapsUrl | string | Google search fallback | ❌ | Your Google Business URL for the "View all reviews" link |
| className | string | — | ❌ | Additional CSS class(es) applied to the outer <section> element |
| reviewCardClassName | string | — | ❌ | Additional CSS class(es) applied to each individual review card |
| googleLinkClassName | string | — | ❌ | Additional CSS class(es) applied to the "View all reviews on Google" link |
Customisation
Changing the colour theme
Pass any valid CSS colour string to themeColor:
// Green brand
<ReviewShield apiKey="…" themeColor="#16A34A" />
// Blue brand
<ReviewShield apiKey="…" themeColor="#2563EB" />
// Custom hex, RGB, or HSL
<ReviewShield apiKey="…" themeColor="hsl(262, 83%, 58%)" />Styling with CSS classes
Use className, reviewCardClassName, and googleLinkClassName to layer your own Tailwind or custom classes:
<ReviewShield
apiKey="…"
className="max-w-5xl mx-auto py-12" // outer <section>
reviewCardClassName="bg-gray-50 border-none" // each review card
googleLinkClassName="bg-blue-100 text-blue-700 border-blue-200 hover:bg-blue-200" // 'View all reviews on Google' link
/>Tip:
- Use
classNameto style the outermost widget container (<section>) - Use
reviewCardClassNamefor each review card - Use
googleLinkClassNameto override the "View all reviews on Google" link styling only
Filtering reviews by star rating
Show only your best reviews by setting minRating:
// Only 4 and 5 star reviews
<ReviewShield apiKey="…" minRating={4} />
// Only 5 star reviews
<ReviewShield apiKey="…" minRating={5} />Adding structured data for SEO
The <SchemaMarkup /> component is included automatically inside <ReviewShield />. It injects a <script type="application/ld+json"> tag with AggregateRating and Review structured data. No extra configuration is required.
To use it independently in a custom layout:
import { SchemaMarkup } from "@reviewshield/react-widget";
// Render once per page alongside your custom review UI
<SchemaMarkup
reviews={reviews}
businessName="My Business"
placeUrl="https://g.page/r/YOUR_PLACE_ID"
/>;Individual Exports
All public exports are available as named imports:
import {
ReviewShield, // Full drop-in widget
ReviewCard, // Single review card
StarRating, // Star rating display (1–5 stars)
SkeletonCard, // Animated loading placeholder card
SchemaMarkup, // JSON-LD structured data injector
useReviews, // Data-fetching hook (headless usage)
} from "@reviewshield/react-widget";<ReviewCard />
Renders a single review card. Useful when building a custom layout.
import { ReviewCard } from "@reviewshield/react-widget";
<ReviewCard
review={{
authorName: "Jane Smith",
rating: 5,
text: "Absolutely fantastic service!",
time: 1700000000,
relativeTime: "2 months ago",
profilePhotoUrl: "https://…/photo.jpg",
}}
themeColor="#16A34A"
className="my-custom-class"
/>;<StarRating />
Renders filled/empty stars for a given rating.
import { StarRating } from "@reviewshield/react-widget";
<StarRating rating={4} themeColor="#F59E0B" />;<SkeletonCard />
Animated loading placeholder that matches the ReviewCard dimensions.
import { SkeletonCard } from "@reviewshield/react-widget";
<SkeletonCard />;<SchemaMarkup />
Injects JSON-LD structured data (AggregateRating + Review) for SEO.
import { SchemaMarkup } from "@reviewshield/react-widget";
<SchemaMarkup
reviews={reviews}
businessName="My Coffee Shop"
placeUrl="https://g.page/r/YOUR_PLACE_ID"
/>;useReviews(options)
Custom hook that fetches and caches reviews from the proxy API.
import { useReviews } from "@reviewshield/react-widget";
const { reviews, isLoading, error, refetch } = useReviews({
apiKey: "rs_live_abc123",
proxyUrl: "https://your-proxy.vercel.app",
minRating: 1, // optional, default: 1
});Returns:
| Property | Type | Description |
| ----------- | ---------------- | ----------------------------------------------------- |
| reviews | Review[] | Array of review objects (filtered by minRating) |
| isLoading | boolean | true while the request is in-flight |
| error | string \| null | Error message if the request failed, otherwise null |
| refetch | () => void | Re-fetches reviews on demand |
TypeScript Types
All public types are exported from the package:
import type {
Review,
ReviewShieldConfig,
UseReviewsResult,
} from "@reviewshield/react-widget";Review
interface Review {
id?: string;
businessId?: string;
authorName: string;
authorUrl?: string;
profilePhotoUrl?: string;
rating: number; // 1–5
text: string;
time: number; // Unix timestamp (seconds)
relativeTime?: string; // e.g. "2 months ago"
fetchedAt?: string;
}ReviewShieldConfig
interface ReviewShieldConfig {
apiKey: string;
proxyUrl?: string;
layout?: "grid" | "carousel";
minRating?: number;
themeColor?: string;
className?: string;
googleMapsUrl?: string;
}UseReviewsResult
interface UseReviewsResult {
reviews: Review[];
isLoading: boolean;
error: string | null;
refetch: () => void;
}Accessibility & Compliance
- All interactive elements have proper
aria-labelattributes. - Loading state sets
aria-busy="true"andaria-label="Loading reviews…". - Error state uses
role="alert"for screen-reader announcements. - Review cards use semantic
<article>elements withschema.orgmicrodata. - The "View all reviews on Google" link is always rendered when reviews are displayed, as required by the Australian Competition and Consumer Commission (ACCC) guidelines on online reviews.
FAQ
Q: Do I need Tailwind CSS in my project?
A: Yes. The widget renders Tailwind CSS utility classes for all its styles. You must have Tailwind CSS installed and configured in your project for the widget to display correctly. Follow the Tailwind CSS installation guide if you have not already set it up. The tailwind-merge dependency bundled with the widget only resolves class-name conflicts — it does not provide Tailwind's CSS.
Q: Where is my Google API key?
A: Your Google Places API key is stored securely in the ReviewShield proxy API environment variables. It is never sent to or stored in the browser.
Q: What happens if the proxy is unavailable?
A: The widget renders a friendly error card with a "Retry" button. No reviews are shown and the page remains fully functional.
Q: Can I use the widget without the ReviewShield proxy?
A: The widget is designed to work with the ReviewShield proxy API. You can self-host the proxy by deploying apps/proxy-api from this monorepo. See the root README for instructions.
Q: How do I find my Google Maps URL?
A: Go to your Google Business Profile, click "Share", and copy the short link. It will look like https://g.page/r/XXXXXXXXXXXXXXXXXX/review.
Q: How often are reviews refreshed?
A: Reviews are cached by the proxy for 24 hours. The refetch() function from useReviews bypasses the in-component state but is still subject to the server-side cache TTL.
Contact & Technical Support
For technical assistance with the @reviewshield/react-widget package:
| Channel | Details | | ----------------------- | -------------------------------------------------------------------------------------------------------------------- | | 📧 Email | [email protected] | | 🐛 Bug reports | Open an issue on GitHub | | 💡 Feature requests | Open a discussion on GitHub | | 📖 Documentation | Root README for full monorepo setup and proxy API docs |
When reporting a bug, please include your React version, package version, browser/Node.js version, and a minimal reproduction.
License
MIT © ReviewShield
