A text file of HTTP calls, each with its expected reply
Hurl is a command-line tool from Orange that runs HTTP requests written in plain .hurl files. Under each request goes the response you expect: status code, headers, then assertions on the body. Networking goes through libcurl, and options borrowed from curl keep exactly the same meaning. Run bare, Hurl prints the last response the way curl would; --test swaps that for a per-file summary. Either way, a failed assertion ends the run with exit code 4.
POST https://api.example.org/jobs
HTTP 201
[Captures]
job_id: jsonpath "$.id"
GET https://api.example.org/jobs/{{job_id}}
[Options]
retry: 10
retry-interval: 500ms
HTTP 200
[Asserts]
jsonpath "$.state" == "COMPLETED"
duration < 1000
certificate "Expire-Date" daysAfterNow > 15
The second call is retried up to ten times, 500 ms apart, until every assertion passes.
Assertions that reach cookie flags and certificate expiry
- JSONPath (an RFC 9535 implementation since 8.0), XPath for HTML and XML, and regex matching.
- Less common queries: a cookie's
Secure,HttpOnlyandSameSiteattributes, the TLS certificate's expiry date and subject alternative names, the body's SHA-256, the HTTP version, the server IP and the response time. - Captures carry a token or an ID from one request into the next.
- Values passed with
--secret, or captured withredact, are masked in logs and reports. - HTML, JSON, JUnit and TAP reports, the HTML one with per-request timings.
--curlexports every request as a curl command, andhurlfmt --in curlturns a curl command into a Hurl file.
Async jobs, CSRF logins and load runs
- Poll an asynchronous job with
retryuntil its status says it is done. - Replay a form login without a browser, picking the CSRF token out of the page with XPath.
- Fail the CI build when a certificate gets close to expiry, using
certificate "Expire-Date" daysAfterNow > 15. - Put load on an endpoint with
--repeatand--jobs. The docs suggest ten files of 10,000 requests rather than 100,000 one-request files, which can run the machine out of ephemeral TCP ports.
Command line only, tied to libcurl, breaking changes in 8.0
The project sets itself apart from GUI clients and browser automation. Its FAQ finds GUI-oriented tools such as Postman less attractive than a CLI, and describes Karate as doing more at the price of more complexity. Against Selenium, it argues that working on raw HTTP, with no headless browser, keeps false positives very rare.
There is no GUI and no JavaScript engine. The FAQ's own answer to "why shouldn't I use Hurl?" is "if you need a GUI". Hurl only sees what the server sends back, so a page rendered client-side calls for a driven browser such as Playwright.
The binary leans on the system's libcurl. The README promises a single binary with no runtime, yet the FAQ shows an executable dynamically linked against libcurl and libxml2, and warns that Hurl cannot send HTTP/2 if the installed libcurl lacks it. hurl --version reports which libcurl is in use. The prebuilt Linux binary needs glibc 2.35 or later, and Windows users have to install the Visual C++ Redistributable themselves.
Each file is a self-contained scenario. In --test mode, files run in parallel and share nothing: requests within a file run in order and share cookies and captured values, but nothing crosses from one file to the next. Templates stop at variables and a few functions (newUuid, newDate), so tomorrow's date has to be computed in the shell and passed in.
The latest release is 8.0.1, published on 29 April 2026. It fixes underscores in JSONPath dot-notation member names, two days after an 8.0.0 that shipped breaking changes: --ignore-asserts became --no-assert, HURL_foo environment variables gave way to HURL_VARIABLE_foo, and --interactive was dropped. Nothing has been released since, though the default branch was still taking commits in October 2026.
