Help us improve
Share bugs, ideas, or general feedback.
From framer-pack
Implements Framer API rate limiting with batching for CMS, debouncing plugins, backoff retries for Server API/WebSocket. Use for 429 errors, retries, throughput optimization.
npx claudepluginhub jeremylongshore/claude-code-plugins-plus-skills --plugin framer-packHow this skill is triggered — by the user, by Claude, or both
Slash command
/framer-pack:framer-rate-limitsThis skill is limited to the following tools:
The summary Claude sees in its skill listing — used to decide when to auto-load this skill
Handle Framer API rate limits for Server API and plugin operations. The Server API uses WebSocket, so rate limits apply per-connection. CMS operations are limited by collection size and concurrent writes.
Optimizes Framer API and plugin performance via batch CMS syncs, React memoization, persistent WebSocket connections, and image optimization. Use for slow responses, CMS timeouts, or render lag.
Manages Webflow Data API v2 rate limits using SDK retries, exponential backoff with jitter, request queuing, and bulk endpoints to maximize throughput and avoid 429 errors.
Expert guidance for Framer design, Framer Motion animations, interactive prototyping, production site building, and CMS/MCP integration. Activates automatically when working on Framer sites or animations.
Share bugs, ideas, or general feedback.
Handle Framer API rate limits for Server API and plugin operations. The Server API uses WebSocket, so rate limits apply per-connection. CMS operations are limited by collection size and concurrent writes.
| Operation | Limit | Notes |
|---|---|---|
| Server API connections | 1 per site | WebSocket, persistent |
| CMS setItems | ~100 items/call | Batch larger sets |
| CMS getItems | No hard limit | Returns all items |
| Plugin API calls | Debounced | Framer throttles internally |
| Publish | ~1/minute | Site publishing |
| Image upload | Concurrent limit | Via CMS image fields |
async function batchSetItems(collection: any, items: any[], batchSize = 100) {
for (let i = 0; i < items.length; i += batchSize) {
const batch = items.slice(i, i + batchSize);
await collection.setItems(batch);
console.log(`Synced ${Math.min(i + batchSize, items.length)}/${items.length}`);
if (i + batchSize < items.length) {
await new Promise(r => setTimeout(r, 1000)); // 1s between batches
}
}
}
// Debounce rapid plugin UI interactions
function debounce<T extends (...args: any[]) => any>(fn: T, ms = 300) {
let timer: NodeJS.Timeout;
return (...args: Parameters<T>) => {
clearTimeout(timer);
timer = setTimeout(() => fn(...args), ms);
};
}
const debouncedSync = debounce(async () => {
await syncCollection();
}, 500);
async function withRetry<T>(fn: () => Promise<T>, maxRetries = 3): Promise<T> {
for (let i = 0; i <= maxRetries; i++) {
try {
return await fn();
} catch (err: any) {
if (i === maxRetries) throw err;
const delay = 1000 * Math.pow(2, i);
console.log(`Retry ${i + 1} in ${delay}ms`);
await new Promise(r => setTimeout(r, delay));
}
}
throw new Error('Unreachable');
}
| Error | Cause | Solution |
|---|---|---|
| WebSocket disconnected | Connection timeout | Reconnect with backoff |
| setItems slow | Large batch | Split into chunks of 100 |
| Publish rate limited | Too frequent | Wait 60s between publishes |
For security, see framer-security-basics.