Public reactions API
Better Likes collects one piece of data that's genuinely interesting on its own: the aggregate reaction counts of pages across the web. The plan is to expose that data as a small, read-only HTTP API anyone can build on.
Principles
- Open data. Reaction counts are facts about public web pages. They will be served without authentication, without API keys, and without per-developer registration.
- No personal data, ever. The API will only ever expose aggregates. There is no "who reacted" endpoint and there never will be — the underlying database doesn't even associate identities with public targets in a way that could power one.
- Cache-friendly. Every response will set
Cache-ControlandETagheaders so the edge does the heavy lifting and your client doesn't pay for stale requests. CORS will be open to*. - Permissive licensing. The data will be released under CC0 / public domain. Attribution is welcome but not required. Use it in dashboards, research, art, browser extensions, blog widgets — whatever you want.
- Stable URLs. Endpoints will live under
/v1/. Breaking changes ship as/v2/; the old version is kept for at least 12 months after a successor lands.
Planned endpoints
1 · Per-target reactions
Get the full reaction breakdown for one public target — a Facebook post, a GitHub repo, an Amazon product, and whatever else is supported by the time the endpoint ships.
GET /v1/reactions/{site}/{targetId}
{
"site": "github",
"targetId": "khasky/betterlikes",
"total": 1284,
"counts": {
"❤️": 612,
"🔥": 301,
"👍": 189,
"🎉": 102,
"🤔": 80
},
"lastUpdated": 1747560000000
} 2 · Batch reads
The same shape, multiplexed. Useful for embedding counts on a listing page where you have many targets in one render.
GET /v1/reactions/batch?t=github/khasky/betterlikes&t=amazon/B08N5WRWNW 3 · Top pages
The most-reacted-to targets across a site, or globally, optionally windowed to a recent period. Useful for "what's everyone talking about right now" boards.
GET /v1/top?site=github&window=24h&limit=50
{
"window": "24h",
"items": [
{ "site": "github", "targetId": "user/repo", "total": 921 },
{ "site": "github", "targetId": "user/other", "total": 743 },
...
]
}
Supported windows under consideration: 1h,
24h, 7d, 30d,
all.
4 · Trending
Targets ranked by the rate of reactions in a window rather than the absolute count. A two-day-old post that gained 500 reactions today beats a five-year-old post that has 50 000 lifetime reactions but none today.
GET /v1/trending?site=facebook&window=1h&limit=20 5 · Emoji popularity
Which emojis are most-used as reactions — globally, per site, or per time window. Answers "what does the modern web feel like today?" in one chart.
GET /v1/emojis?site=&window=7d&limit=25
{
"window": "7d",
"items": [
{ "reaction": "❤️", "count": 184_402 },
{ "reaction": "🔥", "count": 97_215 },
{ "reaction": "👍", "count": 88_117 },
...
]
} 6 · Site activity
Time-bucketed totals per site: reactions per hour or per day, suitable for sparkline charts and longitudinal research. No targets, no users — just the count of votes landing in each bucket.
GET /v1/activity?site=amazon&bucket=hour&range=24h 7 · Aggregate site stats
A one-line summary per site: total reactions ever recorded, total targets observed, number of supported items by category, and the timestamp of the most recent reaction.
GET /v1/sites/{site}/stats
{
"site": "github",
"totalReactions": 412_900,
"uniqueTargets": 18_204,
"topReactions": [ "❤️", "🔥", "👍", "🎉", "💯" ],
"lastReactionAt": 1747560000000
} 8 · Discovery
A machine-readable manifest of which sites the extension currently supports and the schema version of their target IDs. Useful for third-party clients that want to mirror the supported list.
GET /v1/sites
{
"sites": [
{ "id": "facebook", "label": "Facebook", "schemaVersion": 1 },
{ "id": "github", "label": "GitHub", "schemaVersion": 1 },
{ "id": "amazon", "label": "Amazon", "schemaVersion": 1 }
]
} Embeds and widgets
Beyond raw JSON, two convenience surfaces are on the roadmap so non-engineers can embed counts on a blog or a project page:
- Live count badge — a tiny SVG image at a stable URL that always
shows the current top-three reactions for a target. Drop it in a README, a Markdown
post, or an
<img>tag anywhere.<img src="https://betterlikes.app/v1/badge/github/khasky/betterlikes.svg"> - oEmbed endpoint — so platforms that already understand oEmbed (Ghost, WordPress, Substack, …) can unfurl a Better Likes target URL into an interactive reaction strip without a plug-in.
- Webhooks. Subscribe to a target and get a POST when its reaction count crosses a threshold you set. Useful for site owners who want to know when their post breaks out.
Rate limits and fair use
Every endpoint will sit behind a per-IP rate limit chosen so a normal dashboard never hits it. Heavy users — research crawlers, public dashboards with global reach — should reach out before the first launch so the budget can be tuned rather than tripped.
Responses will set
X-RateLimit-Remaining and
X-RateLimit-Reset headers, and a
429 will always include a Retry-After
value. Edge caching means most repeat fetches are free at the client.
What it will not do
- No reaction submission via the public API. Votes will always go through the extension's authenticated path. A public submit endpoint would defeat the one-person-one- vote guarantee that makes the counts worth reading in the first place.
- No identity lookups. Not by email, not by hash, not by anything else. The public API only knows about counts.
- No private targets. If a page requires authentication to view, the extension doesn't record reactions for it and the API has nothing to return.
- No data resale. The data is free, including for commercial use under CC0. We will not turn around and start gating it behind paid tiers.