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

google-react-recaptcha-v2

v1.0.3

Published

React component for Google reCAPTCHA

Readme

🛡️ google-react-recaptcha-v2

Componente React ligero y tipado para Google reCAPTCHA v2 (checkbox e invisible). Sigue Clean Architecture — domain / application / infrastructure / presentation — para que mantener, extender y testear la librería sea trivial.

✅ TypeScript estricto
✅ Funciona con React 17+ (testeado con React 18 y 19)
✅ Invisible, compacto y checkbox, configurable
✅ Soporta Trusted Types (?trustedtypes=true)
✅ Helper server-side para /recaptcha/api/siteverify
✅ 82 tests + smoke test anti-"npm roto" incluido
✅ Bundle pequeño: ~6 KB (ESM y CJS minificado con treeshake)


📦 Instalación

npm install google-react-recaptcha-v2
# o
pnpm add google-react-recaptcha-v2
# o
yarn add google-react-recaptcha-v2

🚀 Uso básico

Invisible (recomendado para formularios)

import { useRef } from "react";
import { ReCaptchaV2, type ReCaptchaV2Ref } from "google-react-recaptcha-v2";

export function LoginForm() {
  const recaptchaRef = useRef<ReCaptchaV2Ref>(null);

  const handleSubmit = async (event: React.FormEvent<HTMLFormElement>) => {
    event.preventDefault();
    const token = await recaptchaRef.current?.execute();
    if (!token) return; // grecaptcha no estaba listo
    // Envía `token` al backend para verificarlo.
  };

  return (
    <form onSubmit={handleSubmit}>
      <input name="email" type="email" required />
      <input name="password" type="password" required />
      <button type="submit">Entrar</button>

      <ReCaptchaV2 ref={recaptchaRef} siteKey="YOUR_SITE_KEY" />
    </form>
  );
}

Checkbox visible

<ReCaptchaV2
  ref={recaptchaRef}
  siteKey="YOUR_SITE_KEY"
  size="normal"
  theme="dark"
  onSuccess={(token) => console.log("Listo para enviar:", token)}
  onExpired={() => console.warn("El usuario tardó demasiado, debe revalidar")}
/>

Modo desarrollo (isDevelop)

Si quieres probar sin configurar nada en Google, usa la test key oficial:

<ReCaptchaV2
  ref={recaptchaRef}
  isDevelop
  // siteKey se ignora cuando isDevelop={true}
/>

🧠 API pública

Componente <ReCaptchaV2>

| Prop | Tipo | Default | Descripción | | ----------------- | ----------------------------------------------------- | ------------- | ------------------------------------------------------------ | | siteKey | string | — | Requerido. Site key de Google reCAPTCHA v2. | | onSuccess | (token: string) => void | — | Callback cuando el usuario resuelve el challenge. | | onError | () => void | — | Callback si la API falla (red, configuración, etc.). | | onExpired | () => void | — | Callback cuando el token expira antes de ser verificado. | | size | "invisible" \| "normal" \| "compact" | "invisible" | Tamaño del widget. | | theme | "light" \| "dark" | "light" | Tema visual. | | badge | "bottomright" \| "bottomleft" \| "inline" | "bottomright" | Posición del badge cuando size="invisible". | | tabindex | number | 0 | Tabindex del widget. | | hl | string | — | Idioma BCP-47 (p.ej. "es", "en"). | | isDevelop | boolean | false | Usa la site key oficial de pruebas de Google (siempre pasa). | | trustedTypes | boolean | false | Carga la variante ?trustedtypes=true del script. | | multiple | boolean | false | @deprecated. Cada <ReCaptchaV2> ya es independiente. |

Ref (ReCaptchaV2Ref)

| Método | Tipo | Descripción | | --------------- | -------------------------- | ------------------------------------------------------------ | | execute() | () => Promise<string> | Ejecuta el reto invisible y devuelve el token. | | reset() | () => void | Resetea el widget y descarta el token actual. | | getResponse() | () => string \| null | Devuelve el token actual del widget, o null si no hay. |


🔒 Verificación server-side (backend)

Google exige verificar el token en el backend antes de confiar en él. La librería incluye un helper con resultado discriminado:

// Node, Bun, Deno o cualquier Edge runtime con `fetch` global.
// (Node 18+ tiene fetch nativo.)
import { verifyRecaptchaV2Token } from "google-react-recaptcha-v2";

