Automated summary
Implements rate limiting, exponential backoff, and request queuing for the Lokalise API.
Strengths
- Specifies the exact 6 requests-per-second limit and 170 ms minimum spacing
- Provides ready-to-use TypeScript examples with p-queue and @lokalise/node-api
- Explains how to read X-RateLimit and Retry-After headers
- Includes throttled pagination for bulk operations
Limitations
- Focused on Node.js/TypeScript and gives no examples in other languages
- Assumes use of p-queue and the official SDK
- The pagination code snippet is truncated in the SKILL.md
Use when integrating the Lokalise API and needing to handle 429 errors, retries, or request throughput.
Avoid if working with another API or looking for a generic rate-limiting solution independent of Lokalise.
Security analysis
SafeThe skill is pure documentation and TypeScript example code for implementing rate limiting, backoff, and request queuing against the Lokalise API. It declares only Read/Write/Edit tools and contains no shell execution, no network calls that exfiltrate data, no obfuscated payloads, and no instructions to disable safety. API tokens are read from environment variables, which is the correct pattern rather than hardcoding secrets.
No concerns found
How this analysis is madeExamples
Add a request queue to my Lokalise API calls so we stay under 6 requests per second, and wrap 429 responses with exponential backoff.My Lokalise translation export sometimes fails with 429 Too Many Requests. Implement retry logic that respects the Retry-After header and adds jitter.Write a TypeScript helper that paginates through all Lokalise project keys with throttled requests and exponential backoff on failures.name: lokalise-rate-limits description: 'Implement Lokalise rate limiting, backoff, and request queuing patterns.
Use when handling rate limit errors, implementing retry logic,
or optimizing API request throughput for Lokalise.
Trigger with phrases like "lokalise rate limit", "lokalise throttling",
"lokalise 429", "lokalise retry", "lokalise backoff".
' allowed-tools: Read, Write, Edit version: 1.14.0 license: MIT author: Jeremy Longshore jeremy@intentsolutions.io tags:
- saas
- lokalise
- api compatibility: Designed for Claude Code, also compatible with Codex and OpenClaw
Lokalise Rate Limits
Overview
Lokalise enforces a strict 6 requests per second rate limit across all API endpoints (https://api.lokalise.com/api2). Exceeding this triggers a 429 Too Many Requests response. This skill covers request queuing with 170ms minimum spacing, exponential backoff for 429 recovery, bulk operation throttling, and proactive quota monitoring via response headers.
Prerequisites
@lokalise/node-apiSDK installed (npm install @lokalise/node-api)- API token configured (read or read/write scope depending on operations)
- Node.js 18+ for native
AbortControllersupport in timeout handling
Instructions
1. Understand the Rate Limit Headers
Every Lokalise API response includes rate limit headers:
X-RateLimit-Limit: 6 # Max requests per second
X-RateLimit-Remaining: 4 # Requests remaining in current window
X-RateLimit-Reset: 1700000000 # Unix timestamp when the window resets
Retry-After: 1 # Seconds to wait (only on 429 responses)
Always read these headers. Never hardcode assumptions about the window — Lokalise may adjust limits per plan tier.
2. Implement a Request Queue with 170ms Spacing
Space requests at minimum 170ms apart (1000ms / 6 = ~167ms, rounded up). Use p-queue for concurrency control:
import PQueue from "p-queue";
const lokaliseQueue = new PQueue({
concurrency: 1,
interval: 170,
intervalCap: 1,
});
async function queuedRequest<T>(fn: () => Promise<T>): Promise<T> {
return lokaliseQueue.add(fn, { throwOnTimeout: true });
}
// Usage with the SDK
import { LokaliseApi } from "@lokalise/node-api";
const lokalise = new LokaliseApi({ apiKey: process.env.LOKALISE_API_TOKEN });
const keys = await queuedRequest(() =>
lokalise.keys().list({
project_id: "123456789.abcdefgh",
limit: 500,
page: 1,
})
);
3. Add Exponential Backoff for 429 Recovery
When a 429 occurs, honor the Retry-After header first. If absent, use exponential backoff with jitter:
async function withBackoff<T>(
fn: () => Promise<T>,
maxRetries = 5
): Promise<T> {
for (let attempt = 0; attempt <= maxRetries; attempt++) {
try {
return await fn();
} catch (error: any) {
if (error.code === 429 && attempt < maxRetries) {
const retryAfter = error.headers?.["retry-after"];
const baseDelay = retryAfter
? parseInt(retryAfter, 10) * 1000
: Math.pow(2, attempt) * 1000;
const jitter = Math.random() * 500;
const delay = baseDelay + jitter;
console.warn(
`Rate limited. Attempt ${attempt + 1}/${maxRetries}. ` +
`Waiting ${Math.round(delay)}ms...`
);
await new Promise((resolve) => setTimeout(resolve, delay));
continue;
}
throw error;
}
}
throw new Error("Max retries exceeded for Lokalise API request");
}
4. Throttle Bulk Operations
For operations that process many items (listing all keys, bulk translations), paginate with built-in throttling:
async function paginateAll<T>(
fetchPage: (page: number) => Promise<{ items: T[]; totalPages: number }>
): Promise<T[]> {
const allItems: T[] = [];
let page = 1;
let totalPages = 1;
do {
const result = await queuedRequest(() => fetchPage(page));
allItems.push(...result.items);
totalPages = result.totalPages;
page++;
} while (page <= totalPages);
return allItems;
}
// Fetch all keys across pages
const allKeys = await paginateAll(async (page) => {
const response = await lokalise.keys().list({
project_id: projectId,
limit: 500, // max per page
page,
});
return {
items: response.items,
totalPages: response.totalCount
? Math.ceil(response.totalCount / 500)
: 1,
};
});
For bulk key creation, batch into groups of 500 (API limit per request) and queue each batch:
async function bulkCreateKeys(
projectId: string,
keys: Array<{ key_name: string; platforms: string[] }>
): Promise<void> {
const batchSize = 500;
for (let i = 0; i < keys.length; i += batchSize) {
const batch = keys.slice(i, i + batchSize);
await queuedRequest(() =>
lokalise.keys().create({
project_id: projectId,
keys: batch,
})
);
console.log(
`Created keys ${i + 1}-${Math.min(i + batchSize, keys.length)} ` +
`of ${keys.length}`
);
}
}
5. Monitor Quota Proactively
Track remaining quota and preemptively slow down before hitting the limit:
let remainingRequests = 6;
let resetTimestamp = 0;
function updateQuota(headers: Record<string, string>): void {
remainingRequests = parseInt(headers["x-ratelimit-remaining"] ?? "6", 10);
resetTimestamp = parseInt(headers["x-ratelimit-reset"] ?? "0", 10);
}
async function throttleIfNeeded(): Promise<void> {
if (remainingRequests <= 1) {
const now = Math.floor(Date.now() / 1000);
const waitSeconds = Math.max(0, resetTimestamp - now) + 0.5;
console.warn(
`Quota nearly exhausted (${remainingRequests} remaining). ` +
`Pausing ${waitSeconds}s until reset.`
);
await new Promise((resolve) =>
setTimeout(resolve, waitSeconds * 1000)
);
}
}
Output
- Request queue enforcing 6 req/sec with 170ms minimum spacing between calls
- Automatic retry with exponential backoff + jitter on 429 responses
- Paginated fetching with throttling for bulk data retrieval
- Proactive throttling when
X-RateLimit-Remainingdrops to 1
Error Handling
| Header | Description | Action |
|--------|-------------|--------|
| X-RateLimit-Limit | Max requests per window (always 6) | Use as concurrency ceiling |
| X-RateLimit-Remaining | Requests left in current window | Pause proactively when <= 1 |
| X-RateLimit-Reset | Unix timestamp of window reset | Sleep until this time on exhaustion |
| Retry-After | Seconds to wait (only on 429) | Always honor this value exactly |
If you receive a 429 without Retry-After, default to 1 second then exponential backoff. Never retry more than 5 times — if consistently rate-limited, your architecture needs request consolidation, not more retries.
Examples
Complete Rate-Limited Client
import { LokaliseApi } from "@lokalise/node-api";
import PQueue from "p-queue";
class RateLimitedLokalise {
private api: LokaliseApi;
private queue: PQueue;
constructor(apiKey: string) {
this.api = new LokaliseApi({ apiKey });
this.queue = new PQueue({ concurrency: 1, interval: 170, intervalCap: 1 });
}
async request<T>(fn: (api: LokaliseApi) => Promise<T>): Promise<T> {
return this.queue.add(
() => withBackoff(() => fn(this.api)),
{ throwOnTimeout: true }
);
}
}
// Usage
const client = new RateLimitedLokalise(process.env.LOKALISE_API_TOKEN!);
const keys = await client.request((api) =>
api.keys().list({ project_id: "123456789.abcdefgh", limit: 500 })
);
CLI with Rate Limiting
# The lokalise2 CLI respects rate limits internally, but for scripted
# loops you need manual spacing:
for project_id in $(lokalise2 project list --token $TOKEN --format json \
| jq -r '.[].project_id'); do
lokalise2 file download \
--token "$LOKALISE_API_TOKEN" \
--project-id "$project_id" \
--format json \
--dest ./locales/"$project_id"/
sleep 0.2 # 200ms spacing
done
Resources
- Lokalise API Rate Limits
- p-queue — Promise-based queue with concurrency control
- @lokalise/node-api SDK
Next Steps
For handling specific API errors beyond rate limits, see lokalise-common-errors.
From the file to a first result
The download contains exactly the content displayed on this page. This copy may differ from the latest version in the source repository.
View the source and supporting filesThis download contains SKILL.md only. Any scripts, references, templates and dependencies are not included. Get the required files from the source, preserving their directory structure, before continuing.
1. Download the file
Download SKILL.mdFrom the root of a test project, save the file as .skill-downloads/lokalise-rate-limits-mrzxuqzx/SKILL.md, or use the command below. This folder is for inspecting the skill before installation.
Command for macOS/Linux or WSL: requires a POSIX shell and curl. On Windows without WSL, use the download button and create the folder manually.
mkdir -p '.skill-downloads/lokalise-rate-limits-mrzxuqzx' && curl --fail --show-error --location 'https://skills-guides.com/api/skills/lokalise-rate-limits-mrzxuqzx/download' --output '.skill-downloads/lokalise-rate-limits-mrzxuqzx/SKILL.md.part' && mv '.skill-downloads/lokalise-rate-limits-mrzxuqzx/SKILL.md.part' '.skill-downloads/lokalise-rate-limits-mrzxuqzx/SKILL.md'2. Check prerequisites
Read SKILL.md before using it. If it references scripts or external services, inspect them and prepare the required access in your test environment.
Environment declared by the author: Designed for Claude Code, also compatible with Codex and OpenClaw
Tools declared by the author (check availability in your agent): Read, Write, Edit
Original excerpt: Prerequisites
@lokalise/node-apiSDK installed (npm install @lokalise/node-api)- API token configured (read or read/write scope depending on operations)
- Node.js 18+ for native
AbortControllersupport in timeout handling
The platforms on this page are catalog indications. The paths below follow tool documentation; they do not prove this skill has been run in those tools. No minimum tool version is confirmed for this listing.
3. Load the skill
After inspection, copy the complete folder into your project using one of the commands below, then open a new tool session. The command stops if a folder with the same name already exists: compare the files before replacing it.
Claude Code
test -f '.skill-downloads/lokalise-rate-limits-mrzxuqzx/SKILL.md' && test -s '.skill-downloads/lokalise-rate-limits-mrzxuqzx/SKILL.md' && mkdir -p '.claude/skills' && test ! -e '.claude/skills/lokalise-rate-limits' && cp -R '.skill-downloads/lokalise-rate-limits-mrzxuqzx' '.claude/skills/lokalise-rate-limits'Codex
test -f '.skill-downloads/lokalise-rate-limits-mrzxuqzx/SKILL.md' && test -s '.skill-downloads/lokalise-rate-limits-mrzxuqzx/SKILL.md' && mkdir -p '.agents/skills' && test ! -e '.agents/skills/lokalise-rate-limits' && cp -R '.skill-downloads/lokalise-rate-limits-mrzxuqzx' '.agents/skills/lokalise-rate-limits'OpenSkills
OpenSkills must already be installed. The local install/read procedure is checked with OpenSkills 1.5.0, which requires Node.js ≥ 20.6.0. Catalog slugs are not resolved automatically.
Official OpenSkills installationopenskills install './.skill-downloads/lokalise-rate-limits-mrzxuqzx'openskills read 'lokalise-rate-limits-mrzxuqzx'Reading should display the installed file content and its base directory. It does not run the skill or install its dependencies.
For an agent that reads AGENTS.md, then sync the index. This command changes AGENTS.md: review the diff before using it.
openskills syncManual method or another tool: attach SKILL.md to a conversation, or open it in an agent that can read files. Include any required supporting resources. No universal folder is recognized by every tool.
4. Try a first task
Use a short, synthetic input: an API endpoint, a small document or an interface brief. In a new conversation, attach the file or give the agent its path, then adapt this request:
Read .skill-downloads/lokalise-rate-limits-mrzxuqzx/SKILL.md and apply its instructions to this example: [describe a test input]. Identify any missing files, dependencies or access. Produce the result requested by the skill without inventing data or running unreviewed scripts.Expected result: output matching the skill instructions, or a precise list of missing prerequisites. A read confirmation alone does not validate a first use. If an external resource is unavailable, that path remains untested.
React Hook Form Best Practices
Development
Master React Hook Form: avoid anti-patterns, manage subscriptions, and handle reset, dirty state, and controlled inputs correctly.
Emotion to Mantine Migration
Development
Migrate Emotion styled-components to Mantine components with style props and CSS modules. Use when converting .styled.tsx files or removing @emotion imports.
Scope Creep Detector
Development
Analyzes git diffs against a stated intent to detect scope creep, unrelated files, broad PRs, and oversized changes, then suggests keep, split, or justify actions.