Connect your app
Your app runs the Limitr engine itself, through the SDK. Connected to Cloud, the engine gets your published policy and your customers' state, keeps them current, and reports usage back. Every decision still happens in your process: the connection is never on the path of a call.
Connecting an app starts on Pay as you go.
The easiest way is your coding agent. With the Limitr skills (in Claude Code:
/plugin marketplace add dev-formata-io/limitr, then /plugin install limitr@limitr; for other agents, see
Made for AI coding agents), ask it to do the steps below in your app,
Ex. "connect this app to Limitr Cloud with the LIMITR_KEY secret and gate the chat endpoint on the chat
entitlement". The same goes for your UI: "show each customer's remaining chat tokens on the account page".
1. Make a key
In Developers, choose New key:
- Name: where it's used, Ex. "Production server".
- Mode: a Test key reads the test policy and test customers; a Live key, the live ones.
- Expires: never, or in 30 days, 90 days, or a year.
- Usage only: for an SDK where end users could tamper with the key, Ex. in a browser. A usage-only key can meter usage but can't create customers or change them (their plan, limits, gives and takes, caps, or metadata).
The key is shown once: copy it and store it as a secret on your server. Deleting a key stops new connections with it; an app already connected stays connected until it reconnects. Making and deleting keys needs the Manage API keys permission.
2. Connect
npm install @formata/limitr
import { Limitr } from '@formata/limitr';
const limitr = await Limitr.cloud({ token: process.env.LIMITR_KEY! });
if (!limitr) throw new Error('Limitr Cloud refused the key');
await limitr.ensureCustomer('user_123', 'pro');
if (await limitr.allow('user_123', 'chat', 1200)) {
// allowed, and metered
}
Limitr.cloud() returns undefined when Cloud refuses the key (Ex. a wrong or deleted key, or a workspace on
Free). It throws if it can't connect within connectTimeout, or the policy doesn't validate. After that, every
function works as it does with a local policy: allow, check, reserve and settle, remaining, and the rest. See the
TypeScript SDK reference.
What syncs
- The policy. The app loads your published policy when it connects, and gets each new version when you publish, with no deploy or restart.
- Customers. The first time the app meets a customer, it gets their state from Cloud.
ensureCustomer()makes a new one, and does nothing if they already exist. Changes made in the app (a plan change, an override, a top-up) reach your running engines. - Usage. Each call's usage, cost, and metadata go to Cloud for ledgers, invoices, dashboards, and alerts. The SDK sends them in small batches.
Several servers running the same app share the same customers through Cloud, so a customer's meters stay right whichever server handles the call.
When the connection drops
The SDK reconnects on its own, catches up on the policy and the customers it holds, and sends any usage it kept.
While it's disconnected, denyUnconnected decides what happens to calls:
denyUnconnected | |
|---|---|
true (default) | Every call is denied while disconnected, even for customers this server holds, so you never over-serve. |
false | Calls are decided on the state this server already has, and their usage is sent when the connection is back. A customer this server doesn't hold can't be loaded until then. |
Shutting down
Call close() when your app shuts down, so the last batch of usage is sent first:
process.on('SIGTERM', async () => {
await limitr.close();
process.exit(0);
});
Options
const limitr = await Limitr.cloud({
token: process.env.LIMITR_KEY!, // required: the API key
policy: 'active', // a version ID to pin to one version; 'active' (default) follows publishes
connectTimeout: 5000, // ms to wait for the first connection
denyUnconnected: true, // see above
validate: true, // check the policy when it loads
batchMs: 250, // ms to collect usage before sending it (0 sends each call right away)
maxExecutionTime: 5000, // ms a policy function may run (null for no limit)
httpHosts: true, // hosts policy capabilities may call (true: any, a list, or false: none)
});
wsAddress and ticketAddress point the SDK at another Limitr Cloud server; most apps never set them.
In a browser
Keep keys on your server when you can. For an SDK in a browser or another place users can reach, use a usage-only key: it can meter, but changes to customers stay on your server's side.