Simple Free & Open Source Hit Counter for Blogs and Websites
Features β’ Self hosting β’ Configuration β’ API quick reference β’ Styling embeds β’ Public Instances
- Generate counters easily and embed them with one
<script>tag. - You can download a backup of your
data/counters.db(your database) as JSON in Settings or you can also download whatever counters you want as JSON (you can choose). - Multi-select toolbar lets you download per-counter JSON or delete groups of counters in one go.
- The dashboard gives you
search,pagination,inline edits,notes,filters, andauto-refreshing stats. - Toggle the instance between
public/privatehowever you like. - See 7-day activity charts and inactive badges so you can spot old or unused counters fast.
- Owner API keys so collaborators can manage their own counters without using the main admin password.
- Change your instance name and homepage title easily from the
Settings. - You can turn on per-IP limits for "Every visit" counters to slow down spam refreshes.
So yeah... it's pretty good :)
First, download Voux and enter the project folder:
git clone https://github.com/QuintixLabs/Voux.git
cd VouxMake sure you are running Node.js 22. If you use fnm :
fnm install 22
fnm use 22
node -vUse one of these:
npm install # normal install
npm install --production # for production installscp .env.example .envOpen .env and set your settings.
This is where you configure your admin token, site URL, port, and other options.
You must set ADMIN_TOKEN to something secret before running the server. For more settings check Configuration
Development (auto-reload) :
npm run devProduction:
npm startBy default, both commands run at: http://localhost:8787. You can change this by setting the PORT value in .env.
Or run Voux via Docker:
docker run -d \
--name voux \
-p 8787:8787 \
-e ADMIN_TOKEN=your-secret \
-v $(pwd)/data:/app/data \
ghcr.io/quintixlabs/voux/voux:latest- Change
ADMIN_TOKENto your own password (do not leave it as the example). - Mount
./dataso counters survive restarts. - Add more
-e VAR=valueflags for more settings if you need them.
Environment variables. You can tweak some of these options later from /settings without editing .env.
| Name | Default | What it does |
|---|---|---|
PORT |
8787 |
The web server port number. |
PUBLIC_BASE_URL |
based on request | Lets you set a fixed site URL (like https://counter.yourdomain.com). |
ADMIN_TOKEN |
unset |
A secret key is needed to access admin tools and the /dashboard page. |
PRIVATE_MODE |
false |
If true, only admins can create new counters. |
ADMIN_PAGE_SIZE |
5 |
How many counters show on each page in the admin panel. |
SHOW_PUBLIC_GUIDES |
true |
Controls if public guide cards are shown on the main page. |
DEFAULT_ALLOWED_MODES |
unique,unlimited |
Comma-separated list of modes to allow (unique, unlimited) for counters. You can change it later in the dashboard. |
COUNTER_CREATE_LIMIT |
5 |
How many counters a single IP can create before hitting the one-minute cooldown. |
COUNTER_CREATE_WINDOW_MS |
60000 |
Window length (in ms) for the above limit. Leave it alone unless you need a different window. |
INACTIVE_DAYS_THRESHOLD |
14 |
Days with no hits before a counter shows an "Inactive" badge in the dashboard. |
BRAND_NAME |
Voux |
Default display name (used in titles, hero text). You can override it in /settings. |
HOME_TITLE |
Voux Β· Simple Free & Open Source Hit Counter... |
The homepage <title> tag value. Editable in settings. |
UNLIMITED_THROTTLE_SECONDS |
0 |
Seconds to wait before counting the same IP again in "Every visit" mode. 0 disables throttling. Applies only on first boot, once data/config.json exists, update the throttle from /settings or edit that file (config.json) (deleting it will regenerate from .env). |
SQLite lives in data/counters.db. Back it up occasionally if you care about the numbers (or download a JSON backup from /settings, which now includes the 30-day activity summaries and your tag catalog). If you delete the DB file, Voux creates a fresh empty one on the next start, but all counters are wiped unless you restore from a backup.
GET /api/configβ tells the UI what's enabled:{ privateMode, showGuides, allowedModes, defaultMode, adminPageSize }.POST /api/countersβ create a counter (admin token required when private mode is on). Body at minimum:{ "label": "Blog Views", "startValue": 0, "mode": "unique" }. Add"tags": ["tag_id_here"]to auto-assign colored tags.GET /api/counters?page=1&pageSize=20&mode=unique&tags=tagA&tags=tagBβ paginated list of counters (admin only). Filter by counting mode and/or by one or more tag IDs.GET /api/counters/:idβ fetch a single counter plus its embed snippet (public; notes are omitted).GET /embed/:id.jsβ the script you drop into your site.DELETE /api/counters/:idβ delete a single counter (admin only).DELETE /api/counters?mode=uniqueβ delete every counter that uses the given mode (admin only). Omitmodeto delete everything.PATCH /api/counters/:idβ edit a counter's label, value, note, or tags (admin only).POST /api/counters/:id/valueβ set a counter's value directly (admin only).GET /api/settingsβ fetch the current runtime config (admin only).POST /api/settingsβ update runtime flags (private mode, guide cards, allowed modes, etc.).GET /api/counters/exportβ download every counter plus its 30-day activity summary and the tag catalog as JSON (admin only).POST /api/counters/importβ restore counters (and optional activity data/tag catalog) from a JSON backup (admin only).POST /api/counters/export-selectedβ body{ "ids": ["abc123", "def456"] }returns just those counters plus their daily stats (admin only). Includes the current tag catalog so you can restore the colors elsewhere.POST /api/counters/bulk-deleteβ body{ "ids": [...] }removes the specified counters (admin only).GET /api/api-keysβ list owner API keys (admin only).POST /api/api-keysβ create a new key (admin only).DELETE /api/api-keys/:idβ revoke a key (admin only).POST /api/counters/purge-inactiveβ delete counters that haven't seen hits in X days (admin only).GET /api/tagsβ list tag definitions (admin only). Used by the dashboard to render the tag pickers.POST /api/tagsβ create a new tag with{ "name": "Articles", "color": "#ff8800" }(admin only).
Every admin request needs the X-Voux-Admin: <token> header. For day-to-day management, just visit /dashboard, sign in once, and use the dashboard (it already calls these endpoints under the hood). Owner API keys use the X-Voux-Key: <token> header and can only touch the counters you assign to them.
Styling your counter with Voux is super simple. All you need to do is wrap your counter script inside an element. We'll use a <span> in this example:
<span class="counter-widget">
<!---------------------replace this with urs--------------------->
<script async src="https://your-domain/embed/abc123.js"></script>
</span>Once that's in place, you can style it however you like using CSS. Here's a simple example that centers the counter on the screen and makes the text black:
.counter-widget {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
text-align: center;
color: black;
font-weight: 600;
font-size: 3rem;
font-family: system-ui, sans-serif;
}And that's it. Your counter is now styled and ready to use. You can change the font, colors, or layout any way you like.
Voux keeps a simple list of "which IP hit which counter, and when" so it can avoid double-counting unique visitors. To wipe that list (for privacy or to give everyone a fresh start), run:
npm run clear-hitsThis keeps your counters and their values. It only clears the saved IP/timestamp pairs so future visits count again.
If you want to run your own public Voux instance and add it to the official public instances list, you can submit it here.
Voux is Free Software: You can use, study, share and modify it at your will. The app can be redistributed and/or modified under the terms of the GNU General Public License version 3 or later published by the Free Software Foundation.