app.post("/api/login", async (req, res) => {
  const result = await verifyRecaptchaV2Token({
    token: req.body["g-recaptcha-response"],
    secret: process.env.RECAPTCHA_SECRET!,
    remoteIp: req.ip, // opcional pero recomendado
  });

  if (!result.success) {
    // result.errorCodes puede ser:
    //   ["missing-token"], ["missing-secret"], ["network-error"],
    //   ["http-<status>"], ["invalid-json"], ["verification-failed"],
    //   o los códigos oficiales de Google ["invalid-input-response", ...]
    return res.status(400).json({ error: result.errorCodes });
  }

  // result.success === true:
  //   { challengeTs, hostname, success: true }
  // Tu backend decide qué hacer.
});

🏗️ Arquitectura limpia (Clean Architecture)

| Capa | Responsabilidad | Carpeta | | --------------- | --------------------------------------------------------------------- | ---------------------- | | domain | Tipos y contratos del componente y ref. | libs/domain/ | | application | Caso de uso (hook React) que orquesta el ciclo de vida. | libs/application/ | | infrastructure| Carga de script, grecaptcha.render, helpers de red. | libs/infrastructure/ | | presentation | Componente React fino que delega todo al hook. | libs/presentation/ | | constants | Identificadores y URLs reutilizados. | libs/constants/ |

Reglas de capa (estrictas):

  • domain no importa de nadie más.
  • application importa de domain + infrastructure.
  • infrastructure importa de domain + constants.
  • presentation importa de application + domain.
  • Sólo libs/index.ts debe llegar al consumidor.

🧪 Tests y build

pnpm typecheck         # tsc --noEmit (TS estricto)
pnpm test              # vitest en modo watch
pnpm test:run          # vitest run (CI)
pnpm test:coverage     # reporte de coverage (v8)
pnpm test:npm-smoke    # simula ser un consumidor (pack → install → tsc)
pnpm build             # tsup → dist/{index.js, index.mjs, index.d.ts, index.d.mts}
pnpm prepublishOnly    # typecheck + tests + build + smoke (encadenado)

Tests incluidos (82)

| Capa | Archivo | | --------------- | -------------------------------------------------------- | | infrastructure| recaptchaV2Script.test.ts (12 tests) | | infrastructure| reCaptchaV2Service.test.ts (14 tests) | | infrastructure| verifyRecaptchaV2Token.test.ts (10 tests) | | application | useReCaptchaV2.test.tsx (10 tests) | | presentation | ReCaptchaV2.test.tsx (5 tests) | | Anti-"npm roto" | types-export.test.ts (14 tests) + types-dist-dts.test.ts (7 tests) | | Smoke del paquete| published-package.test.ts (10 tests) |

El test estrella

tests/types-dist-dts.test.ts parsea el dist/index.d.ts con el compilador real de TypeScript y verifica que cada export público está declarado. Si tsup rompe el bundle de tipos por cualquier razón futura, este test falla antes de que un usuario rompa su build.

scripts/npm-smoke.mjs empaqueta la librería, la instala en un proyecto limpio y compila un consumer.ts que importa cada export. Si los tipos están rotos en el paquete final, el smoke los cazaría.


🧰 API de bajo nivel (avanzado)

Si sólo necesitas parte de la funcionalidad sin el componente React:

import {
  RecaptchaV2Service,
  loadRecaptchaV2Script,
  whenRecaptchaV2Ready,
  installOnloadCallback,
  GOOGLE_TEST_SITE_KEY,
} from "google-react-recaptcha-v2";

// Cargar script manualmente
installOnloadCallback(() => {
  // se invoca cuando api.js termine de cargar
});
const result = loadRecaptchaV2Script({ hl: "es", trustedTypes: true });

// Esperar a grecaptcha.ready
const ready = await whenRecaptchaV2Ready(5000);

// Renderizar un widget programáticamente
const service = new RecaptchaV2Service();
const widgetId = service.renderWidget(container, props, {
  onSuccess: (token) => {/* ... */},
});

📌 Tips de uso

  • Invisible es ideal para validaciones no intrusivas (formularios, acciones sensibles).
  • Si necesitas retos visibles (checkbox), usa size="normal" o size="compact".
  • Cambia el props.siteKey con isDevelop={true} en local para no necesitar claves reales.
  • trustedTypes={true} cuando la app aplica CSP estricta.
  • El backend siempre debe verificar el token con verifyRecaptchaV2Token.

🔒 Test key oficial de Google

Puedes usar esta site key en desarrollo; siempre resuelve el challenge con éxito:

import { GOOGLE_TEST_SITE_KEY } from "google-react-recaptcha-v2";
// "6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI"

OJO: el helper integrado es isDevelop={true} en el componente, que ya hace esto por ti.


📜 Licencia

MIT © Andrés Felipe Hernández Aldana


💡 Créditos

Construido usando: