Arcjet is the runtime security platform that ships with your AI code. Stop bots and automated attacks from burning your AI budget, leaking data, or misusing tools with Arcjet's AI security building blocks.
This is the Arcjet TypeScript and JavaScript SDK core. Most users
should install a framework SDK instead (@arcjet/next, @arcjet/node,
@arcjet/bun, etc.) — see the framework SDKs. Use this
package directly only if you are building a custom adapter for a runtime not
yet supported. Every feature works with any JavaScript application.
import arcjet, { detectBot } from"arcjet";
const aj = arcjet({
// ...rules: [
detectBot({
mode: "LIVE",
allow: [
"CATEGORY:SEARCH_ENGINE", // Google, Bing, etc// "CATEGORY:MONITOR", // Uptime monitoring services// "CATEGORY:PREVIEW", // Link previews e.g. Slack, Discord// "OPENAI_CRAWLER_SEARCH",// See the full list at https://arcjet.com/bot-list
],
}),
],
});
tokenBucket(options)
Token bucket rate limit. Ideal for controlling AI token budgets. Set capacity
to the max tokens a user can spend, refillRate to how many tokens are
restored per interval, and deduct tokens per request via requested in
protect(). The interval accepts strings ("1s", "1m", "1h", "1d")
or seconds as a number.
import arcjet, { tokenBucket } from"arcjet";
const aj = arcjet({
// ...characteristics: ["userId"], // Track per user (or "ip.src" for IP-based)rules: [
tokenBucket({
mode: "LIVE",
refillRate: 2_000, // Tokens added per intervalinterval: "1h", // Refill interval (supports "s", "m", "h", "d" or seconds)capacity: 5_000, // Maximum bucket size
}),
],
});
// Deduct tokens at request time:const decision = await aj.protect(context, {
userId: "user-123",
requested: 500, // Tokens to deduct
});
slidingWindow(options)
Sliding window rate limit. Smoothly limits request rates over a rolling time
window.
import arcjet, { slidingWindow } from"arcjet";
const aj = arcjet({
// ...rules: [
slidingWindow({
mode: "LIVE",
interval: 60, // Window size in secondsmax: 100, // Maximum requests per window
}),
],
});
fixedWindow(options)
Fixed window rate limit. Resets the counter at the start of each window.
import arcjet, { fixedWindow } from"arcjet";
const aj = arcjet({
// ...rules: [
fixedWindow({
mode: "LIVE",
window: "1m", // Window durationmax: 100, // Maximum requests per window
}),
],
});
detectPromptInjection(options)
Detects prompt injection attacks — attempts to override your AI model's
instructions via user input. Pass the user's message via
detectPromptInjectionMessage on each protect() call.
Detects and blocks sensitive information (PII) in request content. Pass the
content to scan via sensitiveInfoValue on each protect() call. Built-in
entity types: CREDIT_CARD_NUMBER, EMAIL, PHONE_NUMBER, IP_ADDRESS.
You can also provide a custom detect callback for additional patterns.
import arcjet, { sensitiveInfo } from"arcjet";
const aj = arcjet({
// ...rules: [
sensitiveInfo({
mode: "LIVE",
deny: [
"CREDIT_CARD_NUMBER",
"EMAIL",
"PHONE_NUMBER",
// See https://docs.arcjet.com/sensitive-info/reference for all types
],
}),
],
});
const decision = await aj.protect(context, {
sensitiveInfoValue: userMessage,
});
The decision object returned by aj.protect() provides information about
why a request was allowed or denied.
const decision = await aj.protect(context, props);
// Top-level verdict
decision.isAllowed(); // true if the request should proceed
decision.isDenied(); // true if the request should be blocked
decision.isErrored(); // true if an error occurred evaluating rules// Reason for the decision
decision.reason.isBot(); // detectBot rule triggered
decision.reason.isRateLimit(); // rate limit rule triggered
decision.reason.isShield(); // shield rule triggered
decision.reason.isSensitiveInfo(); // sensitiveInfo rule triggered
decision.reason.isPromptInjection(); // detectPromptInjection rule triggered
decision.reason.isEmail(); // validateEmail rule triggered// IP intelligence
decision.ip.isHosting(); // Cloud/hosting provider IP
decision.ip.isVpn(); // VPN IP
decision.ip.isProxy(); // Proxy IP
decision.ip.isTor(); // Tor exit node IP
decision.ip.country; // ISO 3166-1 alpha-2 country code
decision.ip.city; // City name
decision.ip.asn; // Autonomous system number// Per-rule results (array, one entry per rule)
decision.results; // ArcjetRuleResult[]
Bot verification details
import { isSpoofedBot } from"@arcjet/inspect";
// Check if any result is from a bot claiming to be a known crawler but failing// IP verification:if (decision.results.some(isSpoofedBot)) {
// Block spoofed bot
}
// Inspect individual bot rule results:for (const result of decision.results) {
if (result.reason.isBot()) {
console.log("Bot type:", result.reason.botType);
console.log("Bot name:", result.reason.botName);
console.log("Verified:", result.reason.verified);
console.log("Spoofed:", result.reason.spoofed);
}
}
IP analysis
Arcjet enriches every request with IP metadata. Use these helpers to make
policy decisions based on network signals:
const decision = await aj.protect(context, {});
if (decision.ip.isHosting()) {
// Requests from cloud/hosting providers are often automated.// https://docs.arcjet.com/blueprints/vpn-proxy-detection
}
if (decision.ip.isVpn() || decision.ip.isProxy() || decision.ip.isTor()) {
// Handle VPN/proxy traffic according to your policy
}
// Access geolocation and network detailsconsole.log(decision.ip.country, decision.ip.city, decision.ip.asn);
Custom adapter example
The following shows the minimal adapter interface required to build a custom
integration. Framework adapters take care of this automatically; this example
illustrates the low-level API.
import http from"node:http";
import { readBody } from"@arcjet/body";
import arcjet, { ArcjetAllowDecision, ArcjetReason, shield } from"arcjet";
const arcjetKey = process.env.ARCJET_KEY;
if (!arcjetKey) {
thrownewError("Cannot find `ARCJET_KEY` environment variable");
}
const aj = arcjet({
// Your adapter takes care of this: this is a naïve example.client: {
asyncdecide() {
returnnewArcjetAllowDecision({
reason: newArcjetReason(),
results: [],
ttl: 0,
});
},
report() {},
},
key: arcjetKey,
log: console,
rules: [shield({ mode: "LIVE" })],
});
const server = http.createServer(asyncfunction (
request: http.IncomingMessage,
response: http.ServerResponse,
) {
const url = newURL(request.url || "", "http://" + request.headers.host);
// Your adapter takes care of this: this is a naïve example.const context = {
getBody() {
returnreadBody(request, { limit: 1024 });
},
host: request.headers.host,
ip: request.socket.remoteAddress,
method: request.method,
path: url.pathname,
};
const decision = await aj.protect(context, {});
if (decision.isDenied()) {
response.writeHead(403, { "Content-Type": "application/json" });
response.end(JSON.stringify({ message: "Forbidden" }));
return;
}
response.writeHead(200, { "Content-Type": "application/json" });
response.end(JSON.stringify({ message: "Hello world" }));
});
server.listen(8000);
Create a single client instance and reuse it with withRule() for
route-specific rules. The SDK caches decisions and configuration, so creating a
new instance per request wastes that work.
// lib/arcjet.ts — create once, import everywhereimport arcjet, { shield } from"@arcjet/node"; // or @arcjet/next, @arcjet/bun, etc.exportdefaultarcjet({
key: process.env.ARCJET_KEY!,
rules: [
shield({ mode: "LIVE" }), // base rules applied to every request
],
});
Arcjet runtime security SDK — bot protection, rate limiting, prompt injection detection, PII blocking, and WAF for JavaScript and TypeScript apps
The npm package arcjet receives a total of 50,185 weekly downloads. As such, arcjet popularity was classified as popular.
We found that arcjet demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago.It has 2 open source maintainers collaborating on the project.
Package last updated on 06 Jul 2026
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.