Skip to content
CF / PROJECT 01

Litho

Native client for linux.do

A native linux.do client for iOS and Android that gets past Cloudflare by letting a browser make every request.

Status
Daily driver · iOS beta / Android released
Stack
Swift · SwiftUI · iOS 17+ · Kotlin
01

Why

linux.do is a community I read every day, and it deserved a native, logged-in experience on the phone.

Discourse already has a solid API. The obstacle was never the data — it was getting a request through at all.

02

Problem

  1. 01

    linux.do sits behind Cloudflare. A plain URLSession or curl request gets a 403 challenge page.

  2. 02

    Third-party tools and even simple scripts keep hitting challenges and losing their session.

  3. 03

    Wrapping the site in a web view passes the challenge, but gives up native reading, interaction and notifications.

03

System

Litho doesn't send requests itself. Every call goes through one off-screen browser gateway.

  1. L1Native app

    SwiftUI on iOS, Kotlin + Compose on Android: topic feeds, reading, reactions, chat, private messages and notifications.

  2. L2Single entry point

    TopicList, Reply, Reaction and every other feature call one gateway API instead of the network.

  3. L3WebView gateway

    An off-screen WKWebView runs each request through the page's own fetch(), carrying the real browser's UA, cookies and TLS fingerprint.

  4. L4Discourse

    The REST API returns real JSON; MessageBus long polling carries real-time updates.

04

Implementation

  • Images through the gateway

    Avatars, post images and badges are fetched as binary inside the page, handed back as base64 and cached by a native loader.

  • Self-healing challenges

    When a challenge does appear, the gateway reloads the page to complete it and resumes the request, with a status banner instead of an app restart.

  • Real-time channel

    MessageBus subscriptions run through the gateway and drive chat, new replies and notifications.

  • Rendering and storage

    Posts render as a single WKWebView document; GRDB keeps the local cache; UserNotifications and background refresh deliver notifications.

  • Android port

    Kotlin + Compose, ported one-to-one from the iOS architecture.

05

Decisions

  1. D1

    Borrow the browser instead of fighting it

    Rather than imitating fingerprints or solving challenges, requests are handed to a real browser context. To Cloudflare, it simply is a browser.

  2. D2

    One gateway for all networking

    Features never talk to the network directly, so challenges, images and real-time updates are solved once, in one place.

  3. D3

    Do three things well

    Get through Cloudflare, feel native, and match the web interactions — not an all-purpose forum client.

06

Result

Status
Daily driver
iOS
TestFlight beta · iOS 17+
Android
APK released

It grew from an MVP into the client I use every day: reading, reactions, chat, private messages and real-time notifications.