npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@reviewshield/react-widget

v1.1.2

Published

ReviewShield – embeddable Google reviews React component

Downloads

56

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.

npm version License: MIT React


Table of Contents

  1. Features
  2. How It Works
  3. Prerequisites
  4. Installation
  5. Step-by-Step Setup Guide
  6. Usage
  7. Props Reference
  8. Customisation
  9. Individual Exports
  10. TypeScript Types
  11. Accessibility & Compliance
  12. FAQ
  13. 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-widget

Peer dependenciesreact and react-dom (≥ 18) must already be installed in your project. The package bundles tailwind-merge automatically; no extra setup is needed.


Step-by-Step Setup Guide

Step 1 — Install the package

npm install @reviewshield/react-widget

Step 2 — Create your API key

  1. 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.

  2. Navigate to API KeysNew Key.

  3. Enter a name for the key (e.g. My Website Production).

  4. Add your website's domain to the Allowed Domains whitelist (e.g. mywebsite.com). Requests from any other origin will be rejected.

  5. 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-api in this monorepo), deploy it to Vercel (or any Node.js host) and use that deployment URL.
# Example proxy URL
https://your-proxy.vercel.app

Step 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.app

For Next.js, prefix with NEXT_PUBLIC_ to expose the variable client-side.
For Vite, prefix with VITE_.
For Create React App, prefix with REACT_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 className to style the outermost widget container (<section>)
  • Use reviewCardClassName for each review card
  • Use googleLinkClassName to 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-label attributes.
  • Loading state sets aria-busy="true" and aria-label="Loading reviews…".
  • Error state uses role="alert" for screen-reader announcements.
  • Review cards use semantic <article> elements with schema.org microdata.
  • 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