diff --git a/pom.xml b/pom.xml
index a7b6c91df6..7ba2d2584d 100644
--- a/pom.xml
+++ b/pom.xml
@@ -204,10 +204,6 @@
                             <pattern>io.papermc.lib</pattern>
                             <shadedPattern>io.github.thebusybiscuit.slimefun4.libraries.paperlib</shadedPattern>
                         </relocation>
-                        <relocation>
-                            <pattern>kong.unirest</pattern>
-                            <shadedPattern>io.github.thebusybiscuit.slimefun4.libraries.unirest</shadedPattern>
-                        </relocation>
                         <relocation>
                             <pattern>org.apache.commons.lang</pattern>
                             <shadedPattern>io.github.thebusybiscuit.slimefun4.libraries.commons.lang</shadedPattern>
@@ -358,20 +354,6 @@
             <version>1.0.8</version>
             <scope>compile</scope>
         </dependency>
-        <dependency>
-            <groupId>com.konghq</groupId>
-            <artifactId>unirest-java</artifactId>
-            <version>3.14.5</version>
-            <scope>compile</scope>
-
-            <exclusions>
-                <exclusion>
-                    <!-- No need to shade Gson, Spigot does that already -->
-                    <groupId>com.google.code.gson</groupId>
-                    <artifactId>gson</artifactId>
-                </exclusion>
-            </exclusions>
-        </dependency>
 
         <!-- Testing dependencies -->
         <dependency>
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/MetricsService.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/MetricsService.java
index e186004c4e..67cd5a7acd 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/MetricsService.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/MetricsService.java
@@ -4,11 +4,22 @@
 import java.io.IOException;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
+import java.net.URI;
 import java.net.URL;
 import java.net.URLClassLoader;
+import java.net.http.HttpClient;
+import java.net.http.HttpRequest;
+import java.net.http.HttpResponse;
+import java.net.http.HttpResponse.BodyHandler;
+import java.net.http.HttpResponse.BodySubscriber;
+import java.nio.ByteBuffer;
 import java.nio.file.Files;
+import java.nio.file.Path;
 import java.nio.file.StandardCopyOption;
-import java.util.concurrent.atomic.AtomicInteger;
+import java.time.Duration;
+import java.util.List;
+import java.util.concurrent.CompletionStage;
+import java.util.concurrent.Flow.Subscription;
 import java.util.logging.Level;
 
 import javax.annotation.Nonnull;
@@ -16,15 +27,13 @@
 
 import org.bukkit.plugin.Plugin;
 
+import com.google.gson.JsonElement;
+import com.google.gson.JsonParseException;
+import com.google.gson.JsonParser;
+
 import io.github.bakedlibs.dough.common.CommonPatterns;
 import io.github.thebusybiscuit.slimefun4.implementation.Slimefun;
 
