JS widgets
No-code image embeds
Custom event API
Public (no auth required)

grow your website with engaging tools.

counters, upvotes, ratings & user stats.

No signup required

easy and free to install

It only takes a few minutes to install our tools or integrate the API.
The best part? Theyโ€™re free. No paid plans, no contracts, no hidden feesโ€”ever.
We can keep this service free because also work with enterprises on custom features.
That's our way to give back to the internet and get some visibility at the same time.

Get Started View Samples

free tools

Add these to any website


Use them at the end of your articles, in website headers on in lists. You can track page views, or any custom actions you'd like. View code...

like/vote buttons

Use them at the end of your articles, in website headers, or for custom actions. View code...

Yes / No

Ask your users for feedback and display the results. View code...

Would you recommend this product? Was this article helpful?

Activity notifications

Ask your users for feedback and display the results. View code...

Sam from Austin, TX ๐Ÿ‡บ๐Ÿ‡ธ
signed up to the neweleter
5 minutes ago verified by Counter

invisible pixel

You cant track conversions and measure events without necessarily displaying a widget or counter at the same time.

img badges

No JS required. Works in Notion, Github and basically anywhere. View code...

quick start

embed a counter

This is the recommended way to add the counter on your site.
The integration consist of a small JS library and an html tag with configurable attributes.

<!-- counterAPI library, insert anywhere on the page. -->
<script src="https://counterapi.com/c.js" async ></script>
<!-- Add the counter instance somewhere to your template... -->
<div class="counterapi" style="min-height:44px" ></div>

Done! ๐Ÿ‘ You should see a counter that look like this:

Note: You can specify your website domain directly in the script tag (useful for test environments, or apps that use more than one domains).

<script src="https://counterapi.com/c.js?ns=mysite.com" async ></script>

limits & pricing

This is a free, public API. No accounts, keys or authentication required.
There is a soft limit of 100k daily requests that we lift after a quick verification.

custom dev

For a small monthly fee, you can get hands-on support and advanced features like advanced analytics, authentified calls, filtering rules, CSV data exports, custom property tracking, whitelabel integrations, or customized branding.

Tell us about your projects to see how we could work together.

options โš™๏ธ

Customize how your counters work.

Param Default
startNumber 0 Got some legacy pageviews that you need to account for? Add them up to the ones tracked in CounterAPI here.
behavior view view, vote or rate. Using the vote and rate behavior will only increment the counter on button clicks.
readOnly false Display a count, but don't increment its value. Useful to show counts of multiples items within a list. (ex: user dashboards, list of videos). If you use aggregations like any keys/actions, you requests will automatically be read-only.
trackOnly API only. Track an event without returning a count, slightly faster. If you post events server side and don't need the count, consider enabling this flag to save us some precious server ressources

These options can be set as attributes on the DIV tag or passed as URL params to the API:

<!-- all settings are passed as attributes... -->
<div class="counterapi"   readOnly="true" startNumber="42000" key="homapage"  ></div>

Or using the API...

