If you build a bilingual WhatsApp agent by adding "respond in Urdu if the user writes in Urdu" to a system prompt, it will work in your tests and disappoint you in production.
The reason is that your tests are written by you, in clean Urdu script or clean English. Real customers write neither. They write this:
Assalam o alaikum, mujhe apki website development service ke bare mein poochna tha. Price kya hai?
That's Urdu, written in Latin characters, with an Arabic-origin greeting and two English nouns embedded in it. It is neither of the languages your bot was configured for, and it is how a very large share of Pakistani, Indian, and Gulf users actually type.
This is what building for these markets actually involves.
Roman Urdu is the default, not the exception
The most consequential thing to internalise: most Urdu-speaking users do not type in Urdu script. They type Urdu phonetically in Latin characters — Roman Urdu — because it's faster on a standard keyboard and it's what they've always done.
There's no standardised spelling. The same word appears many ways, and all are correct:
chahiye/chahiyay/chaheye/chahyenahi/nahin/nhi/nahekya/kia/kea
Any approach based on matching keywords or normalising spelling is doomed here — the variation is unbounded, and it's generational and regional. This is the strongest argument for using a language model rather than intent classification for these markets. Models handle Roman Urdu comprehension reasonably well because the training data is full of it. A rules engine cannot.
Test with real messages. Take actual customer conversations from your WhatsApp Business inbox, strip the identifying details, and use those as your test set. Messages you compose yourself will be cleaner than reality in a way that hides every interesting failure.
Code-switching is one sentence, two languages
Users don't switch languages between messages. They switch mid-sentence, and the pattern is consistent: the sentence structure is Urdu, the technical and commercial nouns are English.
Mujhe ek e-commerce website banwani hai with payment gateway integration, budget around 50k hai.
Nobody says the Urdu word for "payment gateway." It's English, always, and translating it would read as bizarre.
The practical rule for your system prompt: never translate domain terminology. Product names, technical terms, service names, and prices stay in English regardless of the surrounding language. An agent that helpfully renders "payment gateway" in formal Urdu sounds like a machine translation, which destroys the trust you're building.
Mirror the user's register rather than normalising it. If they write Roman Urdu with English nouns, reply in Roman Urdu with English nouns.
Choosing a script: mirror, don't decide
Three ways a user might write Urdu, and your reply should match whichever they chose:
| User writes | Reply in | Notes |
|---|---|---|
| Urdu script (اردو) | Urdu script | Right-to-left; needs correct rendering |
| Roman Urdu | Roman Urdu | The most common case by a wide margin |
| English | English | Even if you know they're a local customer |
The failure to avoid is replying in Nastaliq script to someone who wrote Roman Urdu. It's technically the "correct" language and it's the wrong answer — many Roman Urdu writers read the script slowly or not comfortably at all, particularly younger users. You've made your reply harder to read in the name of authenticity.
A short, explicit instruction handles this better than a long one:
Match the user's language AND script exactly.
If they write Roman Urdu (Urdu in Latin letters), reply in Roman Urdu.
If they write Urdu script, reply in Urdu script.
If they write English, reply in English.
Never translate product names, technical terms, or prices — keep those in English.
Do not correct the user's spelling or switch their script for them.That last line matters more than it looks. Models have a tendency to "improve" input by normalising it into formal script, which reads as a correction and is subtly rude.
The encoding problems that only appear in production
Database. Your columns need genuine full UTF-8. On MySQL specifically, utf8 is a three-byte encoding that cannot store four-byte characters — you need utf8mb4. The symptom is Urdu text that mostly works until an emoji or a rarer character truncates the field. PostgreSQL handles this correctly by default, which is one reason it's the easier choice here.
Character counting. Urdu strings and emoji break naive length checks. In JavaScript, String.length counts UTF-16 code units, so a message that looks like 40 characters may report far more and trip a validation limit you set for English. Count with [...str].length when you need actual character counts, and remember WhatsApp's own message limits are in characters, not bytes.
Model token costs are higher. Non-Latin scripts tokenise less efficiently — Urdu script consumes noticeably more tokens per unit of meaning than the same content in English. Roman Urdu sits in between. This affects both your cost per conversation and how quickly you approach a context limit. Set maxOutputTokens with the worst case in mind, not the English case.
Right-to-left rendering. Urdu script is RTL, and any interface where your team reads these conversations — your CRM, your dashboard — needs dir="auto" on the containers. Without it, mixed Urdu and English lines render with punctuation and numbers in visually scrambled positions. dir="auto" picks direction per element from the first strong character, which handles mixed content correctly. This is a five-minute fix that makes a support inbox usable.
Fonts. Urdu is traditionally set in Nastaliq, and system default fonts almost always render it in Naskh instead — technically readable, but it looks wrong to a native reader in the way Comic Sans looks wrong on a legal document. If Urdu script appears in your interface, load a proper Nastaliq face.
Message templates are per-language
A detail that catches teams late: WhatsApp message templates are approved per language. An approved English template does not cover its Urdu equivalent — that's a separate submission and a separate review.
Two consequences worth planning for. Approval times differ, so submit non-English templates first because they take longer. And you need the language code stored per contact, because sending a business-initiated message requires selecting the right template variant. Capture language preference at the point of first contact and persist it on the lead record.
What we'd tell you before you start
Building for these markets, in order of what actually caused us trouble:
- Collect real messages before writing the prompt. Your assumptions about how customers type will be wrong, and specifically will be too clean.
- Mirror, never normalise. Match script, register, and formality. Do not correct the user.
- Keep domain terms in English. Translating them is the fastest way to sound like a machine.
- Use
utf8mb4anddir="auto"from day one. Both are trivial upfront and irritating to retrofit. - Budget more tokens than the English case suggests.
- Have a native speaker read the output. Not a translator checking correctness — a native speaker checking whether it sounds like a person. Grammatically perfect Urdu that reads as stilted is worse than casual Roman Urdu that sounds natural.
That last point is the one no amount of engineering substitutes for. The gap between "correct" and "sounds right" is where these projects are won.
Building for a multilingual market?
We build WhatsApp AI agents for Urdu, English, and code-switched markets — including the encoding, template, and rendering details that only surface once real customers are typing. Talk to us about AI chatbot development.