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

@hartl-services/payload-google-reviews-plugin

v0.3.0

Published

Payload CMS plugin: fetch Google reviews via the Places API and store them as a draft-enabled collection

Readme

@hartl-services/payload-google-reviews-plugin

Payload CMS 3 plugin that fetches a place's Google reviews through the Google Places API (New) and stores them in a draft-enabled google-reviews collection. New reviews arrive as drafts, so an editor checks and publishes them before they appear publicly.

What it adds

| Addition | Details | | ---------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Collection google-reviews | authorName, authorUrl, rating, comment, reviewDate, googleReviewId (unique), rawData; drafts enabled | | Global google-reviews-summary | The place's overall Google rating: rating, userRatingCount, googleMapsUri, syncedAt; read-only in the Admin, written by the sync | | Access | Logged-in users read and write everything; anonymous readers only see published reviews; the summary global is publicly readable, nobody can update it except the sync | | Endpoint POST /api/google-reviews/sync | Logged-in users only; fetches reviews and creates unseen ones as drafts | | Admin button | "Reviews jetzt abfragen" above the list view, calls the endpoint | | Job task syncGoogleReviews | Scheduled on the default queue, daily at 03:00 server time unless cron is set; an invalid cron fails at startup |

Reviews are deduplicated by Google's review id, or by the author URL (a Google author reviews a place only once). An existing entry without Google's id, e.g. migrated from the legacy Places API, gets the id adopted on the next sync; its content and publish status stay unchanged. Google exposes at most five reviews per place, so older reviews stay in the collection once imported.

Installation

pnpm add @hartl-services/payload-google-reviews-plugin
// payload.config.ts
import { googleReviewsPlugin } from '@hartl-services/payload-google-reviews-plugin'

export default buildConfig({
  // ...
  plugins: [
    googleReviewsPlugin({
      apiKey: process.env.GOOGLE_PLACES_API_KEY,
      placeId: process.env.GOOGLE_PLACES_ID,
      // languageCode: 'de', // default
      // cron: '0 3 * * *', // default: daily at 03:00 server time
      // adminGroup: 'Helfer', // default: no Admin navigation group
    }),
  ],
  // Needed for the daily sync: runs due jobs, including scheduled ones.
  // Requires a long-lived Node.js process (not serverless).
  jobs: {
    autoRun: [{ cron: '* * * * *' }],
  },
})

Then regenerate types and the import map, and create a migration for the new collection and global (when upgrading from 0.2.x, the migration adds the google-reviews-summary global):

pnpm payload generate:types
pnpm payload generate:importmap
pnpm payload migrate:create google_reviews

Missing apiKey or placeId does not break the build; the sync then fails with "nicht konfiguriert".

Environment

# --- Google Reviews (@hartl-services/payload-google-reviews-plugin) ---
# Required for syncing: API key of a Google Cloud project with "Places API (New)" enabled.
GOOGLE_PLACES_API_KEY=
# Required for syncing: Google Place ID of the business.
GOOGLE_PLACES_ID=

The plugin uses the Places API (New) (places.googleapis.com/v1). The legacy Places API can no longer be enabled for new Google Cloud projects. Restrict the API key to the Places API (New).

Rendering reviews

Read published reviews through the Local API with access enforced, so drafts stay hidden:

const { docs } = await payload.find({
  collection: 'google-reviews',
  depth: 0,
  limit: 20,
  overrideAccess: false,
  sort: '-reviewDate',
})

Rendering the overall rating

Every sync also stores the place's overall rating, e.g. for "4,8 · 127 Google-Bewertungen". The global is public Google data and therefore readable without login:

const summary = await payload.findGlobal({
  slug: 'google-reviews-summary',
  depth: 0,
  overrideAccess: false,
})
// { rating: 4.8, userRatingCount: 127, googleMapsUri: 'https://...', syncedAt: '...' }

The values are null until the first successful sync, or when Google does not return them. Upgrading from 0.2.x requires a migration (pnpm payload migrate:create google_reviews_summary); the global is filled with the next sync.

Development

cp dev/.env.example dev/.env   # needs a local MongoDB
pnpm install
pnpm dev                       # http://localhost:3000/admin, login [email protected] / test
pnpm lint && pnpm typecheck
pnpm exec vitest run           # unit + integration tests (in-memory MongoDB)
pnpm test:e2e                  # Playwright against the dev app

Neue Paketversion auf npm veröffentlichen

Das Paket wird öffentlich über npmjs.com bereitgestellt. GitLab CI prüft bei jedem Lauf auf dem Default-Branch, in dem sich package.json oder .gitlab-ci.yml geändert hat, ob die Version aus package.json bereits auf npm existiert. Eine neue Version wird auf dem projekteigenen Runner gebaut und gepackt und anschließend auf einem GitLab.com Shared Runner per npm Trusted Publishing mit kurzlebigen GitLab-OIDC-Tokens veröffentlicht; bereits veröffentlichte Versionen werden übersprungen.

Erhöhe für ein Release die Version und bringe die Änderung auf den Default-Branch:

pnpm version patch --no-git-tag-version
git add package.json
git commit -m "release: publish next version"
git push

Für ein Minor- oder Major-Release verwende entsprechend minor oder major.

Einmaliger npm-Bootstrap

Trusted Publishing kann erst in den Einstellungen eines bereits existierenden npm-Pakets aktiviert werden. Veröffentliche daher die erste Version einmalig mit einem npm-Account, der Pakete im Scope @hartl-services anlegen darf:

pnpm install --frozen-lockfile
pnpm build
pnpm pack --out /tmp/payload-google-reviews-plugin.tgz
npm login --registry=https://registry.npmjs.org/
npm publish /tmp/payload-google-reviews-plugin.tgz --registry=https://registry.npmjs.org/

Konfiguriere danach unter den npm-Paketeinstellungen den Trusted Publisher mit diesen Werten:

| Einstellung | Wert | | ---------------------- | ---------------------------------------- | | Provider | GitLab CI/CD | | Namespace | hartl-services-gmbh/pakete/payload-cms | | Project name | payload-google-reviews-plugin | | Top-level CI file path | .gitlab-ci.yml | | Allowed action | npm publish |

Nach erfolgreicher Einrichtung sollten in npm unter Publishing access klassische Publish-Tokens deaktiviert werden.

Compatibility

| Requirement | Supported | | ----------- | ----------- | | Payload | ^3.86.0 | | Node.js | >=20.9.0 | | pnpm | 9, 10 or 11 |

License

MIT