OTPs fail in Tanzania mostly for avoidable reasons: the sender ID is not registered on every network (unregistered IDs have been blocked since 16 June 2025), the sender ID is too generic and was rejected, the number is formatted wrongly or belongs to a roaming visitor, or the app lets users hammer the resend button until codes arrive out of order. Fix the sender ID first, normalise numbers to +255 format, rate-limit resends and give users a fallback. This article goes through each cause, how to diagnose it and how to fix it, with a code sample.
Last reviewed: 27 October 2026
Start with the symptom
| What users report | Most likely cause | First check |
|---|---|---|
| No users on one network get codes | Sender ID not registered or approved on that network | Delivery reports filtered by network |
| Nobody gets codes since a certain date | Unregistered or changed sender ID being blocked | Sender ID status on every network |
| Some users never get codes | Wrong number format, inactive SIM, phone off | Number normalisation and DLR status |
| Codes arrive late or two at once | Resend spam, network congestion, phone out of coverage | Resend logs per number |
| Tourists and diaspora users fail | Foreign or roaming numbers, international routing | Country code of failing numbers |
| Code arrives but "invalid" | Expired code, older code used after resend | Expiry window and which code is checked |
Cause 1: unregistered sender ID
This is the big one. Since 16 June 2025, the main Tanzanian networks block messages from sender IDs that have not been registered with them. An app that was sending fine in May 2025 with an unregistered alphanumeric ID could stop reaching users overnight. Registration is per network, so an ID approved on Vodacom but still pending on Halotel will fail only for Halotel users, which looks like a random bug until you split delivery reports by network.
Fix: register your brand sender ID with Vodacom, Airtel, Yas and Halotel before launch, and keep it identical across networks. eSMS Africa handles the submissions; steps and fees are on the Tanzania sender ID page. While registration is pending, test on the eSMS default sender, which is already registered.
Cause 2: a generic or mismatched sender ID
Networks reject generic names such as OTP, VERIFY, INFO or SMS, and some ask for a sample message that names the brand. A sender ID that does not obviously match the company applying for it is more likely to be queried or refused.
Fix: use your app or company name, up to 11 characters with no spaces, and make the OTP template name the brand too:
- "PesaHub: nambari yako ya uthibitisho ni 482913. Usimpe mtu yeyote. Inaisha baada ya dakika 5."
- "PesaHub: your verification code is 482913. Do not share it with anyone. Expires in 5 minutes."
Putting the code early means it shows in the notification preview, and Android's SMS code autofill can pick it up.
Cause 3: number format
Tanzanian mobile numbers are written locally as 07XX XXX XXX or 06XX XXX XXX and internationally as +255 7XX XXX XXX. Users type every variation: with the leading zero, without it, with 255 but no plus, with spaces. Sending to "0712345678" without a country code, or to "+2550712345678" with the zero left in, fails.
Fix: normalise every number to E.164 (+2557XXXXXXXX or +2556XXXXXXXX) before you store it, and show users the country code in the input field. Validate length: a Tanzanian mobile number has nine digits after +255.
Cause 4: roaming tourists and foreign numbers
Tanzania recorded 2,294,495 international arrivals in 2025, according to TanzaniaInvest. Safari bookings, Zanzibar hotel apps, airlines and ride-hailing apps all verify visitors who keep their home SIM. A UK or German number is sent as international SMS to the home network, which then delivers to the roaming handset. That path is longer and the sender ID may display differently abroad.
Fix: allow international numbers with a country picker, do not hard-code +255, and offer a fallback for visitors, such as email verification or a voice call option where you have one. For foreign numbers, allow a slightly longer expiry window.
Cause 5: resend spam and race conditions
Impatient users tap "resend" five times in 20 seconds. Each tap creates a new code, the codes arrive in a burst, and the user types the first one they see, which is no longer valid. Meanwhile bots use the resend button to pump SMS to premium numbers at your expense.
Fix:
- Disable resend for 30 to 60 seconds and show a countdown.
- Limit attempts per number and per IP per hour.
- Either keep the same code valid across resends within the expiry window, or invalidate old codes clearly and tell the user to use the latest.
- Limit wrong guesses per code, then require a new one.
Cause 6: phone off, out of coverage or SIM inactive
Some failures are not fixable on your side. A phone switched off or out of coverage, for instance in a national park or on an upcountry bus, will receive the SMS when it reconnects if that happens within the network's retry window. Delivery reports will show these as pending or undelivered rather than failed at submission.
Fix: read delivery reports and show the user a useful message, such as "We sent the code to +255 7XX XXX 678. Check your number or try again in a minute", rather than a generic error. Our guide to receiving delivery reports explains the statuses.
Use a managed OTP instead of building your own
Most of the fixes above (code generation, expiry, retry limits, rate limiting and checking) are the same for every app. eSMS Verify does them for you: you call one endpoint to start a verification and one to check the code. Read the full eSMS Verify overview or the step-by-step OTP guide.
// Node.js 18+: start and check a verification with eSMS Verify
const BASE = "https://sms.esmsafrica.io";
const headers = {
"Authorization": "Bearer " + process.env.ESMS_API_KEY, // esms_live_... or esms_test_...
"Content-Type": "application/json"
};
// Normalise Tanzanian input to +255XXXXXXXXX
function toE164TZ(input) {
let n = input.replace(/[^\d+]/g, "");
if (n.startsWith("+")) return n;
if (n.startsWith("255")) return "+" + n;
if (n.startsWith("0")) return "+255" + n.slice(1);
return "+255" + n;
}
async function startVerification(phone) {
const res = await fetch(BASE + "/v1/verify/start", {
method: "POST",
headers,
body: JSON.stringify({ to: toE164TZ(phone), app_id: "vera_xxxxxxxx" })
});
return res.json(); // keep the verification_id for the check step
}
async function checkCode(verificationId, code) {
const res = await fetch(BASE + "/v1/verify/check", {
method: "POST",
headers,
body: JSON.stringify({ verification_id: verificationId, code })
});
return res.json();
}
With a test key the calls are simulated without charge, so you can test the full flow, including wrong codes and expiry, before switching to a live key. The OTP SMS page for Tanzania has country-specific notes and pricing.
A pre-launch OTP checklist for Tanzania
- Sender ID registered and approved on Vodacom, Airtel, Yas and Halotel.
- Template names the brand, puts the code first and warns against sharing, in Kiswahili and English.
- Numbers normalised to E.164, with a country picker for visitors.
- Resend cooldown, per-number and per-IP limits, and a cap on wrong guesses.
- Delivery reports read and turned into helpful user messages.
- A fallback path for users who cannot receive SMS.
- Monitoring split by network, so one network's failure is visible.
What it costs
OTP messages are billed per SMS at the Tanzania rate, TZS 18.2819 ($0.0069) on the basic tier. Resend limits and bot protection usually save more than any rate negotiation.
Frequently asked questions
Why do OTPs work on Vodacom but not on another network?
Your sender ID is probably approved on one network and pending or rejected on another. Split delivery reports by network to confirm, then check the sender ID status for each network.
Can I send OTPs from a numeric sender instead?
Brand sender IDs are the expected route in Tanzania, and generic or unregistered senders are blocked. Register your brand name rather than looking for a workaround that could stop working without notice.
Should my OTP be in Kiswahili?
Use the language the user selected in your app. For mass-market apps, Kiswahili is a safe default. Keep the code at the start of the message in either language.
How long should an OTP be valid?
Five to ten minutes suits most apps. Very short windows fail for users with weak coverage or roaming numbers. Limit wrong attempts rather than shortening expiry too far.
Do I need consent to send an OTP?
An OTP the user requested is a transactional message, not marketing. Do not reuse OTP numbers for promotions without separate consent, which the Personal Data Protection Act expects you to respect.
Sources
- TanzaniaInvest - Tanzania tourism arrivals and earnings 2025
- TCRA - Tanzania Communications Regulatory Authority
- eSMS Verify documentation
- Personal Data Protection Act, 2022 (TanzLII)
See how fintechs structure OTP and alerts on the fintech SMS page for Tanzania, then create a free account, grab a test key and run your first verification in minutes.


