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

is-responding

v1.3.0

Published

πŸ”¨ A tool to find active endpoint use an enumeration strategy

Readme

is-responding

cli-available node version npm version downloads count size license github-ci typescript

πŸ”¨ A tool to find active endpoints using an enumeration strategy

Give a ⭐️ if this project helped you!

What it does

Plenty of services put a plain counter in the URL: /invoice/1042, /photo/007.jpg, /status/204. Point is-responding at such an address with the counter replaced by {{integer}}, give it a range, and it sends a HEAD request to every address in that range and prints the ones that answered.

is-responding -u "https://example.org/invoice/{{integer}}" -f 1000 -t 1100

Five requests run in parallel by default, silent endpoints are skipped, and the exit code tells a script whether anything was found.

CLI

Installation:

npm install -g is-responding

Or run it without installing:

npx is-responding -u "https://example.org/{{integer}}"
is-responding --help
Usage: is-responding -u <url with {{integer}}> [options]

Options:
  --version          Show version number                               [boolean]
  --url, -u          URL with {{parameter}}                           [required]
  --from, -f         Value the enumeration starts at                [default: 0]
  --to, -t           Value the enumeration ends at                 [default: 10]
  --pad, -p          Pad values with leading zeros, 3 gives 007     [default: 0]
  --concurrency, -c  Requests kept in flight at once                [default: 5]
  --timeout          Milliseconds before a request is abandoned [default: 10000]
  --verbose, -v      Display endpoints which refused
  --help             Show help                                         [boolean]

Examples:
  Scan a range of ids
    is-responding -u "https://example.org/invoice/{{integer}}" -f 1000 -t 1100

  Show why endpoints were skipped
    is-responding -u "https://example.org/{{integer}}" -f 1 -t 50 --verbose

  Fixed-width numbers, so 7 becomes 007
    is-responding -u "https://example.org/photo/{{integer}}.jpg" -t 999 --pad 3

  Scan a wide range faster
    is-responding -u "https://example.org/{{integer}}" -t 5000 --concurrency 25

  Keep the output in range order
    is-responding -u "https://example.org/{{integer}}" -t 100 --concurrency 1

Exit codes:
    0  at least one endpoint responded
    1  nothing responded, or the arguments were invalid
  130  the scan was interrupted with Ctrl+C

Press Ctrl+C to stop early; the report covers whatever was scanned.

Options

| Option | Short | Default | Meaning | | --- | --- | --- | --- | | --url | -u | - | URL template containing at least one {{integer}}. Required. | | --from | -f | 0 | First value of the range, inclusive. May be negative. | | --to | -t | 10 | Last value of the range, inclusive. | | --pad | -p | 0 | Width to pad values to with leading zeros. 0 disables padding. | | --concurrency | -c | 5 | How many requests may be in flight at the same time. | | --timeout | - | 10000 | Milliseconds before a single request is given up on. | | --verbose | -v | off | Also print the endpoints that refused, with the reason. |

Every numeric option must be a whole number, and the run stops with exit code 1 if one is not.

Usage

Placeholders

A placeholder is written as {{type}} - double curly braces around a supported type name.

| Placeholder | Meaning | Supported | | ------------- | --------------------------------------------- | --------- | | {{integer}} | Every whole number from --from up to --to | βœ… Yes |

[!IMPORTANT] integer is currently the only supported type, and the placeholder must be the type name itself. Invented names like {{id}}, {{page}} or {{user}} are rejected - the tool prints "id" is not supported and exits with code 1.

A URL without any placeholder is rejected as well, because there would be nothing to enumerate. So is a template that is not a valid http/https address once the placeholders are filled.

Repeating a placeholder

You can use {{integer}} more than once. Each occurrence is an independent dimension, so the run walks the cartesian product of the ranges - not one shared counter.

is-responding -u "https://example.org/{{integer}}/photo/{{integer}}.jpg" -f 1 -t 3
https://example.org/1/photo/1.jpg
https://example.org/1/photo/2.jpg
https://example.org/1/photo/3.jpg
https://example.org/2/photo/1.jpg
...
https://example.org/3/photo/3.jpg

Two placeholders side by side behave the same way - {{integer}}{{integer}} over 1..4 produces 11, 12, 13, 14, 21, 22, ... 44, so all 16 combinations, not just 11, 22, 33, 44.

[!WARNING] The number of requests is the range size raised to the number of placeholders. Two placeholders over 1..100 means 10 000 requests, three means 1 000 000. Keep the range small when repeating a placeholder.

One placeholder or two?

Every placeholder shares the same --from/--to, so reach for a second one only when both positions really do span that range. A fixed-width number needs --pad, not a second placeholder:

# 31 requests: 01, 02 ... 31
is-responding -u "https://example.org/day-{{integer}}.pdf" -f 1 -t 31 --pad 2

# 961 requests: 0101, 0102 ... 3131, most of them meaningless
is-responding -u "https://example.org/day-{{integer}}{{integer}}.pdf" -f 1 -t 31 --pad 2

When two positions need different ranges, such as a month and a day, keep one of them outside the template and loop:

for month in 01 02 03; do
  is-responding -u "https://example.org/$month{{integer}}2026.pdf" -f 1 -t 31 --pad 2
done

Parallel requests

Five requests are kept in flight at once. Each worker takes the next address as soon as its own finishes, so one slow endpoint holds up a single slot instead of the whole run.

is-responding -u "https://example.org/{{integer}}" -f 1 -t 500 --concurrency 20

Raise it to finish sooner, lower it to go easy on the service. --concurrency 1 sends one request at a time, which keeps the output in range order.

