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

vitalityfit

v1.2.0

Published

Compare prices of health products (medicines, supplements, cosmetics) from German online pharmacies and drugstores by name, PZN or EAN barcode: free price API client and CLI with cheapest offers, shipping costs, stock and 90-day low, no API key

Readme

vitalityfit

Compare prices of health products (medicines, supplements, cosmetics) from German online pharmacies and drugstores. Look a product up by name, PZN (the German pharmacy product number) or EAN barcode and get the cheapest current offers: shop, price, shipping cost, stock, delivery time, unit price and the lowest price of the last 90 days.

A small client and command line tool for the free Vitalityfit Price API: no API key, no login, no dependencies.

Deutsch: Preisvergleich für Apotheken- und Drogerieprodukte aus deutschen Online-Shops und Versandapotheken, per Name, PZN oder EAN. Daten von vitality-fit.de.

Command line

npx vitalityfit ibuprofen
npx vitalityfit 01568889 --pack "30 st"
npx vitalityfit "orthomol immun" --json

The command searches for the product, then lists the cheapest offers for the best match: shop, price, shipping cost, stock, delivery time, unit price and shop link, plus the lowest price of the last 90 days. A PZN or EAN shows the offers for exactly that pack. Affiliate links are marked (affiliate). The exit code is 1 when there is nothing to show (no product, pack size not found, no current offers) or on an error, and 2 on a usage error.

| Option | Meaning | |---|---| | -p, --pack <size> | Pack size, e.g. "20 st", or a pzn_/ean_ key (default: the pack size with the most offers) | | -l, --limit <n> | Number of products to search, 1-10 (default 5) | | --json | Print the API answers as JSON |

Library

Node 18 or later, browsers, Deno and Bun (ES module, uses the global fetch). From CommonJS, load it with await import('vitalityfit').

npm install vitalityfit
import { searchProducts, listOffers } from 'vitalityfit';

const { products } = await searchProducts('ibuprofen 400', { limit: 3 });
const best = products[0];
console.log(best.title, best.cheapest_price, best.pack_sizes.map((p) => p.label));

const result = await listOffers(best.product_key, { packSize: '20 st' });
for (const offer of result.offers) {
  console.log(offer.shop, offer.price, offer.shipping_cost, offer.link);
}
// Show these with the offers:
console.log(result.compliance_notice ?? '', result.disclosure);
  • searchProducts(query, { limit }): up to 10 products (default 5), best match first. Each has product_key, title, brand, pack_sizes, cheapest_price (EUR), shop_count, url, image_url (when the product has an image) and, for a PZN or EAN, matched_pack (the cheapest offer of the pack that holds that PZN/EAN). For medicines also compliance_notice.
  • listOffers(productKey, { packSize }): up to 10 offers, cheapest first (each with shop_logo_url when the shop has a logo), for one pack size (default: the pack size with the most offers). packSize takes a pack's identity_key when it has one, else its label; a pack is one pack-size label as on the product page and can hold several PZNs (an original and its reimports). The answer also has disclosure, low_90d, data_date, image_url (when the product has an image) and, for medicines, compliance_notice. An unknown pack size gives message: "pack size not found" with available_packs.
  • Both take { signal, fetch, baseUrl } as further options. TypeScript types are included.

Errors are thrown as VitalityfitError with status, code and, when rate-limited, retryAfter in seconds. Codes from the API: invalid_argument, not_found, rate_limited, internal, unavailable; from the client: http_error (an answer that is not the API's JSON), network (no answer) and no_fetch. A not_found (HTTP 410) for a product key means the product was merged or delisted: search again by name, PZN or EAN for its current key. A 429 without retryAfter means the service is busy: retry after a few seconds. Aborts and timeouts from signal are passed through.

Limits

  • One request per 10 seconds per IP address on average (12 in 2 minutes); above that the API answers 429 with Retry-After. The command line tool uses two requests per search.
  • Answers are cached for up to 1 hour.

Terms in short

  • Free for personal and non-commercial use, including free apps. Commercial use only by agreement: [email protected]
  • Name the source "Preise: vitality-fit.de" with a link to https://vitality-fit.de/ and keep shop links unchanged.
  • For medicines, show the compliance_notice together with the results.
  • No bulk download, mirroring or resale of the data.
  • Prices only, no medical advice. Prices may have changed since; the price in the shop applies. Shop links can be affiliate links: vitality-fit.de may earn a commission, and the price does not change for the buyer.

Full terms: vitality-fit.de/api (the German version is binding).

For AI assistants

The same data is available as an MCP server at https://vitality-fit.de/mcp (streamable HTTP, no login), listed in the official MCP Registry as de.vitality-fit/prices. Setup for Claude, ChatGPT and other clients: vitality-fit.de/mcp.

License

The code is MIT licensed. The price data is subject to the API terms above.