Appreciate Button

Clap · applause · like button · open source · one tag

A tiny clap button for any page.

A Medium-style clap, applause or like button for your blog or site. Visitors click an icon that fills up as they go. Counts are kept per page and capped per visitor, on the hosted instance or a server you run. No cookies, no accounts, no tracking pixels.

Try it. Click up to ten times.

It starts gray and fills with colour from the bottom a little more with each click, with a little burst every time. After ten it's full and stops counting. Reload the page: your clicks are still spent, because the cap is enforced on the server, not in your browser. Reset my votes gives you ten more here, on this demo only.

Install

The server hands you this tag when you create a button. Paste it where the button should appear.

<script src="https://your-instance.example/widget.js" data-key="pk_…" async></script>

Let your agent add it

Using Claude Code, Cursor or another coding agent? Paste this prompt into it. It asks for your button's key, then puts the tag at the end of your post template, and that's it. The dashboard has the same prompt for each button with its key filled in. Your part: make sure the site's address is in the button's allowed origins.

Loading the prompt…

Works with your platform

Step-by-step guides with the exact file to edit, for a like or clap button on every post:

Make it yours

The icon and its four colours live on the server, so every site that embeds a button sees the same thing. A page can still override colours and size with plain CSS; the count and the spacing grow with the icon.

appreciate-button {
  --appreciate-size: 2.5rem;
  --appreciate-full: gold;
  --appreciate-clicked: orange;
}
appreciate-button {
  --appreciate-default: currentColor;
  --appreciate-hover: currentColor;
  --appreciate-clicked: currentColor;
  --appreciate-full: currentColor;
}
<appreciate-button
  data-key="pk_…"
  data-label="Clap for this">
appreciate-button {
  --appreciate-size: 3rem;
}

Where the count goes

Put data-count on the tag to place the number on any side of the icon. It defaults to right.

data-count="right"
data-count="left"
data-count="top"
data-count="bottom"

Read-only

Add data-readonly to show the count without taking clicks, say on a list of posts that each link to the page with the real button. This one reads the main demo's count: click the heart at the top and it follows, but it cannot be clicked itself.

<script src="https://your-instance.example.com/widget.js"
  data-key="pk_…" data-readonly async></script>

Want a different icon? Any single-colour outline SVG works: a CLI strips its colours so the four states can restyle it. Icons that need four different drawings can be supplied as four SVGs.

Listen to it

The button tells the page what happens through DOM events. They bubble and cross its shadow root, so one listener on document hears every button on the page: event.target is the button, and event.detail carries the data. All of them are optional; the button works the same whether anything listens or not.

Event Fires event.detail
appreciate:ready Once the button has loaded and shows its count. counts
appreciate:burst On every click, counted or not; a spent button plays no burst. counts, as shown right after the click
appreciate:change When the server confirms a counted click. counts
appreciate:maxed Once, when the click that uses up the visitor's allowance is confirmed. counts
appreciate:error When loading or a click fails. { code, message }

The counts are { totalCount, maxClicks, visitorCount, visitorRemaining, maxed }: the total from everyone, this visitor's cap, how many they have used and have left, and whether they are out.

<script>
  document.addEventListener('appreciate:ready', (event) => {
    console.log('loaded with', event.detail.totalCount);
  });
  document.addEventListener('appreciate:burst', (event) => {
    console.log('clicked', event.target, event.detail.totalCount);
  });
  document.addEventListener('appreciate:maxed', () => {
    console.log('all clicks used, say thanks');
  });
  document.addEventListener('appreciate:error', (event) => {
    console.warn(event.detail.code, event.detail.message);
  });
</script>
Live, from the demo at the top: click it and watch.

    How it works

    1. The tag loads the bundle from your instance and renders a <appreciate-button> in a shadow root, isolated from the page's CSS.
    2. It fetches the button config and the page's counts in parallel, painting from a small localStorage cache first so there is no flash.
    3. Each click is sent one at a time. The server increments inside a guarded transaction, so two tabs clicking at once cannot push a visitor past the cap.
    4. The cap is per visitor, per page. Visitors are told apart by a keyed hash of IP address and browser, never stored raw. Clearing storage does not reset it; changing networks does. It is an abuse deterrent, not a ballot box.

    Several buttons, one page

    Load the bundle without data-key and place elements yourself. Give each an data-item and they count separately — comments, cards, or a single-page app that changes routes without reloading.

    <script src="https://your-instance.example/widget.js" async></script>
    …
    <appreciate-button data-key="pk_…" data-item="post-1" data-count="left"></appreciate-button>
    <appreciate-button data-key="pk_…" data-item="post-2" data-count="left"></appreciate-button>

    Why we count per page, not per site

    One key, many pages: the counter follows the URL, so a single button serves a whole blog without any setup per post.

    Four states from one SVG

    Hand over an outline icon and the widget recolours it for idle, hover, click and full. No sprite sheets, no second file.

    A cap without cookies

    Ten clicks per visitor, enforced server-side from a keyed hash, with no IP address stored and nothing set in the browser.

    Questions

    Is it like Medium's clap button?

    Yes: readers can clap several times, and each clap fills the icon a little more. Medium allows 50 claps per story; here you choose the limit per button, from 1 to 1,000. More on Medium claps.

    Can it be a plain like button?

    Set a button to one click per visitor and it is a classic like button. See the like button page.

    Does it use cookies?

    No. Visitors are told apart by a keyed hash of IP address and browser, which is never stored as is. The widget keeps a small cache of counts in localStorage so the page does not flash.

    Do I need to run a server?

    No. Sign in with GitHub on the hosted instance and create a button. If you would rather keep the data yourself, the same server runs anywhere with Node.js and MySQL.

    I used the Applause Button. Can I switch?

    Its free hosted service no longer runs. Replacing its tags with one Appreciate Button tag is most of the move. How to switch.

    Does it work with single-page apps?

    Yes. The button notices client-side navigation and loads the new page's count by itself, in React, Next.js, Astro and the rest.