libcpr/cpr: a C++17 wrapper over libcurl for people who want Python Requests ergonomics
C++ Requests: Curl for People, a spiritual port of Python Requests.
At a glance
- What is it?
- cpr turns libcurl's easy interface into a handful of C++17 idioms: cpr::Get, cpr::Url, cpr::Parameters, cpr::Response. It is a good fit for application code that makes a few HTTP calls, and a poor fit if you need streaming control or a header-only dependency.
- Who is it for?
- Adopt cpr if you write C++17 application code that makes ordinary HTTP calls and you would rather not hand-manage libcurl handles, curl_slist headers and cleanup. Do not adopt it if you need a header-only dependency, if you must support a compiler older than C++17 on a supported release line, or if you need fine-grained control over the transfer loop.
- Can I use it commercially?
- Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
- Is it still maintained?
- Yes. The repository last received commits 11 days ago.
- What is it written in?
- Mainly C++, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 29, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The problem cpr solves, and who actually has it
libcurl's easy interface is not easy. You allocate a CURL handle, set options one by one with curl_easy_setopt, build a linked list of headers with curl_slist_append, remember to free that list, call curl_easy_perform, then read the body out of a write callback you had to supply yourself. The README says this directly: "Despite its name, libcurl's easy interface is far from simple, and errors and frustration often arise from mistakes or misuse." That sentence is the whole pitch.
cpr targets the developer who is already writing C++17 and wants a network call to look like a function call. The README describes it as "a simple wrapper around libcurl inspired by the excellent Python Requests project," and the API surface follows that lineage: you pass named option objects into a verb function and get back a response object. The audience is application and tool developers, not library authors building an HTTP stack. If you are writing a CLI that talks to an internal API, a test harness that hits a service, or a desktop application that polls a REST endpoint, that is the shape cpr was designed for.
How the option-object design keeps call sites readable
The mechanism is composition of small value types rather than a builder or a config struct. The README's GET example passes cpr::Url, cpr::Authentication and cpr::Parameters as separate arguments to cpr::Get, and the returned cpr::Response exposes status_code, header and text as members. Each option type carries one concern, so a call site reads as a sentence about the request instead of a sequence of setter calls.
Underneath, cpr is a libcurl wrapper. The README states that it provides "Thread Safe access to libCurl," which matters because libcurl's own threading rules are a common source of confusion: you cannot share a handle across threads, but you can have one per thread. cpr's asynchronous request support and its callback interfaces sit on top of that. The response object is the data flow boundary: libcurl's write callback feeds the body, headers are parsed into the header member, and the status code is lifted out of the CURLcode and response-code path so callers rarely touch CURL types directly.
The feature list is broad for a wrapper: custom headers, URL-encoded parameters and POST values, multipart form uploads, file uploads, Basic, Bearer, Digest and NTLM authentication, connection and request timeouts, low-speed connection timeouts, cookies, proxies, PUT, DELETE, HEAD, OPTIONS and PATCH, OpenSSL and WinSSL for HTTPS, and Server Sent Events handling. That last one arrived in the 1.14.0 release, whose title in the release list is "1.14.0 - NuGet Fixes And Server Sent Events."
Installing cpr with CMake FetchContent and making a first request
The README calls FetchContent "the primary way" to integrate cpr into an existing CMake project. You declare the dependency with a pinned git tag and then link the produced target. Note that the README's snippet uses a commit hash and tells you to replace it with your desired commit from the releases page.
include(FetchContent)
FetchContent_Declare(cpr GIT_REPOSITORY https://github.com/libcpr/cpr.git
GIT_TAG f091b2c061b307ee89b164c39976fc9202a1c79d)
FetchContent_MakeAvailable(cpr)After that, the target cpr::cpr is available and you link it privately into your own target. The README's phrasing is that there is "no need to handle libcurl yourself" with this route, because the dependencies are pulled in for you.
target_link_libraries(your_target_name PRIVATE cpr::cpr)If you prefer a system install instead, the README notes this is feasible only when CPR_USE_SYSTEM_CURL is set, referencing pull request #645. The build sequence clones the repository, configures with that flag, builds in parallel, and installs.
git clone https://github.com/libcpr/cpr.git
cd cpr && mkdir build && cd build
cmake .. -DCPR_USE_SYSTEM_CURL=ON
cmake --build . --parallel
sudo cmake --install .With the library installed you switch to find_package, which the README shows as a required package plus the same cpr::cpr link line.
find_package(cpr REQUIRED)
add_executable(your_target_name your_target_name.cpp)
target_link_libraries(your_target_name PRIVATE cpr::cpr)For a first real use, the README's own example is the shortest complete program: include cpr/cpr.h, call cpr::Get with a URL, optional authentication and query parameters, then read r.status_code, r.header["content-type"] and r.text. The reader should expect a 200 and a JSON body from that endpoint when the credentials and parameters are valid. cpr is also available as a module from the Bazel Central Registry according to the README, and there is an Arch Linux AUR package, though the README warns that "so few distributions currently have a package for cpr" that most users will not be able to rely on that route.
Where cpr stops being the right tool
The first limitation is stated by the project itself. The supported releases table lists master and 1.14.x as the only lines with supported status, both requiring C++17. Everything from 1.10.x through 1.13.x is marked unsupported, and 1.9.x and below are unsupported and require C++11. If your toolchain is pinned to an older standard and you cannot move to C++17, the supported path is closed to you; the README offers no maintained C++11 line.
The second is that cpr is a wrapper, not an HTTP stack. Anything libcurl does not expose through the option objects cpr defines is either unreachable or requires dropping below the abstraction. The README's feature list is long, but it is a list, and it does not claim to cover every libcurl capability. If your work involves tight control of the transfer loop, custom multi-handle scheduling, or protocol behaviour outside the documented option set, you will end up either fighting the wrapper or bypassing it, and at that point the wrapper is cost without benefit.
The third is packaging. The README is unusually candid that distribution packages are scarce, which means most consumers take on a build-from-source dependency. That is fine inside a CMake project that already vendors dependencies. It is friction for a project that expects to find libraries through a system package manager and nothing else. The README also points to the tests as the fallback documentation, saying the docs "should give you a better idea of how to use the library than the tests currently do," which implies the tests are not a pleasant substitute for reading docs.
cpr against cpp-httplib, curlpp and raw libcurl
cpp-httplib is the comparison that surfaces most often in searches around this project, and the difference is architectural rather than cosmetic. cpp-httplib is a header-only C++ library that implements both client and server; you drop in a header and you are done, with no CMake target to fetch and no separate libcurl build to manage. cpr takes the opposite position: it is a compiled library that depends on libcurl, and the payoff is that it inherits libcurl's protocol coverage, TLS backends and proxy behaviour rather than reimplementing them. If your priority is zero build integration, cpp-httplib wins on that axis alone. If your priority is libcurl's behaviour and you want it behind a friendlier API, cpr is the closer match.
curlpp and curlcpp are C++ bindings to libcurl as well, but they bind the C API more literally. The README's framing of cpr's value is that it uses "the more expressive features of C++17" to distill network calls "into a few clear and concise idioms," which is a claim about ergonomics relative to those thinner bindings. The practical difference is how much of libcurl's option model leaks into your code: with cpr you pass cpr::Url and cpr::Parameters; with a thin binding you are closer to setting libcurl options yourself, which is more control and more ceremony.
Raw libcurl remains the baseline. The README links to a gist it describes as "less functional, more complicated code, without cpr," which is the honest way to present the trade: cpr removes boilerplate but also removes the option to hand-tune each step.
Maintenance, release cadence and licence
The repository is not archived, and the last push was on 2026-09-18, so the codebase is being touched on a current basis. The README names two maintainers, Fabian Sauter and Kilian Traub, and points to a Gitter channel for quick help and discussion.
The release history shows three releases in the 1.14 line: 1.14.0 on 2025-11-29 with the title "NuGet Fixes And Server Sent Events," 1.14.1 on 2025-11-29 labelled "Windows Build Hotfix," and 1.14.2 on 2026-02-15. The pattern is worth reading carefully. A hotfix released the same day as the feature release, and a follow-up roughly two and a half months later, suggests that the Windows and NuGet packaging paths are where breakage tends to appear. If you consume cpr through NuGet or build on Windows, budget for pinning a patch version rather than tracking the line loosely.
The upgrade cost is tied to the C++ standard, not to API churn that the README documents. The supported table puts master and 1.14.x both at C++17, so moving from 1.14.x to master does not change your required standard. Moving from 1.9.x or earlier does: those lines are C++11, and the README marks them unsupported. Any project still on the old line faces a language-standard migration, not just a version bump.
The license field for the repository is NOASSERTION, which means the platform could not classify it automatically. The repository has a LICENSE file at the top level. Read that file yourself before you depend on the library in a distributed product; a NOASSERTION label is not a licence, and nothing in the README resolves it.
Editorial conclusion
Adopt cpr if you write C++17 application code that makes ordinary HTTP calls and you would rather not hand-manage libcurl handles, curl_slist headers and cleanup. Do not adopt it if you need a header-only dependency, if you must support a compiler older than C++17 on a supported release line, or if you need fine-grained control over the transfer loop. Before committing, verify three things: that your CMake setup can consume the cpr::cpr target, whether you want CPR_USE_SYSTEM_CURL against your own libcurl, and whether the 1.14.x line is the one you pin, since the README marks 1.10.x through 1.13.x as unsupported.
Frequently asked questions
What is libcpr/cpr used for in C++?
It is a wrapper around libcurl that turns HTTP calls into short C++17 expressions such as cpr::Get(cpr::Url{...}, cpr::Parameters{...}), returning a cpr::Response with status_code, header and text members. The README describes it as a spiritual port of Python Requests.
How do I install libcpr/cpr in a CMake project?
The README calls FetchContent the primary route: declare cpr with FetchContent_Declare and a pinned GIT_TAG, call FetchContent_MakeAvailable(cpr), then link cpr::cpr into your target. A system install is also possible but only when CPR_USE_SYSTEM_CURL is set.
Which C++ standard does libcpr/cpr require?
The supported releases table lists master and 1.14.x as supported, both requiring C++17. Versions 1.10.x through 1.13.x are marked unsupported at C++17, and 1.9.x and below are unsupported at C++11.
Does libcpr/cpr work with Bazel or Linux distribution packages?
The README states cpr is available as a module from the Bazel Central Registry and points to its module page. For Linux distributions it lists an Arch Linux AUR package and warns that so few distributions package cpr that most users cannot rely on that approach.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/libcpr-cpr)