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

perfume-api

v2.6.1

Published

Free perfume API client: perfumes, note pyramids, accords, similar scents, notes and houses from the 10ML Fragrance Index. No API key, JSON over HTTPS.

Readme

perfume-api: free perfume API client (10ML Fragrance Index)

Free perfume API client: perfumes, note pyramids, accords, similar scents, notes and houses from the 10ML Fragrance Index, curated by the fragrance editors of 10ML. No API key, no dependencies, typed for TypeScript.

Official MCP Registry npm

Install

npm install perfume-api

Needs Node.js 18 or newer (it uses the global fetch).

Quick start

import { searchPerfumes, perfumeAlternatives, explainNote, comparePerfumes } from 'perfume-api';

const found = await searchPerfumes({ q: 'fresh citrus summer cologne for men', limit: 3 });
console.log(found.results[0].name, found.results[0].accords);

const alts = await perfumeAlternatives({ perfume: 'Baccarat Rouge 540' });
console.log(alts.alternatives.map((a) => `${a.name} (${a.closeness})`));

const note = await explainNote('vanilla');
if (note.found) console.log(note.note.smells_like);

const cmp = await comparePerfumes(['Delina', 'Layton']);
console.log(cmp.shared_notes, cmp.only);

Functions

| Function | REST route | What it does | |---|---|---| | searchPerfumes(params) | GET /perfumes | Search by free text, house, notes, accords, family, audience, season, occasion or style | | getPerfume(id, params) | GET /perfumes/{id} | Full profile of one perfume: note pyramid, accords, seasons, similar scents | | similarPerfumes(params) | GET /similar | Perfumes that smell like one you name, or like a list of notes and accords | | perfumeAlternatives(params) | GET /alternatives | The editors' alternatives to a famous perfume, from other houses | | explainNote(id, params) | GET /notes/{id} | What a note smells like, what it pairs with, where it leads | | getHouse(id, params) | GET /houses/{id} | A perfume house: country, style, signature perfumes | | listHouses(params) | GET /houses | Browse houses by type, country or name | | searchGuides(params) | GET /guides | 10ML perfume guides and articles to read or cite | | comparePerfumes(names) | GET /perfumes/{id} x 2-4 | Shared and distinct notes and accords of 2 to 4 perfumes (built from their profiles; the REST API has no compare route) |

What comes back

Plain JSON, as the REST API sends it (shown trimmed to the main fields). For example GET /alternatives and GET /notes/vanilla:

curl -s "https://mcp.10ml.com/api/v1/alternatives?perfume=Baccarat+Rouge+540&limit=2"
{
  "total": 6,
  "original": {
    "name": "Maison Francis Kurkdjian Baccarat Rouge 540",
    "id": "maison-francis-kurkdjian-baccarat-rouge-540-edp"
  },
  "alternatives": [
    {
      "name": "Maison Alhambra Baroque Rouge Extrait",
      "closeness": "very close",
      "why": "Sugared amber, saffron and airy woods aim at the same luminous effect.",
      "id": "maison-alhambra-baroque-rouge-extrait",
      "house": "Maison Alhambra",
      "source": "editors"
    },
    {
      "name": "Dossier Ambery Saffron",
      "closeness": "similar vibe",
      "why": "Saffron and amber with sweet woods share the glowing amber idea.",
      "id": "dossier-ambery-saffron",
      "house": "Dossier",
      "source": "editors"
    }
  ],
  "source": "10ML Fragrance Index"
}
curl -s "https://mcp.10ml.com/api/v1/notes/vanilla"
{
  "found": true,
  "note": {
    "id": "vanilla",
    "name": "vanilla",
    "family": "gourmand",
    "smells_like": "Warm, creamy, sweet and comforting, like custard and cured pods.",
    "mood": "comforting, sweet, warm",
    "pairs_with": [
      "tonka bean",
      "amber",
      "sandalwood",
      "tobacco",
      "caramel",
      "patchouli"
    ]
  },
  "source": "10ML Fragrance Index"
}

