- Updated: March 19, 2026
- 7 min read
Step-by-Step Guide: Implementing OpenClaw Rating API Edge CRDT Token‑Bucket Operator
The OpenClaw Rating API Edge CRDT token‑bucket operator can be built, deployed, and tested on ubos.tech in just a handful of steps, using the ubos.tech CLI, a simple JavaScript/TypeScript schema, and a few deployment commands.
This developer‑focused guide walks you through the entire workflow—from prerequisites to troubleshooting—so you can integrate a high‑performance, rate‑limited rating engine into any real‑time application.
1. Introduction
What is OpenClaw Rating API Edge CRDT?
OpenClaw is an open‑source framework that provides a Rating API built on top of Edge CRDTs (Conflict‑Free Replicated Data Types). Edge CRDTs enable deterministic, eventually consistent state across distributed nodes without a central coordinator. The Rating API exposes operations such as upvote, downvote, and score, all stored in a CRDT that automatically resolves conflicts.
Why use a token‑bucket operator?
Real‑time rating systems often face burst traffic (e.g., a viral post receiving thousands of votes per second). A token‑bucket operator throttles incoming requests by allowing a fixed number of tokens to be consumed per time window. When the bucket empties, further requests are queued or rejected, protecting your backend from overload while preserving a smooth user experience.
2. Prerequisites
- Node.js ≥ 18 (LTS recommended)
- npm or yarn for package management
- An ubos.tech account (free tier works for testing)
- Git installed locally
- Basic familiarity with TypeScript or JavaScript
Environment setup
Open a terminal and run the following commands to prepare your workspace:
# Create a project folder
mkdir openclaw-token-bucket && cd $_
# Initialise a Node project
npm init -y
# Install ubos.tech CLI (global)
npm i -g @ubos/cli
# Install TypeScript and required libs
npm i -D typescript @types/node
npm i openclaw-sdk
After installing, initialise a TypeScript configuration:
npx tsc --init --rootDir src --outDir dist --esModuleInterop3. Step‑by‑Step Implementation
3.1 Creating the token‑bucket CRDT schema
Open a new file src/tokenBucket.ts and define the schema. The schema uses OpenClaw’s CRDTMap to store tokens and lastRefill timestamps.
// src/tokenBucket.ts
import { CRDTMap } from "openclaw-sdk";
/**
* TokenBucketCRDT represents a simple token‑bucket rate limiter.
* - capacity: maximum tokens the bucket can hold
* - refillRate: tokens added per second
*/
export interface TokenBucketCRDT {
capacity: number;
refillRate: number;
}
/**
* Initialise a bucket with default values.
*/
export function createBucket(
capacity: number,
refillRate: number
): CRDTMap {
const bucket = new CRDTMap();
bucket.set("tokens", capacity);
bucket.set("lastRefill", Date.now());
bucket.set("capacity", capacity);
bucket.set("refillRate", refillRate);
return bucket;
}
3.2 Writing the Edge function
The Edge function lives in src/edgeHandler.ts. It receives a rating request, checks the token bucket, and either processes the vote or returns a 429 Too Many Requests response.
// src/edgeHandler.ts
import { Request, Response } from "openclaw-sdk";
import { createBucket } from "./tokenBucket";
const DEFAULT_CAPACITY = 100; // 100 votes per minute
const DEFAULT_REFILL_RATE = 100 / 60; // tokens per second
// Initialise a shared bucket (in a real deployment you’d store this in a persistent CRDT)
const bucket = createBucket(DEFAULT_CAPACITY, DEFAULT_REFILL_RATE);
/**
* Refill tokens based on elapsed time.
*/
function refill() {
const now = Date.now();
const last = bucket.get("lastRefill") as number;
const elapsed = (now - last) / 1000; // seconds
const refillAmount = Math.floor(elapsed * bucket.get("refillRate") as number);
if (refillAmount > 0) {
const newTokens = Math.min(
bucket.get("tokens") as number + refillAmount,
bucket.get("capacity") as number
);
bucket.set("tokens", newTokens);
bucket.set("lastRefill", now);
}
}
/**
* Edge entry point for rating actions.
*/
export async function handler(req: Request, res: Response) {
// Only allow POST /rate
if (req.method !== "POST" || req.path !== "/rate") {
return res.status(404).send("Not found");
}
refill(); // Ensure bucket is up‑to‑date
const tokens = bucket.get("tokens") as number;
if (tokens <= 0) {
return res
.status(429)
.send({ error: "Rate limit exceeded. Try again later." });
}
// Consume a token
bucket.set("tokens", tokens - 1);
// Simulate rating logic (e.g., increment a score CRDT)
// In a real app you’d call another CRDT operation here.
const { itemId, vote } = req.body;
// ... rating logic omitted for brevity ...
return res.status(200).send({ success: true, itemId, remaining: tokens - 1 });
}
3.3 Deploying with ubos.tech CLI
ubos.tech uses a ubos.yaml manifest to describe Edge functions, runtime, and permissions. Create the file at the project root:
# ubos.yaml
name: openclaw-token-bucket
runtime: nodejs18
entrypoint: dist/edgeHandler.handler
permissions:
- read
- write
environment:
NODE_ENV: production
Compile TypeScript to JavaScript before deployment:
npm run build # assuming "build": "tsc" in package.jsonNow initialise the project on ubos.tech and push the code:
# Log in (first time only)
ubos login
# Initialise a new ubos project
ubos init
# Deploy the Edge function
ubos deploy
After a successful deployment, ubos.tech will output an endpoint URL, e.g., https://api.ubos.tech/openclaw-token-bucket. You can now send POST requests to /rate on that URL.
4. Deployment Commands
| Command | Purpose |
|---|---|
ubos login | Authenticate your local CLI with your ubos.tech account. |
ubos init | Create a new ubos project and generate ubos.yaml if missing. |
npm run build | Compile TypeScript sources to dist/. |
ubos deploy | Push the compiled Edge function to the ubos cloud. |
ubos logs --tail | Stream live logs for debugging. |
5. Testing the Operator
5.1 Unit tests with Jest
Install Jest and write a quick test for the refill logic.
npm i -D jest @types/jest ts-jest
npx ts-jest config:init
// tests/tokenBucket.test.ts
import { createBucket } from "../src/tokenBucket";
test("refill adds tokens based on elapsed time", () => {
const bucket = createBucket(10, 1); // 1 token per second
// Simulate 5 seconds passing
const now = Date.now();
bucket.set("lastRefill", now - 5000);
// Call internal refill (exposed for test only)
// @ts-ignore
bucket.refill();
expect(bucket.get("tokens")).toBe(10); // capped at capacity
});
5.2 Integration test with curl
After deployment, verify the rate‑limit works:
# Replace ENDPOINT with the URL from ubos deploy
ENDPOINT="https://api.ubos.tech/openclaw-token-bucket/rate"
# Send 5 rapid votes
for i in {1..5}; do
curl -X POST $ENDPOINT \
-H "Content-Type: application/json" \
-d '{"itemId":"post123","vote":1}'
echo "" # newline for readability
done
If the bucket is exhausted, you’ll receive a JSON payload with error: "Rate limit exceeded" and HTTP status 429.
6. Troubleshooting Tips
| Symptom | Possible Cause | Fix |
|---|---|---|
| All requests return 429 immediately | Bucket capacity set to 0 or negative | Check DEFAULT_CAPACITY in edgeHandler.ts and ensure it’s a positive integer. |
| Tokens never refill | `lastRefill` timestamp not updated after refill | Verify the refill() function sets lastRefill to Date.now(). |
| Deployment fails with “Missing runtime” | Incorrect runtime field in ubos.yaml | Use nodejs18 or a supported version listed in ubos docs. |
| Logs show “CRDTMap is undefined” | Package openclaw-sdk not installed or mismatched version | Run npm i openclaw-sdk@latest and rebuild. |
| High latency on rating endpoint | Bucket refill logic runs on every request; heavy CPU load | Cache the refill calculation for a short interval (e.g., 100 ms) or move it to a background Edge worker. |
7. Conclusion
By following this OpenClaw Rating API Edge CRDT token‑bucket operator tutorial, you now have a production‑ready, rate‑limited rating service that scales across edge nodes without sacrificing consistency. The combination of CRDTs and a token‑bucket algorithm gives you deterministic conflict resolution and protection against traffic spikes.
Next steps could include:
- Persisting the bucket state in a distributed KV store for cold‑start recovery.
- Extending the operator to support multiple rating categories (e.g., likes, dislikes, stars).
- Integrating with Host OpenClaw to manage multiple rating micro‑services from a single dashboard.
Remember, the key to a smooth real‑time experience is not just the algorithm but also observability. Use ubos logs and set up alerts on the 429 rate‑limit metric to stay ahead of traffic bursts.
Happy coding, and may your ratings stay both accurate and performant!
For background on the OpenClaw Rating API launch, see the original announcement
here.