A simple Gopher client for KaiOS
prepared the readme to v0.0.6
basic gopher:// url view activity handling


browse  log 



You can also use your local clone with git send-email.

#Kopher: a simple Gopher client/browser for KaiOS

Yo dawg, we put a browser in your browser, so you can browse Gopher while you browse KaiOS UI

#What is it?

Kopher is a really small (under 500 SLOC of HTML+JS) client to browse pages ("holes") using Gopher protocol. Besides Gophermaps, it also allows to display plain text downloaded via this protocol "as is" and redirect to the system browser to view non-Gopher protocol links and download non-text media file types.

Structurally, Kopher is a KaiOS-specific frontend to the hi01379.js library which is developed under the same project. Both the library and the app are designed to be as lightweight as practically possible.

Installation is as usual, via WebIDE. For GerdaOS, you can prepare the kopher.gpkg.zip file as follows:

zip -9r --exclude=*.git* --exclude=*.DS_Store* --exclude=README.md ../application.zip .
cd ..
echo {\"version\": 1, \"manifestURL\": \"app://kopher.luxferre.top/manifest.webapp\"} > metadata.json
zip -9 kopher.gpkg.zip application.zip metadata.json

#Which KaiOS versions are supported?

Tested on 2.5.x up to 2.5.4. Doesn't work on 1.0 (some bug with mozTCPSockets I'm not gonna investigate) and definitely won't work on 3.x.