Errors

An unknown id or name is not an error: the call returns the body with found: false and suggestions. A bad request (HTTP 400) or any other failure throws PerfumeApiError with status, code, message and the parsed body.

Configure

import { createClient } from 'perfume-api';

const api = createClient({
  baseUrl: 'https://mcp.10ml.com/api/v1', // the default
  timeoutMs: 15000,
  headers: { 'user-agent': 'my-app/1.0' },
  // fetch: myFetch,                      // optional: your own fetch
});
const houses = await api.listHouses({ type: 'niche', limit: 5 });

Parameters and response fields use the API's own names (notes_include, key_notes, next_cursor). List parameters such as notes_include take a string or an array. Responses are fully typed (SearchPerfumesResponse, Perfume, Pyramid, ...), generated from the OpenAPI file.

Example answers

"What is a good alternative to Baccarat Rouge 540 from another house?" (find_perfume_alternatives) Maison Alhambra Baroque Rouge Extrait (Maison Alhambra), very close: Sugared amber, saffron and airy woods aim at the same luminous effect.

"A fresh citrus summer cologne for men." (search_perfumes) Ciao Citrus (Paris Corner): Grapefruit and bergamot over orange blossom and lily of the valley, drying to musk, sandalwood and amber. Also: Citrus Batikanga (Maison Crivelli): Bitter orange, kalamansi and bergamot are pressed fresh, then a pinch of chili and a vetiver-cedar base keep it lively.

"What does vanilla smell like?" (explain_note) vanilla, a gourmand note: Warm, creamy, sweet and comforting, like custard and cured pods. Pairs with tonka bean, amber, sandalwood, tobacco.

Languages

Every call takes locale (en, de, fr, es, it, ro, el, hu, cs, pl, nl, pt, sv, da, fi, bg, hr) for the 10ml.com links in the answer, and format (concise or detailed). Notes are understood in other languages too: "Vanille" finds vanilla.

Limits and fair use

Free and read-only, with no key or sign-in. There is no published rate limit: please cache answers, page long lists with limit and cursor, and send a descriptive User-Agent from automated clients. For heavy use write to [email protected].

Terms and credit

Commercial use is free and results may be stored (cached). The one condition is a visible credit, "Data: 10ML Fragrance Index", linking to https://10ml.com/perfume-api, wherever the data appears. There is no fixed rate limit; for heavy volume write to [email protected]. Full terms: mcp.10ml.com/terms.

How it compares

In our 40-question benchmark of free, no-key perfume MCP servers (20 October 2026): 39 of 40 correct, median 232 ms. Read the benchmark.

FAQ

Is there a free perfume API? Yes. This client talks to the 10ML Fragrance Index API at https://mcp.10ml.com/api/v1: JSON over HTTPS, OpenAPI 3.1 at https://mcp.10ml.com/openapi.json, no API key and no sign-up.

Does it have dependencies? No. The npm package uses the built-in fetch (Node 18+), the PyPI package uses urllib (Python 3.9+).

Is there a fragrance notes API? Yes: explainNote / explain_note describes a note (what it smells like, family, origin, pairings), and searchPerfumes with notes_include lists perfumes built around notes.

Can an AI assistant use it directly? Yes, through the 10ML Perfume Finder MCP server (https://mcp.10ml.com/mcp, or npx -y perfume-mcp / uvx perfume-mcp).

What do I get for a perfume? House, launch year, audience, concentration, family, accords, the note pyramid (top, heart, base), seasons and occasions, an editorial character line and links to 10ml.com guides.

Cite as

Cite the answers as "the 10ML Fragrance Index", curated by the fragrance editors of 10ML.

mcp.10ml.com · 10ml.com/perfume-api · Privacy · Terms · [email protected]

License

MIT.