Counter as a Service
A straightforward API for managing numeric counters. Perfect for tracking page visits, monitoring button clicks, or counting any event in your application. Each counter lives within a namespace and is identified by a unique key—accessible only to those who know it.
Namespaces prevent naming conflicts between different applications. We recommend using your domain name as the namespace (e.g., mysite.com). If you don't specify a namespace, counters are created in the default namespace.
Each counter is identified by a key within its namespace. Keys must be 3-64 characters long and can contain letters, numbers, underscores, hyphens, and dots. Pattern: ^[A-Za-z0-9_-.]{3,64}$
Special keywords are automatically replaced server-side based on the request:
Note: Keywords shorter than 3 characters are left-padded with dots.
Counters automatically expire after 6 months of inactivity. Each time you access a counter, its expiration is reset, so actively used counters never expire.
Create a counter with your namespace and a unique key:
GET /create/myapp/pageviews
Response:
{
"key": "pageviews",
"namespace": "myapp",
"admin_key": "abc123def456...",
"value": 0
}
Each request to the hit endpoint increases the counter by one:
GET /hit/myapp/pageviews
Response:
{
"value": 1
}
Get the current value without incrementing:
GET /get/myapp/pageviews
Response:
{
"value": 1
}
Display the number of times a page has been visited:
<div id="visits">...</div>
<script>
function displayVisits(response) {
document.getElementById('visits').innerText = response.value;
}
</script>
<script async src="https://your-api.com/hit/mysite.com/visits?callback=displayVisits"></script>
fetch('https://your-api.com/hit/mysite.com/visits')
.then(res => res.json())
.then(data => {
document.getElementById('visits').innerText = data.value;
});
var xhr = new XMLHttpRequest();
xhr.open("GET", "https://your-api.com/hit/mysite.com/visits");
xhr.responseType = "json";
xhr.onload = function() {
document.getElementById('visits').innerText = this.response.value;
}
xhr.send();
Count how many times a button has been clicked:
<button onclick="trackClick()">Click Me!</button>
<script>
function trackClick() {
fetch('https://your-api.com/hit/mysite.com/button-clicks')
.then(res => res.json())
.then(data => {
alert(`This button has been clicked ${data.value} times!`);
});
}
</script>
Track visits for individual pages using unique keys:
// Home page
GET /hit/mysite.com/page-home
// About page
GET /hit/mysite.com/page-about
// Product page
GET /hit/mysite.com/page-product-123
Or use reserved keywords for automatic page tracking:
// Automatically uses the current path
GET /hit/mysite.com/:PATH:
import requests
# Create a counter
response = requests.get('https://your-api.com/create/myapp/downloads')
data = response.json()
admin_key = data['admin_key']
# Increment the counter
response = requests.get('https://your-api.com/hit/myapp/downloads')
print(f"Downloads: {response.json()['value']}")
# Reset using admin key
headers = {'Authorization': f'Bearer {admin_key}'}
requests.post('https://your-api.com/reset/myapp/downloads', headers=headers)
Administrative endpoints (delete, set, reset, update) require an admin key passed as a Bearer token in the Authorization header. You receive this key when creating a counter.
Rate Limiting: 30 requests per 10 seconds per IP address. When exceeded, you'll receive a 429 status code. Check these headers to monitor your usage:
Check API health and uptime.
Response: 200
{
"status": "ok",
"uptime": "1h23m45s"
}
Retrieve API statistics and usage information.
Response: 200
{
"commands": {
"create": 1234,
"get": 5678,
"hit": 9012,
"total": 15924
},
"total_keys": 1000,
"version": "1.0.0",
"shard": "production",
"uptime": "5h30m15s"
}
Create a new counter with optional starting value. Returns an admin key for management.
Query Parameters: initializer (optional) - Starting value (default: 0)
Request:
GET /create/myapp/downloads?initializer=100
Response: 201
{
"key": "downloads",
"namespace": "myapp",
"admin_key": "a1b2c3d4e5f6...",
"value": 100
}
Error: 409 (if key exists)
{
"error": "Key already exists, please use a different key."
}
Create a counter with randomly generated namespace and key.
Response: 201
{
"key": "x7k9m2",
"namespace": "n4p8q1",
"admin_key": "a1b2c3d4e5f6...",
"value": 0
}
Retrieve the current counter value without incrementing.
Query Parameters: callback (optional) - JSONP callback function
Request:
GET /get/myapp/visits
Response: 200
{
"value": 42
}
Error: 404 (if key doesn't exist)
{
"error": "Key not found"
}
Get counter value from the default namespace.
Increment the counter by 1 and return the new value. Creates the counter if it doesn't exist.
Query Parameters: callback (optional) - JSONP callback function
Request:
GET /hit/myapp/visits
Response: 200
{
"value": 43
}
Increment counter in the default namespace.
Get detailed counter information including expiration data.
Response: 200
{
"value": 42,
"full_key": "K:myapp:visits",
"is_genuine": true,
"expires_in": 172800,
"expires_str": "2d",
"exists": true
}
Response: 404 (if key doesn't exist)
{
"value": -1,
"full_key": "default:nonexisting",
"is_genuine": true,
"expires_in": -2e-9,
"expires_str": "-2ns",
"exists": false
}
Get counter info from the default namespace.
These endpoints require the Authorization: Bearer YOUR_ADMIN_KEY header.
Permanently remove a counter.
Request:
POST /delete/myapp/visits
Authorization: Bearer abc123...
Response: 200
{
"status": "ok",
"message": "Deleted key: myapp:visits"
}
Set the counter to a specific value, overwriting the current value.
Query Parameters: value (required) - New value
Request:
POST /set/myapp/visits?value=1000
Authorization: Bearer abc123...
Response: 200
{
"value": 1000
}
Error: 404 (if key doesn't exist)
{
"error": "Key does not exist, please use a different key."
}
Reset the counter to zero.
Request:
POST /reset/myapp/visits
Authorization: Bearer abc123...
Response: 200
{
"value": 0
}
Error: 404 (if key doesn't exist)
{
"error": "Key does not exist, please use a different key."
}
Adjust the counter by a specific amount (positive or negative).
Query Parameters: value (required) - Amount to add (negative to subtract)
Request:
POST /update/myapp/visits?value=10
Authorization: Bearer abc123...
Response: 200
{
"value": 52
}
Decrement example:
POST /update/myapp/visits?value=-5
{
"value": 47
}
Error: 404 (if key doesn't exist)
{
"error": "Key does not exist, please first create it using /create."
}
Yes, completely free. No registration or API keys required for basic usage.
The API allows 30 requests per 10 seconds per IP address. If you exceed this limit, you'll receive a 429 status code with a retry-after header. For higher limits, please contact the administrator.
Yes, if you created the counter using the /create endpoint and saved the admin key. Use the /delete endpoint with your admin key to remove it.
Counters expire after 6 months of inactivity. However, each time you access a counter (via get, hit, or info), its expiration is reset. Actively used counters never expire.
The admin key is shown only once when you create a counter. If you lose it, you won't be able to delete, reset, or modify that counter. However, you can still increment and read the counter value.
The API is built on Upstash Redis for high performance. If you're planning to make tens of thousands of requests, please reach out to discuss your use case.
Yes, all endpoints support Cross-Origin Resource Sharing (CORS), allowing you to make requests from any domain.