npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

node-ip-rate-limiter

v1.2.0

Published

Adaptive IP rate limiter with hierarchical pattern tracking (p2/p3 patterns) for in-memory rate limiting

Readme

node-ip-rate-limiter

An adaptive IP rate limiter with hierarchical pattern tracking (p2/p3 patterns) for in-memory rate limiting. This package automatically detects patterns in IP addresses and applies rate limiting at different levels (single IP, /24 subnet, /16 network).

Features

  • Adaptive Rate Limiting: Automatically detects and groups IPs by patterns
  • Hierarchical Pattern Tracking:
    • Single IP: Individual IP address tracking
    • P3 Pattern (/24 subnet): Groups IPs sharing the first 3 octets (e.g., 72.145.152.*)
    • P2 Pattern (/16 network): Groups IPs sharing the first 2 octets (e.g., 72.145.*.*)
  • Real Request Counting: Every request is counted per IP, per /24 and per /16; blocking always uses these request counts
  • Automatic Grouping: The /24 and /16 quotas switch on when several IPs or subnets from the same range are active
  • In-Memory Storage: Fast, efficient in-memory storage with automatic expiration
  • Zero Dependencies: No external dependencies required

Installation

npm install node-ip-rate-limiter

Quick Start

const { createRateLimiter } = require('node-ip-rate-limiter');

const limiter = createRateLimiter({
  moduleName: 'my-api',
  single: {
    maxCount: 10,        // Max requests per IP
    expiryTime: 60000    // 60 seconds in milliseconds
  },
  p3Series: {
    maxCount: 50,        // Max requests per /24 subnet
    expiryTime: 60000    // 60 seconds
  },
  p2Series: {
    maxCount: 100,       // Max requests per /16 network
    expiryTime: 60000    // 60 seconds
  }
});

// Check an IP address
const result = limiter.check('72.145.152.42');

if (result.isDuplicate) {
  console.log('Rate limit exceeded!');
  console.log(result.reason);
} else {
  console.log('Request allowed');
  console.log(`Current level: ${result.level}`);
  console.log(`Count: ${result.count}`);
}

Multi-module Example (same Node process)

const { createRateLimiter, ipRateLimiting } = require('node-ip-rate-limiter');

const authLimiter = createRateLimiter({
  moduleName: 'auth',
  single: { maxCount: 5, expiryTime: 60000 },
  p3Series: { maxCount: 20, expiryTime: 60000 },
  p2Series: { maxCount: 50, expiryTime: 60000 }
});

const apiLimiter = createRateLimiter({
  moduleName: 'api',
  single: { maxCount: 10, expiryTime: 60000 },
  p3Series: { maxCount: 30, expiryTime: 60000 },
  p2Series: { maxCount: 80, expiryTime: 60000 }
});

// Option 1: use the per-module instance
authLimiter.check('192.168.1.10');

// Option 2: use the registry via moduleName
ipRateLimiting('192.168.1.10', 'api');

How It Works

Pattern Detection

The rate limiter tracks IP addresses at three levels:

  1. Single IP (72.145.152.42): Individual IP tracking
  2. P3 Pattern (72.145.152.*): First 3 octets - /24 subnet
  3. P2 Pattern (72.145.*.*): First 2 octets - /16 network

Request Counting

Every request increments three request counters, each with its own expiry window:

  • the IP counter (single.expiryTime)
  • the /24 counter (p3Series.expiryTime)
  • the /16 counter (p2Series.expiryTime)

Which Limits Apply

  • Per-IP limit (single.maxCount): always applies.
  • /24 limit (p3Series.maxCount): applies while 2+ distinct IPs from that /24 are active.
  • /16 limit (p2Series.maxCount): applies while 2+ distinct /24 subnets from that /16 are active.

A request is blocked when any applicable counter is over its limit. level is the broadest active tier (or the tier that blocked), and count is that tier's real request count.

Example (single = 5, p3 = 10, p2 = 15):

72.145.152.42  → level single, count 1   (IP counter)
72.145.152.43  → level p3,     count 2   (/24 counter: 2 requests)
72.145.83.96   → level p2,     count 3   (/16 counter: 3 requests)
...16th request anywhere in 72.145.*.* → blocked at p2, count 16

A range stops being grouped once its members have been inactive for the expiry window.

Changelog

1.2.0

  • Fixed: the /16 tier blocked on the number of distinct /24 subnets instead of the number of requests, so a distributed flood inside a few subnets was never blocked.
  • Fixed: the first IP seen in a subnet stayed at the per-IP tier and its counter was deleted whenever a neighbour was evaluated, so it never reached its limit.
  • Fixed: the /16 pattern count could expire independently and read 0.
  • The per-IP limit now also applies inside grouped subnets and networks.
  • count is now always a real request count.
  • Removed the full-store scans on every grouped request (about 0.75 ms per check under load in 1.1.0).

API Reference

createRateLimiter(config)

Creates and returns an isolated limiter instance for a single moduleName (safe to use multiple modules in one process).

Returns:

  • moduleName (string)
  • check(ip) (function) -> { isDuplicate, level, reason, count }

Example:

const { createRateLimiter } = require('node-ip-rate-limiter');

const limiter = createRateLimiter({
  moduleName: 'api-server',
  single: { maxCount: 100, expiryTime: 60000 },
  p3Series: { maxCount: 500, expiryTime: 60000 },
  p2Series: { maxCount: 1000, expiryTime: 60000 }
});

