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

@usethrottle/checkout-react

v1.0.1

Published

React component for embedded Throttle checkout

Readme

@usethrottle/checkout-react

React components for embedding Throttle checkout in your site. Two embed products + one helper hook:

  • <PaymentEmbed/> — payment-only iframe. Drops a Gr4vy-backed card form into your existing checkout page.
  • <CheckoutEmbed/> — full-checkout iframe. Address + shipping + payment. Single iframe, single drop-in.
  • useThrottleEvents() — hook for parents who build their own iframe wrapper but want Throttle's strict postMessage validation.

Install

npm install @usethrottle/checkout-react

One-time setup: allow your site's origin

Each embed posts events to your page over postMessage with a strict targetOrigin. Your origin must be on the merchant's allowlist:

throttle embed-config set --origins https://shop.example.com

Or via API:

fetch('https://api.usethrottle.dev/api/v1/embed-config', {
  method: 'PUT',
  headers: { 'x-api-key': 'sk_...', 'content-type': 'application/json' },
  body: JSON.stringify({ allowed_origins: ['https://shop.example.com'] }),
});

<PaymentEmbed/> — payment-only

import { PaymentEmbed } from '@usethrottle/checkout-react';

export function CheckoutPage({ sessionId }: { sessionId: string }) {
  return (
    <PaymentEmbed
      sessionId={sessionId}
      parentOrigin="https://shop.example.com"
      primary="#ff6b00"
      onReady={() => console.log('ready')}
      onProcessing={() => console.log('paying...')}
      onSucceeded={({ orderId, paymentId }) => {
        // navigate to thank-you page, clear cart, etc.
        window.location.href = `/orders/${orderId}`;
      }}
      onFailed={({ code, message }) => {
        // surface to user
      }}
      onCanceled={() => {
        // user dismissed
      }}
    />
  );
}

<CheckoutEmbed/> — full checkout

import { CheckoutEmbed } from '@usethrottle/checkout-react';

export function CheckoutPage({ sessionId }: { sessionId: string }) {
  return (
    <CheckoutEmbed
      sessionId={sessionId}
      parentOrigin="https://shop.example.com"
      primary="#ff6b00"
      logo="https://shop.example.com/logo.png"
      onSucceeded={({ orderId, paymentId }) => {
        /* ... */
      }}
      onStepChanged={({ step }) => {
        // step: 'cart' | 'address' | 'shipping' | 'payment'
      }}
    />
  );
}

useThrottleEvents — DIY iframe wrapper

import { useThrottleEvents, type ThrottleMessage } from '@usethrottle/checkout-react';
import { useRef } from 'react';

export function MyEmbed({ sessionId }: { sessionId: string }) {
  const iframeRef = useRef<HTMLIFrameElement>(null);
  const baseUrl = 'https://checkout.usethrottle.dev';

  useThrottleEvents({
    iframeRef,
    expectedOrigin: new URL(baseUrl).origin,
    onMessage: (msg: ThrottleMessage) => {
      if (msg.type === 'throttle.completed') console.log('paid', msg.orderId);
    },
  });

  const src = `${baseUrl}/c/${sessionId}?embed=1&mode=payment-only&parentOrigin=${window.location.origin}`;
  return <iframe ref={iframeRef} src={src} allow="payment *" />;
}

Events

Both <PaymentEmbed/> and <CheckoutEmbed/> fire these events to the parent page over postMessage. They're complementary to Throttle's outbound webhooks (which fire from Throttle's servers to your backend over signed HTTP).

| Event | When | Callback | | ----------------------- | ------------------------------- | ----------------------------------- | | throttle.ready | iframe mounted | onReady() | | throttle.processing | user clicked Pay; awaiting auth | onProcessing() | | throttle.completed | payment captured | onSucceeded({orderId, paymentId}) | | throttle.error | card declined / network failure | onFailed({code, message}) | | throttle.cancelled | user dismissed | onCanceled() | | throttle.step.changed | (CheckoutEmbed) step transition | onStepChanged({step}) | | throttle.resize | iframe content resized | (auto: updates iframe height) |

Every message is wrapped in { source: 'throttle', version: 1, ...event } so your page can disambiguate Throttle messages from other senders. The hook validates origin, source window, and envelope before invoking your callback.

Backwards-compat alias: <ThrottleCheckout/>

ThrottleCheckout is a v0.1 alias that resolves to CheckoutEmbed. The callback shape changed in v0.2: onCompleted(orderId, paymentId) is now onSucceeded({orderId, paymentId}) and onError(code, message) is now onFailed({code, message}). Update call sites accordingly.

See also