WhatsApp on a classic BlackBerry: a practical J2ME guide
Bring messaging to a classic BlackBerry with WhatsApp J2ME: host the Baileys bridge, build your client in the browser, and link your account by QR code.
There is something about typing a message on a BlackBerry keyboard that a touchscreen never quite replaced. If you still have a classic handset, WhatsApp J2ME is an experimental way to put that keyboard back to work.
The setup has two parts: whatsapp-j2me, the Java ME client on your phone, and baileys-j2me, the bridge you run on a computer or server. Your current Android phone or iPhone links the bridge to your WhatsApp account using a QR code. The BlackBerry talks to that bridge.
This is an independent project, with no affiliation with WhatsApp or Meta. It does not restore the official BlackBerry app. Compatibility and features depend on your handset, firmware, network, and the bridge; treat it as a retro computing experiment rather than your only way to receive messages.
Start with the right BlackBerry
This guide focuses on classic BlackBerry OS handsets capable of running Java ME applications, rather than BlackBerry 10 devices such as the Q10, Z10, or Passport. Do not assume that a model with a BlackBerry logo will install a MIDlet.
Before building anything, check that your particular device supports MIDP 2.0 / CLDC 1.1 applications, has working internet access, and can install a JAR/JAD pair. A working Wi-Fi connection is a useful first test. An old data plan or a browser that opens one page does not establish that Java applications can reach your server.
You will also need a current WhatsApp account on Android or iOS, a computer or Linux server that stays online, and an address your BlackBerry can reach. Symbian phones with the required Java ME support can follow the same general approach, but installation, permissions, certificates, and memory limits vary by model.
1. Host the Baileys J2ME bridge
The bridge handles the modern WhatsApp connection and exposes an API the old client can use. Keep it running whenever you want the BlackBerry to exchange messages.
Give your BlackBerry a server of its own
Want to keep the bridge running without leaving your home computer on? A DigitalOcean Droplet gives you a Linux server for this part of the setup. Create it first, then return here when it is ready to deploy the bridge.
You can create a DigitalOcean Droplet through my referral link.
I may receive referral credit for qualifying signups. Check the current pricing before creating your server; hosting is billed separately from my membership.
- Follow the link above and create your account, or sign in.
- Create a Droplet with a supported Ubuntu LTS image. Choose a region near you and a plan with enough memory for Rust compilation and the Node bridge; builds can need more memory than the running service.
- Add your SSH public key during creation and keep the private key on your computer. Give the server a recognizable name, such as
blackberry-bridge. - Configure the cloud firewall: allow SSH only from your administrative IP, and allow your authorized devices or network to reach the proxy on HTTPS. Keep port 8085 closed to the public internet.
- Wait for provisioning to finish and copy the Droplet's public IP. You can point your bridge hostname at this address when you configure DNS below.
Once your Droplet is ready, open a terminal on your computer and connect, replacing the example address with your Droplet's IP:
ssh root@YOUR_DROPLET_IPIf you configured another administrative user, use that username instead. Verify the server's SSH host key through a trusted channel on the first connection. Prepare an unprivileged service user and install the Linux prerequisites below before starting the bridge; the service later in this guide runs as baileys.
Already have a Linux server? Continue with the same deployment steps. The bridge does not require DigitalOcean.
Install and start the bridge
On a Linux machine with Git, Rust/Cargo, and a currently supported Node.js release compatible with the bridge dependencies installed:
git clone https://github.com/mateuslacorte/baileys-j2me.git
cd baileys-j2me
npm --prefix node-bridge ci
cargo build --release
PORT=8085 NODE_PATH="$(command -v node)" ./target/release/baileys-j2meRun this from the repository directory. The binary starts the Node companion using node-bridge/bridge.js, so copying only the Rust executable is insufficient. The project needs its Node dependencies and a writable sessions/ directory too. If compilation reports missing system libraries, install the development packages required by the reported crate for your distribution.
The server listens on all interfaces on port 8085 by default. Keep this port closed to the public internet and allow the reverse proxy to reach it locally. Configure the Nginx username and password below before connecting your phone.
For an initial local check, in another terminal on the server:
curl http://127.0.0.1:8085/api/device/setup-check/statusThis creates a test device session and should return a JSON status. It tests the Rust/Node bridge, not a completed WhatsApp login. Do not pair your account with this test ID; the app generates its own.
Keep it running after logout or reboot
For a persistent installation, place the repository at /opt/baileys-j2me, owned by a dedicated, unprivileged baileys user. Install Node and the build dependencies first, then install the bridge dependencies and build the binary there as that user. That user must be able to write to the repository's sessions/ directory.
Save this as /etc/systemd/system/baileys-j2me.service, adjusting the Node path to the output of command -v node:
[Unit]
Description=Baileys J2ME bridge
Wants=network-online.target
After=network-online.target
[Service]
Type=simple
User=baileys
WorkingDirectory=/opt/baileys-j2me
ExecStart=/opt/baileys-j2me/target/release/baileys-j2me
Environment=PORT=8085
Environment=NODE_PATH=/usr/bin/node
Restart=on-failure
RestartSec=5
UMask=0077
[Install]
WantedBy=multi-user.targetsudo systemctl daemon-reload
sudo systemctl enable --now baileys-j2me
sudo systemctl status baileys-j2me
sudo journalctl -u baileys-j2me -n 50 --no-pagerKeep sessions/ private. It contains account credentials and message data; it must never be served as website content or committed to Git. The bridge operator can access messages handled by the bridge, so use a server you control and trust.
Give the phone a reachable address
Use a hostname that resolves to your server. For access outside your LAN, configure DNS and the necessary router or firewall rules. Put a reverse proxy in front of the bridge, with HTTPS and a certificate your handset trusts.
Create credentials for the proxy first:
sudo apt install -y apache2-utils
sudo htpasswd -c /etc/nginx/baileys.htpasswd bridge-user
sudo chown root:www-data /etc/nginx/baileys.htpasswd
sudo chmod 640 /etc/nginx/baileys.htpasswdReplace bridge-user with your username and enter a password when prompted. Use printable ASCII characters and no colon in the username. Match the file group to your Nginx worker group (www-data on Debian/Ubuntu). To change a password or add a user later, omit -c so the existing file is preserved.
Inside an existing Nginx server block that already has a working TLS certificate, this location proxies the API at the domain root:
location / {
auth_basic "WhatsApp J2ME bridge";
auth_basic_user_file /etc/nginx/baileys.htpasswd;
proxy_set_header Authorization "";
proxy_pass http://127.0.0.1:8085/;
proxy_http_version 1.1;
proxy_buffering off;
proxy_read_timeout 90s;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}Apply your network access restrictions to this virtual host as well. Run sudo nginx -t before sudo systemctl reload nginx. This location includes Basic Auth; keep it inside your HTTPS virtual host and redirect HTTP API traffic to HTTPS.
With this layout, the client settings are host: your hostname; port: 443; protocol: HTTPS; API path: /. Check that curl -o /dev/null -w '%{http_code}\n' https://your-hostname/api/device/setup-check/status returns 401 without credentials. Then run curl --user bridge-user https://your-hostname/api/device/setup-check/status, enter the password when prompted, and confirm a 200 JSON response.
Old BlackBerry certificate stores and TLS implementations can be the difficult part. Check the phone's date and time, certificate trust chain, and negotiated TLS support. A certificate that works on your laptop may still fail on the handset. Some phones require an imported certificate in DER format. The bridge README covers legacy certificate and proxy scenarios; enabling obsolete TLS or weaker ciphers reduces security, so keep any necessary legacy endpoint isolated. Plain HTTP exposes the phone-to-bridge traffic and should be limited to a trusted, isolated test network.
2. Build WhatsApp J2ME for your server
The client needs the connection details of your bridge. A random JAR downloaded elsewhere may point at somebody else's server.
The WhatsApp J2ME source is available, and compiling it yourself remains an option. The manual route involves a legacy Java ME toolchain, bytecode preverification, and consistent JAR/JAD packaging, as well as the correct server settings. If your goal is to use the phone, that setup can take more time than the client itself.
I keep a WhatsApp J2ME compiler in my member area for this step. You enter your server details in the browser and compile an app configured for that address, without assembling the old development environment. Membership supports my independent projects and is required to compile; you can preview the connection settings before joining. The tool builds the phone client; you still host and maintain the bridge.
- Open the compiler and enter your hostname or IP address, without a URL scheme in the host field.
- Choose the port and protocol exposed by your proxy.
- Use
/as the API path for the root-level proxy above. A deployment under a subpath needs a matching proxy route and client path. - Choose the app language and enter the same API username and API password you created with
htpasswd. - Review the resulting endpoint, then sign in and activate membership to compile. Credentials are not saved in the browser draft; re-enter them after signing in.
- Download and extract the ZIP containing
WhatsApp.jar,WhatsApp.jad, andMANIFEST.MF.
Changing the bridge address or credentials later means generating and installing a new build. Credentials are embedded in the JAR, so keep the ZIP and installation files private. Use HTTPS for authenticated API calls.
3. Install on your BlackBerry
Keep the generated JAR and JAD together. On a compatible BlackBerry OS handset, try opening the JAD using the device browser from a location reachable by the phone. The JAD references the JAR, so keep their relative location intact and do not modify the JAR after compilation: the descriptor includes its byte size.
If you serve the files yourself, use text/vnd.sun.j2me.app-descriptor for .jad and application/java-archive for .jar. Keep installation downloads private, since custom builds contain your API credentials. Use a protected download directory and never publish the bridge repository or sessions/. Depending on the model and firmware, local installation may also be available; follow your handset's supported installation method. A JAR/JAD package does not guarantee that every BlackBerry will accept it.
Allow the app's network access when prompted. Corporate device policies, application permissions, APN settings, and network transport differences can prevent a connection even when installation succeeds. Test Wi-Fi first where supported, then investigate mobile data separately.
4. Link your WhatsApp account
Start the bridge, then open the installed app on the BlackBerry. Once it reaches the bridge, the app's pairing flow should display a QR code.
On the Android phone or iPhone that already has your account, open WhatsApp → Linked devices → Link a device and scan that QR code. Wait for the bridge to connect and the client to load chats, then send a short message to a trusted contact and check the reply.
The modern phone is used to authorize the linked session. This is not a separate SMS registration on the BlackBerry, and it does not require moving your number to the old handset. Existing history may be incomplete; start by checking newly sent and received text messages. Do not assume calls or every official app feature are supported just because a screen exists in the client.
If pairing expires, refresh the QR flow. If you retire the experiment, revoke the session from WhatsApp's linked-device settings.
When something does not work
- HTTP 401: confirm the compiled username/password match
htpasswd; rebuild after changing them. - No QR code: check the service logs, Node path, installed dependencies, and writable session directory. Confirm the phone's build points at the right host, port, protocol, and API path.
- Works on the computer, fails on the BlackBerry: check reachability from the phone's network, app permissions, date/time, certificate trust, and TLS compatibility.
- JAD installation fails: verify that the referenced JAR is reachable, its size matches the descriptor, and the device supports the app's Java ME profile.
- Connected but missing chats: wait for synchronization and test a new text message. A linked experimental client may not reproduce the full history or feature set.
- Stops when you close SSH: use the systemd service and check its working directory instead of launching the binary only in an interactive terminal.
The satisfying part is the first message typed on that physical keyboard. Once your bridge is reachable, configure your BlackBerry build in the member compiler and take the installation files to your phone.
Implementation references: whatsapp-j2me, baileys-j2me, and Baileys, the library used for the bridge's WhatsApp connection. These projects can change as the upstream protocol evolves.
Comments
Keep it useful — questions, corrections, and war stories welcome.
Loading comments…