McTaba Labs logo
Software EngineeringThe WhiteboardProjectsEventsMasterclassesWebinarsLearn
Book Call

500+ developers already in the community

Get answers, find accountability partners, and stay ahead

Join Discord →
McTaba Labs logo

Educating 1 million students in tech by 2030.

Programs

  • HighSchool Graduates Launchpad
  • AI & Business Automation
  • Corporate Training
  • McTaba Story & Mission
  • Full-Stack Curriculum
  • Course Pricing & Plans
  • Frequently Asked Questions

Resources

  • Join Discord Community
  • Tech Events in Nairobi
  • Masterclasses
  • Free Resources
  • Learn
  • Campus
  • Africa Tech Talent Report
  • Partner With Us
  • Start a Project
  • Our Work

Contact Us

  • 124 Manyani East Road, Lavington, Nairobi
  • +254727795603
  • Book a Discovery Call

Office Hours:

Mon-Fri: 9am - 2pm EAT

Sat: 10am - 12pm EAT

© 2027 McTaba Labs - A product of Edtech Industries. All rights reserved.

Privacy PolicyTerms of ServiceRefund Policy
  1. Learn
  2. The African Stack: Skills for This Market
  3. How USSD Apps Are Built: A Plain-Language Walkthrough
Bonaventure OgetoBy Bonaventure Ogeto|Updated July 20, 2026

How USSD Apps Are Built: A Plain-Language Walkthrough

