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

@opacedev/react-preferred-source

v1.0.0

Published

Add as Preferred Source Button & Popup for Google (SEO & AI Overviews) for React and Next.js: client component, hook, fallback and ps-click instrumentation.

Readme

Add as Preferred Source Button & Popup for Google (SEO & AI Overviews) — React and Next.js

Add as Preferred Source Button & Popup for Google (SEO & AI Overviews)

Preferred Sources button variants in light and dark themes

Variant gallery: React and Next.js use the same trigger and fallback behaviour.

@opacedev/react-preferred-source supplies a typed PreferredSourceButton and usePreferredSource() hook. Both load the SDK after mount and provide a deeplink fallback.

Install from npm with npm i @opacedev/react-preferred-source.

Why publishers use Preferred Sources

The button gives a reader a direct route to choose the publication in Google. Google says fresh and relevant content from a selected source is more likely to appear in that reader's Top Stories and may receive a preferred badge in AI Mode and AI Overviews. Google also reports roughly twice the click-through after a user selects a source.

That is personalisation for the individual reader, not a site-wide ranking factor or a guarantee of traffic, inclusion or AI citations. Read Google's guidance and click-through finding.

Build from this repository

pnpm install
pnpm --filter @opacedev/react-preferred-source build

Next.js App Router

The package entry is a client component, so a Server Component can import and render it with serialisable props. Supply domain when you want the server-rendered fallback to use a known publication domain.

// app/page.tsx — Server Component
import { PreferredSourceButton } from "@opacedev/react-preferred-source";

export default function Page() {
  return (
    <PreferredSourceButton
      domain="example.com"
      theme="dark"
      variant="google-colours"
      label="Prefer this source"
    />
  );
}

Callbacks are functions, so keep analytics in a separate client wrapper instead of passing onPsClick from a Server Component.

// app/TrackedPreferredSourceButton.tsx
"use client";

import { PreferredSourceButton } from "@opacedev/react-preferred-source";

export function TrackedPreferredSourceButton() {
  return (
    <PreferredSourceButton
      domain="example.com"
      onPsClick={(detail) => {
        navigator.sendBeacon(
          "/analytics",
          JSON.stringify({ event: "preferred_source_click", detail }),
        );
      }}
    />
  );
}

The Server Component may render <TrackedPreferredSourceButton />; its function callback stays behind the client boundary.

Custom trigger hook

"use client";

import { usePreferredSource } from "@opacedev/react-preferred-source";

export function CustomCta() {
  const { status, open, deeplink } = usePreferredSource({
    theme: "light",
    lang: "en",
  });
  if (status === "blocked") return <a href={deeplink}>Prefer us on Google</a>;
  return <button onClick={() => void open()}>Prefer us on Google</button>;
}

Requirements and limits

  • React and React DOM 18+; Node.js 18+ for development.
  • The package is a client component. Next.js App Router and Pages Router are supported by the source tests; SDK work starts after hydration.
  • mode="auto" creates static attributed markup. Manual mode is the default for dynamic UI.
  • onPsClick measures your trigger click only. open() resolves popup, deeplink or none; popup does not prove the reader completed Google's flow.

| Prop | Default | Notes | | ------------------------------ | ------------------------------------------- | ------------------------------------------------------------------------------- | | theme, lang, domain | light, browser language, current hostname | Documented SDK configuration and fallback hostname. | | mode | manual | auto renders the attributed static target. | | label, children, variant | Standard label, none, google-default | children replaces the label; variants include google-colours and neutral. | | hrefFallback | Computed deeplink | Overrides the fallback target. | | renderTimeoutMs | 4000 ms | Auto-mode time allowed after SDK load before fallback. | | onPsClick, onPsFallback | None | Receives trigger-click detail or a blocked/no-render fallback reason. |

The hook returns { status, open, deeplink }. Standard button attributes pass through to the component.

Limitation. Google's SDK has no completion callback or event. ps-click measures a trigger click, not a confirmed addition.

External service and troubleshooting

Browser use loads Google's publisher script after mount. The package does not send onPsClick anywhere or store event records; your application decides what to do with the callback. If the hook remains blocked or the button uses its deeplink, check consent, CSP, client-only rendering and the eligible domain before retrying the popup.

See the root README for consent, CSP, eligibility and fallback guidance.


Source: suite repository · Support: GitHub issues · Live demo · Opace SEO services · Opace on GitHub · MIT licence