client.get() or client.post() already returns a Promise, so there’s no separate “async” method to learn. The SDK queues every request from a client instance internally and only runs up to concurrency of them at the same time.
Basic usage
Set a concurrency limit
Pass
concurrency when creating the client to cap how many requests run at the same time:Set
concurrency to match your ZenRows plan’s concurrent request limit. Each client instance enforces its own limit. Two scripts (or two client instances) don’t share it, so running both at once can still trigger 429 Too Many Requests errors. See Concurrency for how plan limits work.Scrape a list of URLs in parallel
Map your URLs to
client.get() calls and use Promise.allSettled() to wait for all of them, even if some fail:Promise.allSettled() waits for every call to finish, even if some of them fail. Unlike Promise.all(), it doesn’t reject as soon as one promise fails, so the rest of the batch still completes.When to think about concurrency
You don’t need to do anything special to run requests concurrently, calling.get()/.post() in a .map() already benefits from the internal queue. Set concurrency explicitly when you want to match a specific plan limit, or lower it if you’re seeing 429 errors.
POST in parallel
The same pattern works withclient.post():
How it works under the hood
The SDK uses fastq internally to queue every
get() and post() call from the same client instance and run at most concurrency of them at once (default 5). This applies uniformly, there’s no separate queue for GET versus POST. Retry behavior configured via retries applies the same way regardless of how many requests run in parallel. See Error Handling and Retries for details.Troubleshooting
429 Too Many Requestseven thoughconcurrencyis set correctly: Another script or process is using the same API key at the same time. Concurrency limits are per plan, not per client instance, so simultaneous scripts share the same real ceiling even though eachZenRowsclient only tracks its own local limit.- Some responses in the list are much slower than others: This is expected; total throughput depends on the slowest requests in each concurrent batch. See the Concurrency guide for the underlying math.
- A
Promise.all()call fails as soon as one request errors: UsePromise.allSettled()instead, as shown above, so a single failure doesn’t abort the whole batch. - Cancelling a request doesn’t free a concurrency slot right away: ZenRows keeps the slot occupied for up to a few minutes after a client-side cancellation while it finishes processing server-side.
Pricing
Requests are billed identically whether they run one at a time or concurrently. Cost depends on the config you send per request, not on how many run in parallel:| Configuration | Cost multiplier vs. basic |
|---|---|
| Basic request | 1x |
js_render: true | 5x |
premium_proxy: true | 10x |
js_render: true + premium_proxy: true | 25x |
FAQ (Frequently Asked Questions)
What's the default concurrency if I don't set one?
What's the default concurrency if I don't set one?
- You can set it to any number that matches your ZenRows plan’s concurrent request limit.
Is there a get_async or similar method?
Is there a get_async or similar method?
No. Every method already returns a
Promise, so there’s no separate async variant to call, unlike SDKs for languages without built-in async I/O.