A USSD app works by connecting a shortcode (the *XXX# number) to a server through a telecom carrier or gateway like Africa's Talking. When a user dials the code, the carrier forwards the request to your server. Your server reads what the user typed, decides which menu to show next, and sends back plain text. The server uses CON to keep the session open or END to close it.

In this article

  1. 1. The Three Pieces of Every USSD App
  2. 2. How a Session Flows, Step by Step
  3. 3. The Text Parameter: Your Navigation Map
  4. 4. What the Code Actually Looks Like
  5. 5. Menu Design: The Part That Is Harder Than Coding
  6. 6. Connecting Your USSD App to Real Systems

The Three Pieces of Every USSD App

Every USSD application has three parts, and once you understand them, the whole system clicks.

1. The shortcode. This is the number users dial. Something like *384*100# or *555#. You do not create this yourself. You get it from a telecom carrier (Safaricom, Airtel, Telkom) or more commonly from a USSD gateway provider like Africa's Talking. The shortcode is like a phone number for your application. When someone dials it, the network knows to route the request to your server.

2. The server. This is a web server you build and host. It has one job: receive requests from the USSD gateway and return text responses. When a user dials your shortcode, the gateway sends your server a message that says "this phone number just dialed your code, and here is what they typed so far." Your server decides what to show the user and sends back plain text.

3. The gateway. The gateway sits between the telecom network and your server. It translates the telecom protocol (which is complex and carrier-specific) into simple HTTP requests that your web server can understand. Africa's Talking is the most popular gateway for Kenyan developers. They handle all the telecom complexity. You just build a normal web endpoint.

Think of it like a restaurant. The shortcode is the restaurant's phone number. The gateway is the person who answers the phone and writes down orders. Your server is the kitchen that reads the order and prepares the food. The customer never talks to the kitchen directly. They talk to the person on the phone, who relays everything back and forth.

How a Session Flows, Step by Step

Let us walk through exactly what happens when a user dials your USSD code. We will use a simple example: a USSD app for a water delivery company in Nairobi.

Step 1: User dials *384*200#. The phone sends this code to the Safaricom network. Safaricom sees that this shortcode is registered with Africa's Talking and forwards the request. Africa's Talking translates it into an HTTP POST request and sends it to your server.

Step 2: Your server receives the first request. The POST request includes: the user's phone number (+254712345678), a session ID (unique for this session), the shortcode they dialed, and a text parameter that is empty (because the user has not typed anything yet, just dialed the code).

Step 3: Your server sends the main menu. Since text is empty, your code knows this is the start of a new session. You respond with:

CON Welcome to AquaDeliver
1. Order Water
2. Check Delivery Status
3. My Account

The CON prefix tells the system to keep the session open and wait for the user's response.

Step 4: User selects option 1. They type 1 and press send. Africa's Talking sends another POST request to your server. This time, text is "1".

Step 5: Your server shows the order menu. Your code checks that text equals "1" and responds with:

CON How many 20L jerricans?
1. One (KES 50)
2. Two (KES 90)
3. Five (KES 200)

Step 6: User selects option 2. They type 2. Africa's Talking sends another request. Now text is "1*2" (their first response, an asterisk separator, and their second response).

Step 7: Your server confirms and ends. Your code parses "1*2", knows the user wants to order two jerricans, and responds:

END Order placed: 2 jerricans (KES 90).
Delivery to your area within 2 hours.
You will receive an M-Pesa prompt shortly.

The END prefix closes the session. The user sees the confirmation and the session is done.

That is the entire flow. Your server reads the text parameter to figure out where the user is in the menu, then returns the appropriate text with either CON (continue) or END (finish).

Get weekly developer tips

Join 25,000+ developers. Practical guides, job tips, and new content — straight to your inbox.

No spam. Unsubscribe anytime.

The Text Parameter: Your Navigation Map

The text parameter is the key to understanding USSD development. It accumulates everything the user has typed during the session, with each response separated by an asterisk (*).

Here is what text looks like at each step of a session:

  • First screen (user just dialed): "" (empty string)
  • User types 1: "1"
  • User then types 2: "1*2"
  • User then types 0712345678: "1*2*0712345678"
  • User then types 1 to confirm: "1*2*0712345678*1"

Your server splits this string by the asterisk to figure out where the user is. The length of the resulting array tells you what "level" of the menu the user is on. The values tell you which options they picked.

For a basic menu, this is all you need. Split the text, check the length and values, and return the right response. For more complex apps with many branches, some developers use a state machine or a routing table instead of nested if-else blocks. But the principle is the same: read the text, decide the response.

One thing to watch for: the text parameter can contain anything the user types, not just menu numbers. If you ask "Enter your name" and the user types "John Kamau", that string goes into the text parameter, asterisk-separated from their previous inputs. Make sure your parsing handles free-text input correctly, especially if the user types an asterisk as part of their input (rare, but it happens).

What the Code Actually Looks Like

The server-side code for a USSD app is surprisingly small. Here is a complete, working example in Node.js with Express. This app lets users check water delivery rates and place orders.

const express = require('express');
const app = express();
app.use(express.urlencoded({ extended: false }));

app.post('/ussd', (req, res) => {
  const { sessionId, phoneNumber, text } = req.body;
  const inputs = text === '' ? [] : text.split('*');
  const level = inputs.length;
  let response = '';

  if (level === 0) {
    response = 'CON AquaDeliver Nairobi\n';
    response += '1. Order Water\n';
    response += '2. Check Rates\n';
    response += '3. Track Order';
  } else if (level === 1 && inputs[0] === '1') {
    response = 'CON How many 20L jerricans?\n';
    response += '1. One (KES 50)\n';
    response += '2. Two (KES 90)\n';
    response += '3. Five (KES 200)';
  } else if (level === 1 && inputs[0] === '2') {
    response = 'END Rates per 20L jerrican:\n';
    response += '1 jerrican: KES 50\n';
    response += '2 jerricans: KES 90\n';
    response += '5 jerricans: KES 200\n';
    response += 'Delivery free within Nairobi.';
  } else if (level === 2 && inputs[0] === '1') {
    const quantities = { '1': 1, '2': 2, '3': 5 };
    const prices = { '1': 50, '2': 90, '3': 200 };
    const qty = quantities[inputs[1]];
    const price = prices[inputs[1]];
    if (qty) {
      response = 'CON Order ' + qty + ' jerrican(s) for KES ' + price + '?\n';
      response += '1. Confirm\n';
      response += '2. Cancel';
    } else {
      response = 'END Invalid selection. Dial again to retry.';
    }
  } else if (level === 3 && inputs[0] === '1' && inputs[2] === '1') {
    response = 'END Order confirmed. You will receive an M-Pesa prompt shortly.';
    // Here you would trigger M-Pesa STK Push and save the order
  } else {
    response = 'END Invalid option. Dial *384*200# to try again.';
  }

  res.set('Content-Type', 'text/plain');
  res.send(response);
});

app.listen(3000, () => console.log('USSD server running on port 3000'));

That is under 50 lines. The entire application. No framework, no database (yet), no frontend build tools. Just a server that reads input and returns text. This is why USSD apps are one of the fastest backend projects you can build as a learning exercise.

In Python with Flask, the same logic is even shorter. In PHP, it is a single file. The language does not matter. The pattern is always: receive POST, parse text, return CON or END with your response.

Menu Design: The Part That Is Harder Than Coding

Writing the server code takes an afternoon. Designing a menu that users can actually follow takes much longer. Here are the constraints you are working with:

182 characters per screen. That is roughly what fits on one USSD display. Some phones show less. If your message is too long, it gets cut off without warning. Count characters during development. A menu with 6 options, each with a short label, easily pushes past this limit.

Tiny screens. Feature phones have small screens with basic fonts. A menu that looks fine in your code editor might be cramped and hard to read on a Nokia 105. Test on real hardware, not just the Africa's Talking simulator.

Non-technical users. Your users may include people who are not comfortable with technology. Menu labels need to be short, clear, and unambiguous. "Check Balance" is good. "View Account Summary and Transaction History" is too long and too complex.

Practical rules that help:

  • Keep the menu tree to 3 levels maximum. Deeper than that and users get lost.
  • Put the most popular option at number 1. If 80% of your users dial in to check their balance, make that the first option.
  • Add "0. Back" to sub-menus so users can correct mistakes without starting over.
  • Always confirm before taking action. "Send KES 500 to 0712345678? 1. Confirm 2. Cancel." Users on tiny keypads press wrong buttons more often than you think.
  • Keep labels bilingual if your audience needs it. "1. Tuma Pesa / Send Money" works and is what many Kenyan services do.

The best way to learn menu design is to study existing USSD services. Dial *334# (M-Pesa) and pay attention to how many options are on each screen, how deep the menu goes, and how confirmations are handled. Then try *247# (Equity) or *844# (KCB). Each has slightly different design choices. Notice what feels smooth and what feels frustrating. Those observations will teach you more about USSD UX than any tutorial.

Connecting Your USSD App to Real Systems

A menu that displays static text is a demo. A useful USSD app connects to databases, payment systems, and notification channels. Here is how the connections work in practice.

Database. When a user selects "Check Balance," your server queries your database using their phone number as the lookup key. The phone number comes in +254 format from Africa's Talking, but your database might store it as 0712 or 254712. Normalize the format before querying. This phone number normalization function will be one of the most used utilities in your codebase.

M-Pesa. When a user confirms a payment through your USSD menu, your server triggers an M-Pesa STK Push to their phone. The user sees the M-Pesa PIN prompt, enters their PIN, and the payment processes. Since the STK Push is asynchronous (the result comes via a callback to a separate URL), you end the USSD session immediately with "You will receive an M-Pesa prompt shortly" and handle the payment result separately.

SMS. USSD is good for input but limited for output. If you need to send the user a receipt, a reference number, or detailed information that does not fit in 182 characters, end the USSD session and trigger an SMS. Africa's Talking provides both USSD and SMS APIs, so you can send the SMS from the same server. This USSD-for-interaction, SMS-for-confirmation pattern is what M-Pesa itself uses.

Speed matters. If your server takes more than 2 seconds to respond (because of a slow database query or an external API call), the USSD session may time out. Keep your server fast. Cache frequently accessed data. If a database query might be slow, respond immediately with a "processing" message, end the session, and send the result via SMS when it is ready.

If you want hands-on experience building USSD and M-Pesa integrations, our Full-Stack Software and AI Engineering course (KES 120,000) covers the African Stack with real projects. You ship code that actually processes payments, not just sandbox exercises.

Key Takeaways

  • ✓A USSD app is a server that receives text input from a phone and returns text menus. The entire "frontend" is plain text displayed on the phone's dialer screen.
  • ✓The flow works like a conversation: user dials code, server sends menu, user picks option, server sends next menu. This repeats until the server sends an END response.
  • ✓Africa's Talking is the most popular USSD gateway for Kenyan developers. They handle the telecom side, and you write a simple web server endpoint.
  • ✓Menu design is the hardest part. You have 182 characters per screen, a 30-to-180-second timeout, and users who may be on tiny feature phone screens.

Frequently Asked Questions

What programming language do I need to build a USSD app?
Any language that can run a web server works. Node.js, Python (Flask or Django), PHP, Java, Ruby, Go. The USSD gateway sends HTTP POST requests and expects plain text responses. If you can build a simple API endpoint, you can build a USSD app. Most Kenyan developers use Node.js or Python because the Africa's Talking SDKs for those languages are well-maintained.
How do I test a USSD app without a real shortcode?
Africa's Talking provides a free sandbox with a test shortcode and a simulator. You register on their platform, set up a sandbox app, point it to your server URL (use ngrok to expose your local server), and test using their web-based USSD simulator. No real phone or shortcode needed during development.
How long does it take to build a basic USSD app?
A simple USSD menu with 3 to 5 features can be coded in a day. Setting up the Africa's Talking account and connecting it to your server takes another hour or two. The longer work is designing good menus, connecting to your database and payment systems, and testing thoroughly. End to end, a production-ready USSD application typically takes 1 to 2 weeks for a developer who has not built one before.
Can a USSD app handle many users at once?
Yes. Each USSD session is an independent HTTP request. A properly configured web server can handle hundreds or thousands of concurrent sessions. The bottleneck is usually your database or external API calls, not the USSD handling itself. Use connection pooling for your database and keep your response logic fast. If you expect high traffic, load test before going live.

Learn M-Pesa Integration

KES 9,999

Master Daraja API, STK Push, C2B, B2C, and callback handling. Build a real payment flow from scratch. 10 modules, 57 lessons.

Enrol in M-Pesa Integration

Not ready? Create Free Account

Keep reading

What Is USSD and Why Do Kenyan Businesses Still Pay for It?

Every time you dial *144# to check your M-Pesa balance, you are using USSD. This protocol runs without internet, works on any phone with a SIM card, and processes billions of shillings daily. Here is why Kenyan businesses still spend money on it in 2026.

Read more

Building for the Feature Phone: The Market Nairobi Devs Ignore

While Nairobi developers chase the latest React framework, millions of Kenyans access services on phones that cannot install apps. Feature phone users are an underserved market with real money and real problems. Here is how to build for them.

Read more

Building a USSD App in Kenya From Scratch

USSD works without internet, runs on any phone, and reaches every Kenyan with a SIM card. This guide walks you through building a USSD application from scratch using Africa's Talking, covering session management, menu design, and deployment.

Read more

Explore related topics

M-Pesa & African Stack

M-Pesa Daraja API tutorials, USSD development, and WhatsApp Business API guides. The African Stack that global bootcamps do not teach.

Learning to Code

Roadmaps, language guides, and practical advice for learning to code and launching a programming career.

Breaking Into Tech

Practical, no-nonsense guides for anyone looking to start or change their career in tech. From choosing your first language to acing interviews.

Bonaventure Ogeto

Bonaventure Ogeto

Founder, McTaba Labs

Bonaventure is the founder of McTaba Labs, a coding bootcamp in Nairobi, Kenya. He has spent years building products for the African market and mentoring the next generation of developers across the continent.