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

@goldenhippo/hippo-shop-sdk

v1.1.1

Published

Browser SDK for Hippo Shop — auto-boots from a <script> tag and attaches window.gh.data.

Downloads

312

Readme

@goldenhippo/hippo-shop-sdk

npm version bundle size license: MIT

Browser SDK for reading Golden Hippo public data — funnels, destinations, products. Loads from a <script> tag and exposes two complementary surfaces:

  1. Declarative — write HTML with data-gh-* attributes; the SDK scans the page, fetches the right resources, and renders the values. No JS required.
  2. Programmatic — call window.gh.data.product(slug) and friends for full control.

Both share the same auth, caching, and brand-tenancy guardrails enforced at the API gateway.

Source: GoldenHippoMedia/hippo-shop · DTO contract: @goldenhippo/hippo-shop-types


Installation

For most pages, no install — drop the <script> tag (see Quickstart below). For TypeScript projects or build-tool integrations:

npm install @goldenhippo/hippo-shop-sdk
# or
pnpm add @goldenhippo/hippo-shop-sdk

The published bundle is dist/gh.js (IIFE, browser-loadable directly from a CDN-like URL) and ESM/CJS entries for tooling.


Quickstart — declarative

Drop one <script> and write your HTML:

<script src="https://api-prod.goldenhippo.io/sdk/v1/gh.js"
        data-key="gh_pk_netlify_gundry_xyz"
        data-brand="Gundry MD"></script>

<article data-gh-product="bio-complete-3">
  <img data-attr-src="image" data-attr-alt="name" />
  <h2 data-field="name">Loading…</h2>

  <p class="reviews">
    <span data-field="reviews.average" data-format="number:1"></span>★
    (<span data-field="reviews.count" data-format="number:0"></span> reviews)
  </p>

  <p class="price">
    <span data-field="variants.subscription.standard.0.price"
          data-format="currency:USD"></span>
  </p>

  <p data-if="outOfStock" class="badge-oos">Out of stock</p>
</article>

That's it. The SDK auto-boots, scans for data-gh-* attributes, fetches /public/v1/product/bio-complete-3 once, and renders. Any placeholder text inside the elements stays visible until the data arrives (good for SEO and graceful loading).


Attribute reference

Script tag

| Attribute | Required | Default | Description | |-----------|----------|---------|-------------| | data-key | yes | — | Publishable key. Format: gh_pk_<consumer>_<random>. | | data-brand | yes | — | Brand display name. Validated server-side. | | data-debug | no | false | If true, logs requests/responses/cache to the console. |

The API base URL is derived from the script's src host. Allowed hosts: api-prod.goldenhippo.io, api-uat.goldenhippo.io, localhost, 127.0.0.1, *.local.

Declarative attributes

| Attribute | Where | What it does | |-----------|-------|--------------| | data-gh-product="slug" | Any element | Sets the product context for the element + descendants. | | data-gh-destination="slug" | Any element | Sets the destination context. | | data-gh-funnel="slug" | Any element | Sets the funnel context. | | data-field="path.to.value" | Any element | Replaces textContent with the value at that path. | | data-format="name[:arg]" | With data-field or data-attr-* | Applies a formatter. See below. | | data-attr-<NAME>="path" | Any element | Sets the <NAME> attribute (e.g. data-attr-src, data-attr-href). on* attributes are silently refused. | | data-if="path" | Any element | Hides the element if the path resolves to a falsy value. | | data-if-not="path" | Any element | Hides the element if the path resolves to a truthy value. | | data-each="path" | <template> only | Clones the template's content once per item in the array. |

Paths are dot-separated; array indices are numeric segments: variants.subscription.standard.0.price.

Formatters

| Name | Example | Output | |------|---------|--------| | currency | currency:USD:en-US (currency code + locale, both optional) | $49.95 | | number | number:0 (decimals), number:2:en-US | 1,235 / 1,234.50 | | percent | percent, percent:1 | 25% / 12.3% | | uppercase / lowercase | uppercase | BIO COMPLETE 3 | | bool | bool:In stock:Sold out | renders the second arg if falsy | | join | join: - | joins arrays |

Register custom formatters at runtime:

window.gh.format.register('shouty', (v) => String(v).toUpperCase() + '!');
// then in HTML: <span data-field="name" data-format="shouty"></span>

Loops

<template> is the standard HTML element for non-rendered templates. The SDK expands it once per array item, with each clone seeing the iterated item as its data context.

<ul data-gh-product="bio-complete-3">
  <template data-each="variants.subscription.standard">
    <li>
      <strong data-field="quantity"></strong>
      × <span data-field="packageType"></span>:
      <span data-field="price" data-format="currency:USD"></span>
    </li>
  </template>
</ul>

Loops can be nested inside loops — bind paths resolve against the nearest enclosing iteration item.


Programmatic API

Everything the declarative layer does is also available on window.gh:

window.gh.data.funnel(slugOrId):      Promise<HippoShopFunnelDTO>;
window.gh.data.destination(slugOrId): Promise<HippoShopDestinationDTO>;
window.gh.data.product(slugOrId):     Promise<HippoShopProductDTO>;

// Manually scan a subtree (e.g., a modal opened via JS):
window.gh.bind(myElement);

// Drop cached data and refetch + re-render everything:
window.gh.refresh();

// Formatter registry:
window.gh.format.currency(49.95);                     // "$49.95"
window.gh.format.register('shouty', v => v + '!');

Types come from @goldenhippo/hippo-shop-types — install it for IntelliSense in TypeScript projects.

Lifecycle events

| Event | When | |-------|------| | gh:data-ready | The synchronous setup is done — window.gh.data, bind, refresh, format are attached. | | gh:bindings-ready | The initial declarative bind pass has completed (DOMContentLoaded + first fetch). |

Both are dispatched on window.

Since the SDK boots synchronously when its <script> tag finishes loading, inline scripts placed below it may miss gh:data-ready. Use the defensive pattern:

function whenReady() { /* … */ }
if (window.gh && window.gh.data) whenReady();
else window.addEventListener('gh:data-ready', whenReady, { once: true });

Errors

The programmatic API rejects with GhError:

class GhError extends Error {
  readonly code:
    | 'not_found' | 'rate_limited' | 'forbidden'
    | 'bad_request' | 'network' | 'bad_config' | 'server';
  readonly retryAfterMs: number | null;
  readonly cause: unknown;
}

not_found is deliberately ambiguous between "doesn't exist" and "you're not authorized" — partners cannot enumerate resources they don't own.

Declarative bindings degrade gracefully: a failed fetch logs a warning and leaves placeholder text in place. Pages don't break because one slug is wrong.


Safety

  • All field values are rendered with textContent, never innerHTML — partner data cannot inject markup.
  • data-attr-on* is silently refused — event handlers can never be wired from data.
  • The SDK is read-only by design. No writes, no analytics ingestion, no PII.
  • Cross-brand requests return 404 from the API.

Size budget

Hard-budgeted at 8 KB gzipped, CI-enforced.

Provenance

Published with SLSA provenance attestation via npm Trusted Publishers + GitHub Actions OIDC. Look for the "Built and signed on GitHub Actions" badge on the package page — it links back to the exact workflow run that built the artifact.

License

MIT. See LICENSE.