const result = limiter.check('72.145.152.42');

initRateLimiter(config) (Deprecated)

Initializes the single global default limiter.

Deprecated: unsafe for multi-module usage (each call replaces the global default). Prefer createRateLimiter().

Parameters:

  • config (Object): Configuration object
    • moduleName (string): Unique name for this rate limiter instance
    • single (Object): Configuration for single IP rate limiting
      • maxCount (number): Maximum number of requests allowed
      • expiryTime (number): Time in milliseconds before the limit resets
    • p3Series (Object): Configuration for /24 subnet rate limiting
      • maxCount (number): Maximum number of requests allowed per subnet
      • expiryTime (number): Time in milliseconds before the limit resets
    • p2Series (Object): Configuration for /16 network rate limiting
      • maxCount (number): Maximum number of requests allowed per network
      • expiryTime (number): Time in milliseconds before the limit resets

Example:

initRateLimiter({
  moduleName: 'api-server',
  single: { maxCount: 100, expiryTime: 60000 },
  p3Series: { maxCount: 500, expiryTime: 60000 },
  p2Series: { maxCount: 1000, expiryTime: 60000 }
});

ipRateLimiting(ip, moduleName?)

Checks if an IP address should be rate limited.

Parameters:

  • ip (string): Client IP address (IPv4 or IPv6)
  • moduleName (string, optional): Which module's configuration to use (as registered by createRateLimiter() / initRateLimiter())

Returns:

  • Object: Rate limiting result
    • isDuplicate (boolean): true if rate limit exceeded, false otherwise
    • level (string): Current rate limiting level ("single", "p3", or "p2")
    • reason (string): Human-readable explanation of the result
    • count (number): Number of requests counted at level in the current window

Example:

const result = ipRateLimiting('192.168.1.100', 'api-server');
// {
//   isDuplicate: false,
//   level: 'single',
//   reason: 'Request allowed under the per-IP rate limit...',
//   count: 1
// }

Usage Examples

Express.js Middleware

const express = require('express');
const { createRateLimiter } = require('node-ip-rate-limiter');

const app = express();

// Initialize isolated rate limiter
const limiter = createRateLimiter({
  moduleName: 'express-api',
  single: { maxCount: 100, expiryTime: 60000 },
  p3Series: { maxCount: 500, expiryTime: 60000 },
  p2Series: { maxCount: 1000, expiryTime: 60000 }
});

// Rate limiting middleware
function rateLimitMiddleware(req, res, next) {
  const clientIP = req.ip || req.connection.remoteAddress;
  const result = limiter.check(clientIP);
  
  if (result.isDuplicate) {
    return res.status(429).json({
      error: 'Rate limit exceeded',
      reason: result.reason,
      retryAfter: 60
    });
  }
  
  // Add rate limit headers
  res.setHeader('X-RateLimit-Level', result.level);
  res.setHeader('X-RateLimit-Count', result.count);
  
  next();
}

app.use(rateLimitMiddleware);

app.get('/api/data', (req, res) => {
  res.json({ message: 'Success' });
});

app.listen(3000);

Batch Processing

const { createRateLimiter } = require('node-ip-rate-limiter');
const fs = require('fs');

// Initialize
const limiter = createRateLimiter({
  moduleName: 'batch-processor',
  single: { maxCount: 10, expiryTime: 60000 },
  p3Series: { maxCount: 50, expiryTime: 60000 },
  p2Series: { maxCount: 100, expiryTime: 60000 }
});

// Process IPs from file
const ips = JSON.parse(fs.readFileSync('ip_addresses.json', 'utf8'));
const results = [];

for (const ip of ips) {
  const result = limiter.check(ip);
  results.push({ ip, ...result });
  
  if (result.isDuplicate) {
    console.log(`Blocked: ${ip} - ${result.reason}`);
  }
}

console.log(`Processed ${results.length} IPs`);

Response Examples

Single IP (First Request)

{
  isDuplicate: false,
  level: 'single',
  reason: 'Request allowed under the per-IP rate limit. The client is currently treated as a single IP.',
  count: 1
}

P3 Pattern Detected

{
  isDuplicate: false,
  level: 'p3',
  reason: 'Request allowed under the /24 subnet rate limit. Multiple IPs were detected in the same subnet and are sharing a common quota.',
  count: 2
}

P2 Pattern Detected

{
  isDuplicate: false,
  level: 'p2',
  reason: 'Request allowed under the /16 network rate limit. Traffic from a wider network is being grouped and rate-limited together.',
  count: 3
}

Rate Limit Exceeded

{
  isDuplicate: true,
  level: 'p3',
  reason: 'Request blocked because the /24 subnet rate limit has been exceeded. Multiple IPs from the same subnet are sharing this quota.',
  count: 6
}

Important Notes

  • In-Memory Only: This package uses in-memory storage. Data is lost on process restart.
  • Single Process: Designed for single-process applications. For multi-process setups, consider using Redis or a shared storage solution.
  • Automatic Cleanup: Expired entries are automatically cleaned up every 10 minutes.
  • IPv4 + IPv6: Supports both IPv4 and IPv6. IPv6 is rate-limited by the first /64 prefix (no /48-/32 promotion yet).
  • Multi-module (in one process): Supported via createRateLimiter() / ipRateLimiting(ip, moduleName). initRateLimiter() swaps a single global default and is not safe for multi-module usage.

License

ISC

Author

Mirabel Technologies

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

Support

For issues, questions, or contributions, please visit the npm package page.