HTTP Request Runner avatar

HTTP Request Runner

Pricing

from $0.35 / 1,000 requests

Go to Apify Store
HTTP Request Runner

HTTP Request Runner

Send many HTTP requests to public web addresses and APIs in one run: GET, POST, PUT, PATCH, DELETE, HEAD or OPTIONS with your own headers and body. Each request gives one row with status, headers, body, parsed JSON, redirect chain and timing. Secret field for API keys.

Pricing

from $0.35 / 1,000 requests

Rating

0.0

(0)

Developer

Sanira Botheju

Sanira Botheju

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

a day ago

Last modified

Share

What does HTTP Request Runner do?

HTTP Request Runner sends a list of HTTP requests to public web addresses and APIs, and saves what came back for each one. Use GET, POST, PUT, PATCH, DELETE, HEAD or OPTIONS, add your own headers and a JSON or text body, and get one row per request with the status, headers, body, parsed JSON, redirect chain and response time, ready to export to Excel, CSV or JSON, or to pass on to another app.

  • Sends hundreds or thousands of requests in one run, ten at a time by default (up to 50)
  • Plain list of addresses, or a list of request objects where every request has its own method, headers, query and body
  • Shared defaults for method, headers and body that each request can override
  • A secret field for your API key or token, stored encrypted and never written to the run log or the results
  • Follows redirects and shows every step; requests that fail are repeated with a pause (rules below)
  • Parses JSON answers for you, and cuts very long answers at a size limit you choose
  • Requests go only to the addresses you list, and only to public addresses: localhost, private networks and cloud metadata addresses are refused, also after a redirect

What data do you get?

FieldExample
Place in your list2
Address and methodhttps://api.example.com/items, POST
Status201, with ok: true for any 2xx
Response headers{"content-type": "application/json", ...}
Answer textthe body as text, cut at your size limit
Parsed JSON{"id": 17, "name": "test"}
Redirectseach step with its status and target, and the final address
Size, time, tries212 bytes, 184 ms, 1 try
Errornull, or a code such as TIMEOUT, DNS_NOT_FOUND or BLOCKED_ADDRESS with a message

The request's own headers and body are never copied into the results.

How to send many HTTP requests

  1. Under Web addresses, add the addresses one by one, paste many with Bulk edit, or link a text file with one address per line. For different methods, headers or bodies per request, fill Requests (JSON) instead (see below).
  2. Choose the Method and, if every request needs them, Headers, Authorization (secret) and Body.
  3. Press Start, then open the Responses table and export it, or read it through the API.

The pre-filled example sends a GET and a POST with a JSON body to https://api.apify.com/v2/browser-info, an Apify endpoint that answers with a description of the request it received. Use it to see what the tool sends.

How much does it cost to send requests?

You pay for results, not for time: $0.50 per 1,000 requests. Apify subscribers on the Silver plan pay $0.43 and on the Gold plan $0.35 per 1,000 requests. Each run also has a start fee of $0.00005. Every request in your list gives one row and is charged once, including a request that failed or whose address was not valid. An address that appears twice in your list is sent twice.

Requests sentCost
100$0.05
1,000$0.50
10,000$5.00
100,000$50.00

Apify's free plan includes $5 of credit each month, which covers about 10,000 requests. Set a maximum cost for the run in Apify Console and the tool stops there and keeps what it has done. Requests that were never started are not sent.

Input

You need at least one address, under Web addresses or in Requests (JSON). Everything else has a default.

  • Web addresses: sent first, with the method, headers and body below. An entry may also carry its own method (other than GET), payload (the body) and headers. A method of GET on an entry is read as "not set", because the Console's address editor can write it into every entry; use Requests (JSON) to force GET for one request.
  • Requests (JSON): a list of objects, sent after the addresses. Each object has a url and may have method, headers, query, body and userData:
[
{ "url": "https://api.example.com/items", "method": "POST", "body": { "name": "test" } },
{ "url": "https://api.example.com/search", "query": { "q": "shoes", "page": 2 }, "headers": { "Accept": "application/json" } },
{ "url": "https://api.example.com/items/17", "method": "DELETE", "userData": { "id": 17 } }
]
  • Method, Headers and Body apply to every request that does not set its own. A request removes a shared header by giving null for it. The shared body is sent only with POST, PUT, PATCH and DELETE.
  • Authorization (secret): the full value of the Authorization header, for example Bearer YOUR_TOKEN. It is encrypted, left out of the log and the results, and not passed on to another website after a redirect.
  • Follow redirects, Maximum redirects (up to 10) and Time limit per request (30 seconds by default).
  • Retries: how many more tries after a network error, a 429 or a server error. Default 1, up to 5.
  • Largest answer kept (1 MB by default, up to 4 MB), Include the answer text, Parse JSON answers and Include response headers.
  • Requests at the same time (10 by default, up to 50) and per website (4 by default, up to 10).

A body that is an object or a list is sent as JSON (application/json). Text is sent exactly as written; text that is a JSON object or list also gets application/json unless you set a Content-Type. Set Content-Type: application/x-www-form-urlencoded and give an object to send a form.

