HTTP Request Runner: Bulk API Calls & Checks
Pricing
from $0.80 / 1,000 http requests
HTTP Request Runner: Bulk API Calls & Checks
Send a batch of HTTP requests and API calls (GET, POST, PUT, PATCH, DELETE) with headers, JSON body and query. Fill URLs from variables or CSV. Get status, response time, headers, parsed JSON and redirects, with retries, checks and hidden secrets.
Pricing
from $0.80 / 1,000 http requests
Rating
0.0
(0)
Developer
Malik Said
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
14 hours ago
Last modified
Categories
Share
HTTP Request Runner sends a batch of HTTP requests and API calls that you define. Each request can use any common method, headers, a query and a JSON or text body. The Actor saves one record per request with the status, response time, headers, the body (parsed when it is JSON) and every redirect. Use it from Clay, n8n, Make, Zapier, an AI agent or the Apify API.
What HTTP Request Runner does
- Sends GET, POST, PUT, PATCH, DELETE, HEAD and OPTIONS requests.
- Fills URLs, headers, query and body from rows of variables. Rows can come from a JSON list, CSV text or another Apify dataset.
- Retries network errors, timeouts and busy answers (408, 425, 429, 500, 502, 503, 504) up to 2 times.
- Parses JSON answers and picks values with simple paths such as
data.items[0].id. - Checks each answer: status, text in the body, JSON values, headers and response time.
- Keeps API keys and tokens in an encrypted Secrets field. Their values never appear in the results or the log.
- Follows up to 10 redirects and lists each hop.
- Respects robots.txt on every host and every redirect. Disallowed paths are not sent and cost nothing.
HTTP request output: what you get
One record per request. Main fields:
| Field | Meaning |
|---|---|
index, label | Order of the request and your own label |
method, url | What was sent, with variables filled |
ok | True for a 2xx answer with no error |
status, statusText | Status of the final answer, or robots-disallowed |
timeMs, firstByteMs | Response time and time to first byte, in milliseconds |
attempts | Tries made, including retries |
redirects, finalUrl | Each redirect hop and the final URL |
responseHeaders, contentType | Headers of the final answer |
json | Parsed body when the answer is JSON |
body | Body as text when it is not JSON |
bodyType, bodyBytes, bodyTruncated | json, text, binary or empty; size kept; whether it was cut |
extracted | Values picked with Values to pick |
assertionsPassed, assertionFailures | Result of your checks |
error | Why a request failed or was refused |
callbackStatus | Status your callback URL answered for this record. Null when no callback is set |
Binary answers such as images and PDFs are not saved. Their size and headers are. A body longer than Maximum body size is cut and marked bodyTruncated. A cut body is not parsed as JSON.
Sample record from a test run (the POST example in the input form; some response headers left out):
{"id": "request-00001","index": 1,"label": "create","variables": null,"method": "POST","url": "https://jsonplaceholder.typicode.com/posts","requestHeaders": {"Content-Type": "application/json","User-Agent": "Mozilla/5.0 (compatible; http-request-runner/0.1; Apify Actor)","Accept": "application/json, text/plain, */*","Accept-Encoding": "gzip, deflate, br"},"requestBodyBytes": 47,"ok": true,"status": 201,"statusText": "Created","finalUrl": "https://jsonplaceholder.typicode.com/posts","redirects": [],"attempts": 1,"timeMs": 227,"firstByteMs": 227,"responseHeaders": {"content-type": "application/json; charset=utf-8","content-length": "73","location": "https://jsonplaceholder.typicode.com/posts/101","server": "cloudflare"},"contentType": "application/json; charset=utf-8","bodyBytes": 73,"bodyTruncated": false,"bodyType": "json","body": null,"json": { "title": "Hello", "body": "Test post", "userId": 1, "id": 101 },"extracted": null,"assertionsPassed": true,"assertionFailures": [],"error": null,"requestedAt": "2026-10-22T08:08:10.203Z","callbackStatus": null,"scrapedAt": "2026-10-22T08:08:10.432Z"}
How to send bulk HTTP requests
- Open the input form. Add your calls in Requests, or paste plain URLs in URLs.
- Put tokens and API keys in Secrets, one per line, as
NAME=value. - Use
{{secret.NAME}}where the key goes, for example in a header:"Authorization": "Bearer {{secret.API_TOKEN}}". - To call one endpoint for many records, write
{{name}}in the URL or body. Then add rows in Variables, Variables as CSV or Variables from a dataset. - Add Checks for every response if you want a pass or fail per request.
- Run the Actor. Read the results in the Overview table, or as JSON, CSV or Excel.
Example request list:
[{"label": "post","method": "GET","url": "https://jsonplaceholder.typicode.com/posts/{{postId}}","extract": { "title": "title", "userId": "userId" }},{"label": "create","method": "POST","url": "https://jsonplaceholder.typicode.com/posts","headers": { "Content-Type": "application/json" },"body": { "title": "Hello", "body": "Test post", "userId": 1 },"expect": { "status": "201", "json": { "title": "Hello" } }}]
With Variables [{"postId": 1}, {"postId": 2}], the first request runs twice and the second runs once.
Same body for a list of URLs
You do not need the full Requests list to send one body to many URLs. Paste the URLs in URLs, set Method to POST, and put the JSON in Body. Add shared Query parameters the same way.
{"urls": ["https://jsonplaceholder.typicode.com/posts", "https://jsonplaceholder.typicode.com/comments"],"method": "POST","query": { "source": "apify" },"body": { "title": "Hello", "token": "{{secret.API_TOKEN}}" }}
Each URL gets one request with the same query and body. Secrets in the body are filled when sent and hidden in the results. GET and HEAD requests send no body; the log says so.
Template rules
{{name}}in a URL is URL-encoded.{{{name}}}is inserted as written, for example a full base URL.- In a JSON body, a value that is only
"{{id}}"keeps the variable's type, so a number stays a number. {{user.name}}reads a nested field from the row.- CSV values are always text.
- A request whose variable is missing in a row is refused and not charged.
Checks and picked values
expect keys: status ("2xx", "200", "200,201" or "200-299"), bodyContains, bodyNotContains, maxTimeMs, json and headerContains. In json, map a path to the value you expect, or to "*" to require only that the path exists.
extract maps a name to a path: data.id, items[0].name, items[-1].name (last item), items[*].id (all items) or header:etag.
Input
| Option | Default | Meaning |
|---|---|---|
| Requests | Example | Full request list (method, url, headers, query, body, label, expect, extract) |
| URLs | None | Quick list, sent with Method and the shared Headers, Query parameters and Body |
| Method | GET | Method for the URLs list |
| Headers | None | Headers added to every request |
| Query parameters | None | Query parameters added to every URL in the URLs list |
| Body | None | JSON body sent with every URL in the URLs list. GET and HEAD send no body |
| Secrets | None | NAME=value lines, encrypted, used as {{secret.NAME}} |
| Variables | Example | Rows that fill {{placeholders}} |
| Variables as CSV | None | Same, as CSV text |
| Variables from a dataset | None | Same, from an Apify dataset |
| Checks for every response | None | Checks applied to every answer |
| Values to pick | None | Paths picked from every JSON answer |
| Maximum requests | 100 | Stop after this many. 0 means the limit of 5,000 |
| Parallel requests | 5 | Up to 10 at once across hosts |
| Delay per host (ms) | 250 | Gap between two requests to one host. At least 200 |
| Timeout per request | 30 s | Up to 60 s |
| Retries | 2 | Up to 2 |
| Follow redirects | On | Up to 10 hops |
| Maximum body size | 256 KB | Up to 1,024 KB |
| Callback URL | None | POST each result record as JSON to your webhook |
| Mark the run failed when a request fails | Off | The run ends as failed after saving every result, so a run-failed alert fires |
An empty input runs the example from the input form.
robots.txt rule
The Actor reads robots.txt for every host, and again for every redirect hop. It follows the rules for all crawlers (User-agent: *). The check always runs. You cannot turn it off.
- A path that robots.txt disallows is not sent. Its row has
statusset torobots-disallowed, and it costs nothing. - The rule applies to every method, because robots.txt has no method rules.
- A site with no robots.txt (404) is allowed.
- A robots.txt that cannot be read (server error or no connection) blocks the host, as RFC 9309 requires.
- Some APIs disallow all crawlers in robots.txt. This Actor cannot call them.
Limits and safety
The Actor is for API calls and checks. It is not a load testing tool. These limits are fixed:
- At most 5,000 requests per run and 2,000 per host.
- At most 2 requests at a time to one host, and at least 200 ms between them.
- The default run timeout is 3,600 s (1 hour). The run stops sending about 45 s before the timeout, so every saved row is kept.
- Request bodies up to 1 MB. Response bodies kept up to 1 MB.
- Private, local and cloud metadata addresses are refused, also after DNS lookup and after redirects.
- Ports below 1024 are refused, except 80 and 443.
- Usernames and passwords inside URLs are refused. Use Secrets.
- Headers that hold a secret, plus
AuthorizationandCookie, are dropped when a redirect goes to another host.
You choose the endpoints. Follow each API's terms and rate limits. The Actor uses no proxy and does not get around logins, CAPTCHAs or bot protection.
Pricing
You pay a small start fee per run and a fee per request sent. Requests refused before sending (bad URL, private address, missing variable, robots.txt disallow) are saved with the reason and cost nothing. Retries of one request count as one request.
| Event | Free plan | GOLD plan and higher |
|---|---|---|
| Run start | $0.001 | $0.001 |
| HTTP request | $0.001 ($1.00 per 1,000) | $0.0008 ($0.80 per 1,000) |
| HTTP requests in one run | Free plan | GOLD plan and higher |
|---|---|---|
| 100 | $0.101 | $0.081 |
| 1,000 | $1.001 | $0.801 |
Costs include the run start fee.
FAQ
Can I call an API that needs a key? Yes. Put the key in Secrets and use {{secret.NAME}} in a header, the query or the URL.
Can I chain it after another Actor? Yes. Pick that Actor's dataset in Variables from a dataset. Each item becomes one row of variables.
Does it parse XML or HTML? It returns them as text in body. Only JSON is parsed.
Why was my request refused? The error field says why. A status of robots-disallowed means the site's robots.txt does not allow that path.
How do I get notified when a check fails? Turn on Mark the run failed when a request fails and add Apify's run-failed alert or webhook. Every result is still saved first. To get each result as it arrives, set Callback URL to your n8n, Make or Zapier webhook.
Other Actors by the same developer
Support
Report a problem in the Issues tab. Include the run link. Never paste a secret in an issue.