API

Semantic emoji search over HTTP

The same search that powers the app, as one GET request. Describe what you mean —“ship it”, “feeling great”, “we won” — and get ranked emoji back as JSON. Free, no key, CORS enabled.

curl "https://emoji.haxzie.com/api/v1/search?q=ship+it&limit=4"

Rank emoji for a phrase.

Query parameterTypeDescription
qstring, requiredThe phrase to search for. Up to 200 characters. Any language works, English works best.
limitinteger, optionalHow many results to return. 150, default 10.

Response

{
  "query": "ship it",
  "model": "@cf/baai/bge-small-en-v1.5",
  "took_ms": 41,
  "results": [
    {
      "emoji": "📦️",
      "name": "package",
      "group": "objects",
      "score": 0.612
    },
    {
      "emoji": "🚢",
      "name": "ship",
      "group": "travel-places",
      "score": 0.598
    },
    {
      "emoji": "🚚",
      "name": "delivery truck",
      "group": "travel-places",
      "score": 0.571
    },
    {
      "emoji": "🚀",
      "name": "rocket",
      "group": "travel-places",
      "score": 0.553
    }
  ]
}
FieldDescription
results[].emojiThe emoji character. May include a variation selector (U+FE0F).
results[].nameIts CLDR name.
results[].groupCategory: smileys-emotion, people-body, animals-nature, food-drink, travel-places, activities, objects, symbols, flags.
results[].skinsSkin-tone variants, when the emoji has them. Omitted otherwise.
results[].scoreRelevance. Semantic similarity plus a boost for literal name/keyword matches; higher is better, only meaningful relative to the other results for the same query.
took_msServer time for this request. Repeated queries are served from the edge cache in ~0 ms.

GET /api/v1/status

The model in use, how many emoji are indexed, and when the index was last rebuilt.

{ "model": "@cf/baai/bge-small-en-v1.5", "dimensions": 384, "emoji": 1914, "updated_at": "…", "rate_limit": "60 requests / minute / IP" }

Errors

Errors are JSON with an error code and a human-readable message.

StatuserrorWhen
400missing_queryq is missing or empty.
404not_foundNo such endpoint.
429rate_limitedMore than 60 requests in a minute from one IP. Wait for Retry-After seconds.
503index_emptyThe index is being rebuilt. Retry shortly.

Limits & caching

  • 60 requests per minute per IP. Enough for typing-as-you-search from a client; debounce on your side. Need more? Open an issue.
  • Identical queries are cached at the edge for an hour, so a popular phrase never reaches the model twice.
  • CORS is open (Access-Control-Allow-Origin: *): call it straight from a browser.
  • No authentication, no tracking. Requests aren't logged beyond Cloudflare's standard metrics.

How it works

Each emoji is described by its CLDR name, keywords and a handful of natural phrasings (“let's celebrate”, “shipping a release”). Those descriptions are embedded once withbge-small-en-v1.5 and stored. Your query is embedded on Cloudflare Workers AI at request time and compared against all 1,914 vectors in memory; a prefix search over names and keywords is blended in so that exact and partial words (“cele”) still win. The whole thing isopen source.

The Mac app and this website run the same ranking on-device with a different encoder (all-MiniLM-L6-v2), so results can differ slightly from the API.

Examples

JavaScript

const r = await fetch('https://emoji.haxzie.com/api/v1/search?q=' + encodeURIComponent('mind blown'));
const { results } = await r.json();
console.log(results.map((e) => e.emoji).join(' ')); // 🤯 🤩 💭 …

Python

import requests
r = requests.get("https://emoji.haxzie.com/api/v1/search", params={"q": "coffee break", "limit": 3})
print(" ".join(e["emoji"] for e in r.json()["results"]))  # ☕️ 🥤 🍻