Output example

{
"position": 2,
"url": "https://api.example.com/items",
"method": "POST",
"status": 201,
"statusText": "Created",
"ok": true,
"finalUrl": "https://api.example.com/items",
"redirectCount": 0,
"redirectChain": [],
"contentType": "application/json",
"contentLength": 31,
"bodyBytes": 31,
"truncated": false,
"timeMs": 184,
"attempts": 1,
"requestedAt": "2026-10-16T09:30:00.000Z",
"error": null,
"headers": { "content-type": "application/json; charset=utf-8", "content-length": "31" },
"body": "{\"id\":17,\"name\":\"test\"}",
"json": { "id": 17, "name": "test" }
}

A request that gets no answer has status: null and an error, for example DNS_NOT_FOUND, CONNECTION_REFUSED, TIMEOUT, TLS_CERTIFICATE_EXPIRED, TOO_MANY_REDIRECTS or BLOCKED_ADDRESS. Entries that cannot be sent at all (not an address, an unknown method, a GET with a body) become a row with attempts: 0 and an error such as INVALID_URL, INVALID_METHOD or INVALID_REQUEST. A short summary of the run is saved as SUMMARY.

What can you use it for?

  • Test an API: call many endpoints with different parameters and compare status codes, headers and answers
  • Send bulk POST, PUT or DELETE requests to your own API, for example to import records from a spreadsheet, with userData to match each row to your record
  • Trigger webhooks and automation endpoints, one request per item
  • Check that a list of endpoints is up, and how fast they answer, on a schedule in Apify Console
  • Fetch the JSON of many API addresses into one table for analysis

Use it from the API

curl -X POST "https://api.apify.com/v2/acts/cyber1nj3ct0r~http-request-runner/run-sync-get-dataset-items?token=YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"requests": [{"url": "https://api.example.com/items", "method": "POST", "body": {"name": "test"}}], "authorization": "Bearer YOUR_API_KEY"}'

The same works from Python, JavaScript, Make, Zapier and n8n through Apify's integrations. When you start a run through the API, put keys in the authorization field and not in headers: only the authorization field is stored encrypted.

FAQ

Can I set my own User-Agent?

No. The tool always sends Mozilla/5.0 (compatible; http-request-runner/1.0; +https://apify.com/cyber1nj3ct0r/http-request-runner), so the owner of a website or API can see who is calling and where to complain. A request or a shared header with a User-Agent is refused. All other headers can be set: Authorization, Content-Type, Accept, API key headers and custom headers. Headers that belong to the connection itself (Host, Content-Length, Connection and similar) are set by the tool.

Are my API keys safe?

Put the key in Authorization (secret); Apify stores that field encrypted. The tool never writes header values or bodies to the run log, and the result rows do not contain the request's headers or body. Two things to keep in mind. Fields such as Headers and Requests (JSON) are stored as plain input, so do not put secrets there. And the address of each request is saved in the results, so do not put keys in the query string if you can send them as a header.

Does the key follow a redirect to another website?

No. When a redirect leads to another website, only Accept and Accept-Language are passed on. The key, cookies and your other headers stay with the website you named. If a POST, PUT or DELETE with a body is redirected with 307 or 308 to another website, the body is not sent there: the row shows the redirect and the error REDIRECT_NOT_FOLLOWED. A redirect from http to https on the same host counts as the same website.

Why can the tool not reach my local or internal server?

It runs in a data centre, and it refuses localhost, private ranges such as 10.x.x.x, 172.16.x.x and 192.168.x.x, link-local and cloud metadata addresses (169.254.x.x) and names that point to them, including after a redirect. Ports that are not used for web traffic, such as 25 or 6667, are refused too. That protects your own network and others. The API you call must be reachable from the public internet.

When is a request repeated?

After a network error, a 429 and the server errors 500, 502, 503 and 504, up to the number under Retries, with a pause that doubles each time. A Retry-After header is respected up to 30 seconds; a longer wait is not waited for and the 429 is returned. POST and PATCH requests may already have been carried out when an answer is lost, so they are only repeated after 429, 503, or when no connection could be made. The attempts field shows how often a request was tried.

Why is the order different from my list?

Requests run several at a time, so rows arrive in the order the requests finish. Sort by Place in list (position) to get your order back, or give each request a userData value.

Why is the answer cut or empty?

Answers longer than Largest answer kept are cut and marked truncated: true; a cut JSON answer cannot be parsed. Files such as images, PDFs and archives are not read: the row has a warning and the size in contentLength. HEAD requests and 204 answers have no body.

Is it allowed?

You decide where the requests go. Send them only to services you own or run, or that allow it in their terms, and respect rate limits. The tool is not meant for load testing: it sends at most 50 requests at once and 10 to the same website, it does not use proxies, and it does not try to get round blocks, logins or CAPTCHAs. You are responsible for what you send and for how you use the answers.

Something does not work

Open an issue on the Issues tab with the request that shows the problem (leave out keys and private data). Every report is read and answered.