-import kong.unirest.GetRequest;
-import kong.unirest.HttpResponse;
-import kong.unirest.JsonNode;
-import kong.unirest.Unirest;
-import kong.unirest.UnirestException;
-
 /**
  * This Class represents a Metrics Service that sends data to https://bstats.org/
  * This data is used to analyse the usage of this {@link Plugin}.
@@ -66,22 +75,12 @@ public class MetricsService {
     private final Slimefun plugin;
     private final File parentFolder;
     private final File metricsModuleFile;
+    private final HttpClient client = HttpClient.newHttpClient();
 
     private URLClassLoader moduleClassLoader;
     private String metricVersion = null;
     private boolean hasDownloadedUpdate = false;
 
-    static {
-        // @formatter:off (We want this to stay this nicely aligned :D )
-        Unirest.config()
-            .concurrency(2, 1)
-            .setDefaultHeader("User-Agent", "MetricsModule Auto-Updater")
-            .setDefaultHeader("Accept", "application/vnd.github.v3+json")
-            .enableCookieManagement(false)
-            .cookieSpec("ignoreCookies");
-        // @formatter:on
-    }
-
     /**
      * This constructs a new instance of our {@link MetricsService}.
      * 
@@ -199,20 +198,16 @@ public boolean checkForUpdate(@Nullable String currentVersion) {
      */
     private int getLatestVersion() {
         try {
-            HttpResponse<JsonNode> response = Unirest.get(RELEASES_URL).asJson();
+            HttpResponse<String> response = client.send(buildBaseRequest(URI.create(RELEASES_URL)), HttpResponse.BodyHandlers.ofString());
 
-            if (!response.isSuccess()) {
+            if (response.statusCode() < 200 || response.statusCode() >= 300) {
                 return -1;
             }
 
-            JsonNode node = response.getBody();
+            JsonElement element = JsonParser.parseString(response.body());
 
-            if (node == null) {
-                return -1;
-            }
-
-            return node.getObject().getInt("tag_name");
-        } catch (UnirestException e) {
+            return element.getAsJsonObject().get("tag_name").getAsInt();
+        } catch (IOException | InterruptedException | JsonParseException e) {
             plugin.getLogger().log(Level.WARNING, "Failed to fetch latest builds for Metrics: {0}", e.getMessage());
             return -1;
         }
@@ -235,19 +230,13 @@ private boolean download(int version) {
                 Files.delete(file.toPath());
             }
 
-            AtomicInteger lastPercentPosted = new AtomicInteger();
-            GetRequest request = Unirest.get(DOWNLOAD_URL + "/" + version + "/" + JAR_NAME + ".jar");
+            HttpResponse<Path> response = client.send(
+                buildBaseRequest(URI.create(DOWNLOAD_URL + "/" + version + "/" + JAR_NAME + ".jar")),
+                downloadMonitor(HttpResponse.BodyHandlers.ofFile(file.toPath()))
+            );
 
-            HttpResponse<File> response = request.downloadMonitor((b, fileName, bytesWritten, totalBytes) -> {
-                int percent = (int) (20 * (Math.round((((double) bytesWritten / totalBytes) * 100) / 20)));
 
-                if (percent != 0 && percent != lastPercentPosted.get()) {
-                    plugin.getLogger().info("# Downloading... " + percent + "% " + "(" + bytesWritten + "/" + totalBytes + " bytes)");
-                    lastPercentPosted.set(percent);
-                }
-            }).asFile(file.getPath());
-
-            if (response.isSuccess()) {
+            if (response.statusCode() >= 200 && response.statusCode() < 300) {
                 plugin.getLogger().log(Level.INFO, "Successfully downloaded {0} build: #{1}", new Object[] { JAR_NAME, version });
 
                 // Replace the metric file with the new one
@@ -258,7 +247,7 @@ private boolean download(int version) {
                 hasDownloadedUpdate = true;
                 return true;
             }
-        } catch (UnirestException e) {
+        } catch (InterruptedException | JsonParseException e) {
             plugin.getLogger().log(Level.WARNING, "Failed to fetch the latest jar file from the builds page. Perhaps GitHub is down? Response: {0}", e.getMessage());
         } catch (IOException e) {
             plugin.getLogger().log(Level.WARNING, "Failed to replace the old metric file with the new one. Please do this manually! Error: {0}", e.getMessage());
@@ -287,4 +276,58 @@ public String getVersion() {
     public boolean hasAutoUpdates() {
         return Slimefun.instance().getConfig().getBoolean("metrics.auto-update");
     }
+
+    private HttpRequest buildBaseRequest(@Nonnull URI uri) {
+        return HttpRequest.newBuilder()
+                .uri(uri)
+                .timeout(Duration.ofSeconds(5))
+                .header("User-Agent", "MetricsModule Auto-Updater")
+                .header("Accept", "application/vnd.github.v3+json")
+                .build();
+    }
+
+    private <T> BodyHandler<T> downloadMonitor(BodyHandler<T> h) {
+        return info -> new BodySubscriber<T>() {
+
+            private BodySubscriber<T> delegateSubscriber = h.apply(info);
+            private int lastPercentPosted = 0;
+            private long bytesWritten = 0;
+
+            @Override
+            public void onSubscribe(Subscription subscription) {
+                delegateSubscriber.onSubscribe(subscription);
+            }
+
+            @Override
+            public void onNext(List<ByteBuffer> item) {
+                bytesWritten += item.stream().mapToLong(ByteBuffer::capacity).sum();
+                long totalBytes = info.headers().firstValue("Content-Length").map(Long::parseLong).orElse(-1L);
+
+                int percent = (int) (20 * (Math.round((((double) bytesWritten / totalBytes) * 100) / 20)));
+
+                if (percent != 0 && percent != lastPercentPosted) {
+                    plugin.getLogger().info("# Downloading... " + percent + "% " + "(" + bytesWritten + "/" + totalBytes + " bytes)");
+                    lastPercentPosted = percent;
+                }
+
+                delegateSubscriber.onNext(item);
+            }
+
+            @Override
+            public void onError(Throwable throwable) {
+                delegateSubscriber.onError(throwable);
+
+            }
+
+            @Override
+            public void onComplete() {
+                delegateSubscriber.onComplete();
+            }
+
+            @Override
+            public CompletionStage<T> getBody() {
+                return delegateSubscriber.getBody();
+            }
+        };
+    }
 }
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/github/ContributionsConnector.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/github/ContributionsConnector.java
index 7dd4970552..4eb9d92637 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/github/ContributionsConnector.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/github/ContributionsConnector.java
@@ -9,11 +9,11 @@
 import javax.annotation.Nonnull;
 import javax.annotation.ParametersAreNonnullByDefault;
 
-import io.github.thebusybiscuit.slimefun4.implementation.Slimefun;
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
 
-import kong.unirest.JsonNode;
-import kong.unirest.json.JSONArray;
-import kong.unirest.json.JSONObject;
+import io.github.thebusybiscuit.slimefun4.implementation.Slimefun;
 
 class ContributionsConnector extends GitHubConnector {
 
@@ -90,11 +90,11 @@ public boolean hasFinished() {
     }
 
     @Override
-    public void onSuccess(@Nonnull JsonNode response) {
+    public void onSuccess(@Nonnull JsonElement response) {
         finished = true;
 
-        if (response.isArray()) {
-            computeContributors(response.getArray());
+        if (response.isJsonArray()) {
+            computeContributors(response.getAsJsonArray());
         } else {
             Slimefun.logger().log(Level.WARNING, "Received an unusual answer from GitHub, possibly a timeout? ({0})", response);
         }
@@ -123,13 +123,13 @@ public Map<String, Object> getParameters() {
         return parameters;
     }
 
-    private void computeContributors(@Nonnull JSONArray array) {
-        for (int i = 0; i < array.length(); i++) {
-            JSONObject object = array.getJSONObject(i);
+    private void computeContributors(@Nonnull JsonArray array) {
+        for (JsonElement element : array) {
+            JsonObject object = element.getAsJsonObject();
 
-            String name = object.getString("login");
-            int commits = object.getInt("contributions");
-            String profile = object.getString("html_url");
+            String name = object.get("login").getAsString();
+            int commits = object.get("contributions").getAsInt();
+            String profile = object.get("html_url").getAsString();
 
             if (!ignoredAccounts.contains(name)) {
                 String username = aliases.getOrDefault(name, name);
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/github/GitHubActivityConnector.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/github/GitHubActivityConnector.java
index b298195e7b..60697f1345 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/github/GitHubActivityConnector.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/github/GitHubActivityConnector.java
@@ -7,10 +7,10 @@
 import javax.annotation.Nonnull;
 import javax.annotation.ParametersAreNonnullByDefault;
 
-import io.github.thebusybiscuit.slimefun4.utils.NumberUtils;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
 
-import kong.unirest.JsonNode;
-import kong.unirest.json.JSONObject;
+import io.github.thebusybiscuit.slimefun4.utils.NumberUtils;
 
 class GitHubActivityConnector extends GitHubConnector {
 
@@ -23,11 +23,11 @@ class GitHubActivityConnector extends GitHubConnector {
     }
 
     @Override
-    public void onSuccess(@Nonnull JsonNode response) {
-        JSONObject object = response.getObject();
-        int forks = object.getInt("forks");
-        int stars = object.getInt("stargazers_count");
-        LocalDateTime lastPush = NumberUtils.parseGitHubDate(object.getString("pushed_at"));
+    public void onSuccess(@Nonnull JsonElement response) {
+        JsonObject object = response.getAsJsonObject();
+        int forks = object.get("forks").getAsInt();
+        int stars = object.get("stargazers_count").getAsInt();
+        LocalDateTime lastPush = NumberUtils.parseGitHubDate(object.get("pushed_at").getAsString());
 
         callback.accept(forks, stars, lastPush);
     }
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/github/GitHubConnector.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/github/GitHubConnector.java
index 422ed31787..3d6a711b9e 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/github/GitHubConnector.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/github/GitHubConnector.java
@@ -6,7 +6,12 @@
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStreamReader;
+import java.net.URI;
+import java.net.URISyntaxException;
 import java.net.URL;
+import java.net.http.HttpClient;
+import java.net.http.HttpRequest;
+import java.net.http.HttpResponse;
 import java.nio.charset.StandardCharsets;
 import java.util.Map;
 import java.util.logging.Level;
@@ -14,13 +19,11 @@
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 
-import io.github.thebusybiscuit.slimefun4.implementation.Slimefun;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonParseException;
+import com.google.gson.JsonParser;
 
-import kong.unirest.HttpResponse;
-import kong.unirest.JsonNode;
-import kong.unirest.Unirest;
-import kong.unirest.UnirestException;
-import kong.unirest.json.JSONException;
+import io.github.thebusybiscuit.slimefun4.implementation.Slimefun;
 
 /**
  * The {@link GitHubConnector} is used to connect to the GitHub API service.
@@ -34,6 +37,7 @@ abstract class GitHubConnector {
 
     private static final String API_URL = "https://api.github.com/";
     private static final String USER_AGENT = "Slimefun4 (https://github.com/Slimefun)";
+    private static final HttpClient client = HttpClient.newHttpClient();
 
     protected final GitHubService github;
     private final String url;
@@ -83,7 +87,7 @@ abstract class GitHubConnector {
      * @param response
      *            The response
      */
-    public abstract void onSuccess(@Nonnull JsonNode response);
+    public abstract void onSuccess(@Nonnull JsonElement response);
 
     /**
      * This method is called when the connection has failed.
@@ -105,38 +109,44 @@ void download() {
         }
 
         try {
-            // @formatter:off
-            HttpResponse<JsonNode> response = Unirest.get(url)
-                    .queryString(getParameters())
-                    .header("User-Agent", USER_AGENT)
-                    .asJson();
-            // @formatter:on
-
-            if (response.isSuccess()) {
-                onSuccess(response.getBody());
-                writeCacheFile(response.getBody());
+            String params = getParameters().entrySet().stream()
+                .map(p -> p.getKey() + "=" + p.getValue())
+                .reduce((p1, p2) -> p1 + "&" + p2)
+                .map(s -> "?" + s)
+                .orElse("");
+            URI uri = new URI(url + params);
+
+            HttpResponse<String> response = client.send(
+                HttpRequest.newBuilder(uri).header("User-Agent", USER_AGENT).build(),
+                HttpResponse.BodyHandlers.ofString()
+            );
+            JsonElement element = JsonParser.parseString(response.body());
+
+            if (response.statusCode() >= 200 && response.statusCode() < 300) {
+                onSuccess(element);
+                writeCacheFile(element);
             } else {
                 if (github.isLoggingEnabled()) {
-                    Slimefun.logger().log(Level.WARNING, "Failed to fetch {0}: {1} - {2}", new Object[] { url, response.getStatus(), response.getBody() });
+                    Slimefun.logger().log(Level.WARNING, "Failed to fetch {0}: {1} - {2}", new Object[] { url, response.statusCode(), element });
                 }
 
                 // It has the cached file, let's just read that then
                 if (file.exists()) {
-                    JsonNode cache = readCacheFile();
+                    JsonElement cache = readCacheFile();
 
                     if (cache != null) {
                         onSuccess(cache);
                     }
                 }
             }
-        } catch (UnirestException e) {
+        } catch (IOException | InterruptedException | JsonParseException | URISyntaxException e) {
             if (github.isLoggingEnabled()) {
                 Slimefun.logger().log(Level.WARNING, "Could not connect to GitHub in time.", e);
             }
 
             // It has the cached file, let's just read that then
             if (file.exists()) {
-                JsonNode cache = readCacheFile();
+                JsonElement cache = readCacheFile();
 
                 if (cache != null) {
                     onSuccess(cache);
@@ -150,16 +160,16 @@ void download() {
     }
 
     @Nullable
-    private JsonNode readCacheFile() {
+    private JsonElement readCacheFile() {
         try (BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(file), StandardCharsets.UTF_8))) {
-            return new JsonNode(reader.readLine());
-        } catch (IOException | JSONException e) {
+            return JsonParser.parseString(reader.readLine());
+        } catch (IOException | JsonParseException e) {
             Slimefun.logger().log(Level.WARNING, "Failed to read Github cache file: {0} - {1}: {2}", new Object[] { file.getName(), e.getClass().getSimpleName(), e.getMessage() });
             return null;
         }
     }
 
-    private void writeCacheFile(@Nonnull JsonNode node) {
+    private void writeCacheFile(@Nonnull JsonElement node) {
         try (FileOutputStream output = new FileOutputStream(file)) {
             output.write(node.toString().getBytes(StandardCharsets.UTF_8));
         } catch (IOException e) {
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/github/GitHubIssuesConnector.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/github/GitHubIssuesConnector.java
index 81cd1ac5d3..96a4237e1e 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/github/GitHubIssuesConnector.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/github/GitHubIssuesConnector.java
@@ -7,11 +7,11 @@
 import javax.annotation.Nonnull;
 import javax.annotation.ParametersAreNonnullByDefault;
 
-import io.github.thebusybiscuit.slimefun4.implementation.Slimefun;
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
 
-import kong.unirest.JsonNode;
-import kong.unirest.json.JSONArray;
-import kong.unirest.json.JSONObject;
+import io.github.thebusybiscuit.slimefun4.implementation.Slimefun;
 
 class GitHubIssuesConnector extends GitHubConnector {
 
@@ -24,15 +24,15 @@ class GitHubIssuesConnector extends GitHubConnector {
     }
 
     @Override
-    public void onSuccess(@Nonnull JsonNode response) {
-        if (response.isArray()) {
-            JSONArray array = response.getArray();
+    public void onSuccess(@Nonnull JsonElement response) {
+        if (response.isJsonArray()) {
+            JsonArray array = response.getAsJsonArray();
 
             int issues = 0;
             int pullRequests = 0;
 
-            for (int i = 0; i < array.length(); i++) {
-                JSONObject obj = array.getJSONObject(i);
+            for (JsonElement element : array) {
+                JsonObject obj = element.getAsJsonObject();
 
                 if (obj.has("pull_request")) {
                     pullRequests++;