Photo by Marcus Urbenz on Unsplash
Hey there! Today, I want to talk about something simple but super useful — setting up Gzip compression for your API client. Sounds interesting? Let’s dive in!
First of all, what is Gzip?
Gzip is a tool that compresses and decompresses data (originally files) using the Deflate algorithm. In plain terms, it helps reduce the size of data packets sent over the network by compressing them as much as possible.
Note: Even though a gzipped string looks like a stream of unreadable bytes in the console, Gzip is only for request/response compression. If you’re looking for security and want to protect data in transit between your backend and client, you’ll need cryptographic algorithms instead.
Why do I need it?
You might ask me: “Why do I need this stuff, as everything works quickly enough?”. Just an example, what Gzip can do:

Server Response Size in Postman
In the example above, the original response size was nearly half a megabyte. But after compression, it shrank 8x smaller! I deliberately used a large dataset to show how significantly backend responses can be compressed, impacting data flow, network transmission, and overall performance.
It’s important to note that Gzip doesn’t compress all data equally well:
- Small payloads may not compress efficiently;
- Different data types compress at different rates.

Server Response Size in Postman
In my case, the API returns JSON. In your case, you’ll need to test based on your data structure.
Less talk, more code
By default, most backends don’t support Gzip (or any compression method) out of the box. That means both the client and the backend need to handle it explicitly. You’ll also need to ensure that both sides send the right headers when processing requests.
In case of Retrofit (I believe you are using it) we can add an Interceptor
to do something with requests and responses:
val clientBuilder = OkHttpClient.Builder().addInterceptor { chain -> val request = chain.request() // doing something with request val response = chain.proceed(request) // and here we doing something with response return@addInterceptor response } val retrofit = Retrofit.Builder() .baseUrl(BuildConfig.BASE_API_URL) .client(clientBuilder.build()) .build()
I have a feeling this isn’t the first Interceptor in your project, so I won’t go into too much detail about how they work 😉.
Here’s the full implementation of GzipInterceptor:
import okhttp3.Interceptor import okhttp3.Interceptor.Chain import okhttp3.Response import okhttp3.ResponseBody.Companion.toResponseBody import okio.GzipSource import okio.buffer class GzipInterceptor constructor(): Interceptor { override fun intercept(chain: Chain): Response { val originalRequest = chain.request() val compressedRequest = originalRequest.newBuilder() /// Add special headers to say the backend that we can handle Gzip .header("Accept-Encoding", "gzip, deflate") .method(originalRequest.method, originalRequest.body) .build() val response = chain.proceed(compressedRequest) /// If our Response Gzipped, then decompress it, otherwise /// we just return the Response return if (isGzipped(response)) unzip(response) else response } private fun unzip(response: Response): Response { val body = response.body ?: return response /// Decompress response using okio.GzipSource val gzipSource = GzipSource(body.source()) val bodyString = gzipSource.buffer().readUtf8() val responseBody = bodyString.toResponseBody(body.contentType()) val strippedHeaders = response.headers.newBuilder() .removeAll("Content-Encoding") .removeAll("Content-Length") .build() return response.newBuilder() .headers(strippedHeaders) .body(responseBody) .message(response.message) .build() } private fun isGzipped(response: Response): Boolean { val header = response.header("Content-Encoding") return (header != null) && ("gzip" in header) } }
Now add this Interceptor
to your network client setup (I suggest to add it the last in the queue, then it will handle the response the first):
val clientBuilder = OkHttpClient.Builder() /// our previous interceptors .addInterceptor(GzipInterceptor())
What if I’m using Ktor’s HttpClient in a Kotlin Multiplatform project?
You might ask me: “What if I’m using Ktor’s HttpClient in a Kotlin Multiplatform project?” No worries — Ktor makes this easy with built-in plugins for both — the client and the backend.
First of all, we need to add Gradle dependency
:
implementation("io.ktor:ktor-client-encoding:$ktor_version")
Job Offers
And then we just set up gzip
and deflate
as plugins to our client:
import io.ktor.client.* import io.ktor.client.engine.cio.* import io.ktor.client.plugins.contentencoding.* val client = HttpClient(CIO) { install(ContentEncoding) { gzip() deflate() } }
And that’s it! Now you just need to test it and ship it to your users. That’s all for today — thanks for reading! If you found this helpful, I’d appreciate a like, comment, and follow. 🚀
This article is previously published on proandroiddev.com.