More specifically, as of now, Kopher has been tested on the following devices and KaiOS versions (ordered from oldest to newest):

  • Nokia 8110 4G v13 (2.5/GerdaOS)
  • Nokia 8110 4G v17 (2.5.1)
  • Doro 7060 (DFC-0190) (2.5.1)*
  • Sigma mobile S3500 sKai (**
  • Nokia 800 Tough (2.5.2)
  • Nokia 2720 Flip (
  • Crosscall Core-S4 (
  • Nokia 8000 4G (2.5.4)

* install-via-FFBM trick; also, the system statusbar on the Doro is larger than usual, so the addressbar is a bit overlapped (doesn't hamper its readability)

** there is a bug with displaying Blob-type images on the sKai, so only the download option works correctly

N.B. If you want to debug Kopher to support KaiOS 1.0, make sure to replace the '\u{1f310}' reference in js/app.js with '\uD83C\uDF10' surrogate pair first.

#Which Gophermap entry types are supported?

They are listed in the hi01379.js library name:

  • 0 (plain text)
  • 1 (Gophermap)
  • 3 (error message)
  • 7 (search request)
  • 9 (arbitrary binary type), as well as g (GIF image file)
  • i (information message), as well as I (generic image file)
  • h (external URL)

Outside this list, unknown binary types (5, s, ;, d) are just treated as type 9 internally, and every other type is assumed to be plain text on access. The 8-type entries are just converted to telnet:// URIs with no logic attached.

In the Gophermap, any line that doesn't contain tabulation characters is automatically considered an information line by Kopher client and hi01379.js library. This allows to display messages from Gopher servers that don't strictly adhere to the format, such as Gophernicus or PyGopherd.

Note that currently, Kopher and hi01379.js assume that the search request from a 7-type entry will lead to another Gophermap and not to any other resource type. This was necessary to remove ambiguity, as the client doesn't heuristically determine the response type from its body.

#Which UI features are supported?

  • Minimalistic but easy and quick WAP-like navigation (see "Controls")
  • The gopher:// scheme is assumed by default (no need to enter it manually), same for the port 70
  • One-key light/dark theme toggle
  • One-key switching the line wrapping mode between off (default) and on (for comfortable reading even the hard-wrapped documents)
  • Unlimited navigation history (doesn't persist between sessions)
  • Up to 10 numbered bookmarks plus customizable homepage
  • Binary blob downloads (see "Downloads")
  • Limited support of ANSI terminal escape codes in Gophermap infolines (see "Does it have terminal emulation support for character styling?")


Kopher's controls were inspired by old WAP browsers and partially Opera Mini. Once you get used to them, navigation becomes blazingly fast.

  • Scrolling: Up/Down/Left/Right
  • Previous/next link: 2/5
  • Click on the link: Center
  • Enter address: Left Soft Key
  • Go back: 1 or Right Soft Key
  • Go forward: 3
  • Refresh: Call
  • Page start/end: 8/0
  • Line start/end: 7/9
  • Open the homepage: # *
  • Open a bookmark: # [num]
  • Save to the homepage: * *
  • Save to a bookmark: * [num]
  • Share the URL: * Call
  • Toggle light/dark theme: 4
  • Toggle line wrapping: 6
  • Version and page info: # #
  • Exit: End


For image files supported by KaiOS, Kopher prompts whether or not you want to just view or store them, and if you choose to store them, they are saved to your default gallery storage. All other types are downloaded directly to the root of your default storage (the storage you selected in KaiOS setttings as the default media location, be it internal or the SD card). Note that Kopher does not do any heuristics on how the downloads folder should be named, nor does it create any by itself. Different phones handle the download storage place differently and B2G doesn't have a specific designator for it, so just using the root is the safest and most cross-device way of saving the files.

Note that in most KaiOS phones the internal storage root isn't fully viewable with the stock file manager, so you might have to use MTP and/or third-party file managers like Explorer to see the files if this is the case with your device. For more consistent UX with downloads, please consider using an SD card as the default storage.

#Wait... no input fields in the UI?!

Exactly. No need to reinvent the wheel when the JS engine offers the prompt() method. You enter the starting address in the popup window, same way you enter search queries in the gopherholes.

For your convenience, only the current hole hostname is always displayed in the header bar, and the status bar with service messages or the current resource path is always displayed below. You can view the full URL/URI in the "Version and page info" popup accessed with # # combo.

#Does it have Unicode support?

Yes. In fact, UTF-8 is the only supported encoding. As ASCII is a subset of UTF-8, old ASCII-only resources will be displayed just fine as well.

#Does it have terminal emulation support for character styling?

As of April 2023, Kopher implements a subset of ANSI terminal escape codes for text styling purposes with the following limitations:

  • they are applied to the Gophermap information lines only (and detected and deleted everywhere else);
  • they only work within the single infoline or a block of sequential infolines and all styling gets reset when another entry type is encountered, even if the reset sequence isn't there;
  • only the basic 16-color palette is implemented (because these codes physically translate into corresponding data attributes);
  • beside the colors, the following text attributes are implemented: bold, italic, underline, blinking, inverse, hidden, strikethrough;
  • any unsupported escape sequences are automatically deleted from the rendered output.

All these limitations are intended to keep Kopher's codebase simple, and not likely to change in the foreseeable future.

#How does Kopher integrate with the rest of KaiOS?

It almost doesn't. But, whatever could be done without hacks, has been done since the version 0.0.6. First, you can share the current URL (in the gopher:// format) using Bluetooth/Messages/Email share menu (if you select Bluetooth or any other provider that requires blobs, it gets sent as a vCard 2.1 file with the N and URL fields set to the same value) by pressing * and Call key. Second, Kopher itself registers a view activity handler for every URL that starts with gopher:. If you just updated Kopher to version 0.0.6, you need to reboot your phone for this feature to start working. In the current state of KaiOS, gopher: URLs aren't picked up and translated into proper activities by the stock KaiOS browser or the window.open() call, but any other application that sends URLs to the view activity according to the spec should be able to open gopher:// URLs in Kopher.

#Can I use the hi01379.js library in non-KaiOS environments?

Yes, but you'll need to supply your own gopherRequest(resource, input, successCb, errorCb) function/method that performs the actual resource download over TCP. The success callback must always return a raw binary data string. See the js/transport.js file for the reference of how it's done for KaiOS (using mozTCPSocket API).

If you only need the Gophermap rendering functionality, you can provide a dummy function and only use the Hi01379.render() method. Note that the library generates links in its own internal and more efficient hi:[type]|[selector]|[host]|[port] URI format, where the fields are specified in the same order they appear in the Gophermap. It's up to the callers to convert these links to the standard gopher://[host]:[port]/[type][selector] URL scheme if they need to.

#What's the license on this?

Fully public domain.