โ‡’ 200 {
  "value": 42005,
  "abv": "42K"

styling options ๐Ÿ’๐ŸŽจ

You can customize the way your embeded counters look and behave in various ways.

Param Default
icon eye Customize the icon. (eye, heart, star, etc). Here is the full list of supported icons
abbreviate false Abbreviates large numbers (2M, 5k, etc). Great for lists and summaries
label - Display a unit next the number on the badge. Ex: "views", "votes", "likes", or "downloads"
timeline total Count modifier. You can use a duration notation (15m, 12h, 30d, etc) to only count recent events. Use this for a "currently watching" kind of counter.
unique false Count modifier. Set to true if you want to count unique users instead of events. Especially useful for aggregations using any key or action. For example, all users who watched any videos in the last 30 days. By default, aggregation are done on generated user hashes. If your user are authentified, set userId on your events to better inform this aggregations.
hideIfZero false Hide the widget when the count is zero. ex: Avoid showing '0 people booked this room today'
noNumber false Useful for voting buttons where you just want to show text on the button. ex: 'Upvote this!'
labelVoted - Custom text to display in place of the count after a user upvote. By default, we simply increment the count.
color #ccc (light grey) Text color. Named colors and #hex values work. (#ff0000, red, pink, etc)
bg #000 (black) Background color. Use transparent if you don't want the button/badge look
iconColor #f00 (red) If you want your icon to be a different color than your text.
invisible false Hide the widget
noCss false Disable all styling. Write your own css.
noIcon false Hides the badge icon
noLink false Disable the link to the traffic trends report. You can disable the link even on the free service, but please consider including a link to CounterAPI.com somewher on your page.
noFormatting false By default, long numbers are automatically formatted to the user's locale (ex: 3,000,000)
animDuration 3000 Duration of the counter animation when it loads. In Ms.
noAnim false Disable initial counter animation

These options are set directly on your counter div tag. ex:

<!-- Display a plain text, abbreaviated count to display in a list. -->
<div class="counterapi" noIcon="true" noCss="true" abbreviate="true" startNumber="50000"  ></div>
Will look like this:

IMG badges options

The badge integration is pretty basic. Everything is set via URL parameters. If you manually set the ns, action and key url params, you can preview your badges URLs directly as a browser URL.

If you don't specefy a key and namespace, the current URL and domain will be used as key and namespace.

<img src="https://counterapi.com/counter.svg?key=hehe&color=ff0000&style=for-the-badge&label=bingos">
Param Default
label views Text shown on the right side of the badge
style view social, flat or big. Using the vote and rate behavior will only increment the counter on button clicks.
labelColor false Set background of the left part (hex, rgb, rgba, hsl, hsla and css named colors supported).
color Set background of the right part (hex, rgb, rgba, hsl, hsla and css named colors supported).

All the other usual counterAPI settings can be set too.
For example: readOnly,startNumber, ns, action and key

Invisible IMG pixel

Track and measure events, without showing a count. Similar to using "invisible=true" on the HTML snipet. Requires no JS, so possibly easier to integrate in some systems.

<img src="https://counterapi.com/pixel.gif?action=purchase&key=red-shoes">

Advanced events ๐Ÿท๏ธ

setting your namespace, actions & keys


Specifying the ns, action and key in counters future-proof your setup and gives you neat traffic reports.

Param Default
ns current domain Namespace for all your tracked events. Use your domain name to avoid conflicts and improve filtering.
action "view" or "vote" Action name to group your events. Allows you to assign the same key on different events types (ex: Use the "productID" as a key for "productPage", "productPurchase" and "productReviews" actions). You could just bundle everything together in the key field, but setting "action" values will help you generate clearer trends and analytics reports. Use any to select all events for the name space (ex: use with a 30minutes timeline to show currently online users).
key current page url The unique identifier to identify your counter. By default, you'll have different counts on all your website pages. If you plan on using the API (and not just the embed), we strongly suggest you setup keys manually. Use any to select all events for your action. (ex: get a count of all the videos views on a website). Using any won't increment any counts (make it readOnly).


The default setup uses the page URL as the key.
This has some limitations. For example, if we have a store that shows the same product on two slightly different pages, we might want to use the same counter on both pages.
This can be done by passing a unique productId to our counters. Article slug, author name, or anything unique that defines your content works too.

<!-- This will increment and shows the count for "myProduct1234" -->
<div class="counterapi" key="productId1234"  ></div>

If you want to count different type of events on those keys, you can group them by action.
Defaults to "view" when unspecefied.

 <!-- Count pageviews separately using the same key, but a different action -->
<div class="counterapi" key="Batman" action="superheroProfilePage" ></div>
<div class="counterapi" key="Batman" action="superheroPhotos" ></div>

Grouping stuff in action keeps your events neatly organized and will let you create aggregate reports in your dashboard.

We scope all your events under your website domain, but it's a good practice to set your ns (namespace) manually for more control. This is required to share counts between your mobile app and web version, or if your website URL ever change.

 <!-- Hardcoded the namespace to retrieve counts from a different website, or to use in a mobile app. -->
<div class="counterapi" ns="superhero.com" ></div>

Example with all three fields specified manually:

 <!-- Custom events, neatly tracked -->
<div class="counterapi" ns="superhero.com" key="Batman" action="superheroProfilePage" ></div>

track more user properties

You can pass more attributes via the tag or API URL and these will be saved to your events. While it's not possible to retrieve this data using the public feeds, you'll be able to retrieve it with CSV downloads and authentified API calls.

Param Value
myProperty String Track additional property in your events. Retrieve them using CSV downloads, the authentified API, or advanced reports.

The API works the same way. Just throw in your variables as extra parameters.

โ‡’ 200 { "value": 42005, "abv": "42K" } // "ref", "userId" & "campaignId" will be recorded for your events. // Custom data points don't change the displayed count.

Accessing the api ๐Ÿค–

You can fetch and increment counts using simple requests. This is a good alternative to the embeds if you want to do some math on the numbers, need more control over the presentation, or just can't add our (tiny) library to your stack.

using the browser library ๐Ÿงช

<!-- load the browser library-->
<script async src="https://counterapi.com/counterapi.embed.js"></script>

// later... when a user vote
var key = 'product123'
var action = 'upvoteProduct'
var namespace = 'mysite.com'
var options = { startNumber: 300, behavior: 'vote' } //see options list

counterApi.read(key, action, namespace, options, function(err, res){
  alert('Current number of votes for this: '+ res.value);
  //do something ...

//increase a counter
counterApi.increment(key, action, namespace, options, function(err, res){
  alert('New upvote cout is now '+ res.value);
  //do something ...

API endpoints

Most data tracking and retriving happens on a single endpoint leveraging the same settings than the HTML widgets (beside the cosmetic ones).
The URL parameters are all optional, but you need to specefy your ns, action andkey in the URL.


using jsonp

function cb(response) {
  document.getElementById('visits').innerText = response.value;
<script async src="https://counterapi.com/api/mysite.com/view/product123?callback=cb"></script>

using xhr

var xhr = new XMLHttpRequest();
xhr.open("GET", "https://counterapi.com/api/mysite.com/view/product123");
xhr.responseType = "json";
xhr.onload = function() {
    document.getElementById('visits').innerText = this.response.value;

using jquery

$.getJSON("https://counterapi.com/api/mysite.com/view/product123", function(response) {
    alert(response.value + ' views on product #123')


Data privacy ๐Ÿ•ต๏ธ

We don't like tracking. We anonymize all personal data (IP adresseses and browser details) into untrackable hashes. We don't sell data & we don't work with any advertisers; we just provide simple counters and stats.

preventing content shift

To prevent your page content from shifting when the counter loads, we pre-set the counter height with this inline style style="min-height:44px". Alternatively, you can use the following CSS defenition (in framework like React, or if you're concerned with inline-styles creeping into your templates). In all cases, it is safe to remove that inline-style.


prevent cheating

It's possible to artificially boost pageviews, but not that easily.
We take various measure to detect abuses, duplicate pageviews, and spam-bots. We're doing an okay job: wannabe cheaters would need to waste quite some time reverse-engenieering our filters. And even then, they'll have limited mileage before getting caught. Without captchas or user authentification, there will always be giant holes in the security, so it's best not to run presidential election with our free tools. This public approach remains a pretty good tradeoff beteween friction and reliability.

If you want to more robust data-handling, we can adjust the filter and aggregation settings for your projects. You can also authenticate all your pageviews and votes with encrypted userIds.


The JS library doesn't load third party JS. The only dependency is jQuery and we want to convert everything to pure JS for obvious reasons.

We hope you make good use of these free tools. It's an early-stage project and we're actively working on the documentation. Feel free to write to us if you have any questions.

Get in touch
ยฉ 2021, Counter API - All product names, logos, brands and dogs are property of their respective owners.
Feel free to check out our privacy policy and terms of service.