diff --git a/CMakeLists.txt b/CMakeLists.txt
index 4668d4bea..ad73cf495 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -11,6 +11,8 @@ option(CITRA_USE_BUNDLED_SDL2 "Download bundled SDL2 binaries" OFF)
 option(ENABLE_QT "Enable the Qt frontend" ON)
 option(CITRA_USE_BUNDLED_QT "Download bundled Qt binaries" OFF)
 
+option(ENABLE_WEB_SERVICE "Enable web services (telemetry, etc.)" ON)
+
 if(NOT EXISTS ${CMAKE_SOURCE_DIR}/.git/hooks/pre-commit)
     message(STATUS "Copying pre-commit hook")
     file(COPY hooks/pre-commit
@@ -223,6 +225,9 @@ if (ENABLE_QT)
     find_package(Qt5 REQUIRED COMPONENTS Widgets OpenGL ${QT_PREFIX_HINT})
 endif()
 
+if (ENABLE_WEB_SERVICE)
+    add_definitions(-DENABLE_WEB_SERVICE)
+endif()
 
 # Platform-specific library requirements
 # ======================================
diff --git a/externals/CMakeLists.txt b/externals/CMakeLists.txt
index 11c5d8e7d..ccc7f13b6 100644
--- a/externals/CMakeLists.txt
+++ b/externals/CMakeLists.txt
@@ -4,12 +4,6 @@
 add_library(catch-single-include INTERFACE)
 target_include_directories(catch-single-include INTERFACE catch/single_include)
 
-# CPR
-option(BUILD_TESTING OFF)
-option(BUILD_CPR_TESTS OFF)
-add_subdirectory(cpr)
-target_include_directories(cpr INTERFACE ./cpr/include)
-
 # Crypto++
 add_subdirectory(cryptopp)
 
@@ -34,10 +28,6 @@ add_subdirectory(glad)
 # inih
 add_subdirectory(inih)
 
-# JSON
-add_library(json-headers INTERFACE)
-target_include_directories(json-headers INTERFACE ./json/src)
-
 # MicroProfile
 add_library(microprofile INTERFACE)
 target_include_directories(microprofile INTERFACE ./microprofile)
@@ -62,3 +52,15 @@ endif()
 # ENet
 add_subdirectory(enet)
 target_include_directories(enet INTERFACE ./enet/include)
+
+if (ENABLE_WEB_SERVICE)
+    # CPR
+    option(BUILD_TESTING OFF)
+    option(BUILD_CPR_TESTS OFF)
+    add_subdirectory(cpr)
+    target_include_directories(cpr INTERFACE ./cpr/include)
+
+    # JSON
+    add_library(json-headers INTERFACE)
+    target_include_directories(json-headers INTERFACE ./json/src)
+endif()
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index f855a5195..e11940f59 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -14,4 +14,6 @@ endif()
 if (ENABLE_QT)
     add_subdirectory(citra_qt)
 endif()
-add_subdirectory(web_service)
+if (ENABLE_WEB_SERVICE)
+    add_subdirectory(web_service)
+endif()
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 72233877b..b80efe192 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -386,5 +386,8 @@ set(HEADERS
 
 create_directory_groups(${SRCS} ${HEADERS})
 add_library(core STATIC ${SRCS} ${HEADERS})
-target_link_libraries(core PUBLIC common PRIVATE audio_core video_core web_service)
+target_link_libraries(core PUBLIC common PRIVATE audio_core video_core)
 target_link_libraries(core PUBLIC Boost::boost PRIVATE cryptopp dynarmic fmt)
+if (ENABLE_WEB_SERVICE)
+    target_link_libraries(core PUBLIC json-headers web_service)
+endif()
diff --git a/src/core/telemetry_session.cpp b/src/core/telemetry_session.cpp
index 1ba0a698d..70eff4340 100644
--- a/src/core/telemetry_session.cpp
+++ b/src/core/telemetry_session.cpp
@@ -6,13 +6,19 @@
 
 #include "common/scm_rev.h"
 #include "core/telemetry_session.h"
-#include "web_services/telemetry_json.h"
+
+#ifdef ENABLE_WEB_SERVICE
+#include "web_service/telemetry_json.h"
+#endif
 
 namespace Core {
 
 TelemetrySession::TelemetrySession() {
+#ifdef ENABLE_WEB_SERVICE
     backend = std::make_unique<WebService::TelemetryJson>();
-
+#else
+    backend = std::make_unique<Telemetry::NullVisitor>();
+#endif
     // Log one-time session start information
     const auto duration{std::chrono::steady_clock::now().time_since_epoch()};
     const auto start_time{std::chrono::duration_cast<std::chrono::microseconds>(duration).count()};