[!NOTE] Results are printed as they arrive, so with parallel requests the order does not follow the range. Use --concurrency 1 when you want the output sorted.

Reading the output

While the scan runs, a progress bar tracks how far it has got. It lives on a single line and is wiped when the run ends, so it never pollutes the results.

  β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘ 4/8 (50%)

Every line that survives is a finding, which keeps the output greppable and safe to redirect.

| Line | Meaning | | ------------------ | ------------------------------------------------------- | | βœ“ 200 <url> | The endpoint answered, with the status it returned | | βœ— <reason> <url> | The endpoint refused or timed out, shown only with -v |

The run closes with a summary: how many endpoints were checked, how long it took, the throughput, the split between responding and silent, and how often each status came back.

Checked 8 endpoints in 1.9s (4.1/s)
Found 6 responding, 2 silent

Status breakdown:
  no response  2
  200          1
  201          1
  202          1

Durations are rendered as 842ms below a second, 2.4s below a minute and 1m 35s above. no response covers the endpoints that never produced a status at all, such as a connection reset or a timeout. Only the ten most frequent statuses are listed; the rest are summed up as ... and N more.

The bar and the summary are written only when the output is a terminal; a redirected run emits the result lines and nothing else.

Stopping early

A long scan does not have to run to the end. Press Ctrl+C and the run stops accepting new endpoints, then prints the same report it would have printed on its own, covering everything checked up to that point.

Interrupted after 23 of 81 endpoints
Checked 23 endpoints in 2.9s (8.1/s)
Found 23 responding, 0 silent

Status breakdown:
  200          23

The exit code is 130, the shell convention for a run ended by Ctrl+C, so a script can tell a stopped scan from an empty one. The report appears straight away: requests already in flight get a moment to finish, and anything still hanging is abandoned rather than holding the summary back. Pressing Ctrl+C again kills the process outright.

Leading zeros

Some services expect a fixed-width number, like /photo/007.jpg. Use --pad (-p) to set that width:

is-responding -u "https://example.org/photo/{{integer}}.jpg" -f 7 -t 9 --pad 3
https://example.org/photo/007.jpg
https://example.org/photo/008.jpg
https://example.org/photo/009.jpg

Values already wider than the padding are left alone (--pad 2 keeps 1000 as 1000), and a negative value keeps its sign in front (--pad 3 turns -7 into -007).

Range

--from and --to are inclusive and may be negative. --from must not be greater than --to.

is-responding -u "https://example.org/{{integer}}" -f -3 -t 0

Exit codes

Useful when calling the tool from a script or a CI job.

| Code | Meaning | | ----- | ------------------------------------------------ | | 0 | At least one endpoint responded | | 1 | Nothing responded, or the arguments were invalid | | 130 | The scan was interrupted with Ctrl+C |

if is-responding -u "https://example.org/{{integer}}" -f 1 -t 50; then
  echo "found something"
fi

Examples

➑️ Use case: Find the live endpoints in a range

is-responding -u "https://httpbin.org/status/{{integer}}" -f 198 -t 205
Scanning 8 endpoints with 5 parallel requests
βœ“ 200  https://httpbin.org/status/200
βœ“ 201  https://httpbin.org/status/201
βœ“ 202  https://httpbin.org/status/202
βœ“ 203  https://httpbin.org/status/203
βœ“ 204  https://httpbin.org/status/204
βœ“ 205  https://httpbin.org/status/205

Checked 8 endpoints in 1.9s (4.1/s)
Found 6 responding, 2 silent

Status breakdown:
  no response  2
  200          1
  201          1
  202          1
  203          1
  204          1
  205          1

➑️ Use case: See why endpoints were skipped

Without --verbose a silent endpoint leaves no trace. Add -v to print the misses too, with the reason each one gave.

is-responding -u "https://httpbin.org/status/{{integer}}" -f 198 -t 201 -v
Scanning 4 endpoints with 5 parallel requests
βœ— socket hang up  https://httpbin.org/status/199
βœ— socket hang up  https://httpbin.org/status/198
βœ“ 200  https://httpbin.org/status/200
βœ“ 201  https://httpbin.org/status/201

Checked 4 endpoints in 748ms (5.3/s)
Found 2 responding, 2 silent

Status breakdown:
  no response  2
  200          1
  201          1

➑️ Use case: Scan a wide range quickly

is-responding -u "https://example.org/{{integer}}" -f 1 -t 5000 --concurrency 25

➑️ Use case: Give up on slow endpoints faster

is-responding -u "https://example.org/{{integer}}" --timeout 2000

API

The package can be used programmatically as well.

const { start } = require('is-responding');

const result = await start({
  url: 'https://example.org/{{integer}}',
  from: 1,
  to: 20,
  verbose: false,
  timeout: 10000,
  pad: 0,
  concurrency: 5,
});

console.log(result.responding); // ['https://example.org/7', ...]
console.log(result.checked); // 20
console.log(result.silent); // 19
console.log(result.elapsed); // 2417 (milliseconds)
console.log(result.statuses); // { '200': 1, 'no response': 19 }
console.log(result.interrupted); // false

start() resolves once every endpoint has been checked. It returns { responding, checked, silent, elapsed, statuses, interrupted }, or null when the URL template could not be enumerated.

Pass an AbortSignal to stop a scan from your own code. The returned report covers whatever was checked before the abort, exactly as it does for Ctrl+C:

const controller = new AbortController();
setTimeout(() => controller.abort(), 5000);

const result = await start({
  url: 'https://example.org/{{integer}}',
  from: 1,
  to: 100000,
  verbose: false,
  signal: controller.signal,
});

console.log(result.interrupted); // true

Related

License

The MIT License @ 2026