ASO in 10 locales without paid tools, and a script that keeps it honest
How I wrote native App Store keywords for ten locales with no paid ASO tool, and a small Python check that rejects wasted or risky words before I paste them.

On this page
Most of my apps ship in ten languages: English, Vietnamese, Japanese, German, French, Spanish, Portuguese, Korean, Chinese and Italian. For a long time the App Store metadata for those locales was an afterthought: translate the English name, let the keyword field drift, move on.
On 1 October 2026 I did a proper ASO pass on all seven apps in one day: Stampzy, Talkzy, Baton, Minivid, Ringsy, Lockboxy and Linkeeper. No paid ASO tool, no keyword-volume subscription. What I had instead was a repeatable method, one JSON file per locale, and a check script per repo that refuses to let me paste a wasted or risky keyword into App Store Connect.
Everything below comes from the docs/app-store/aso-2026-10.md file each app repo now carries.
The three fields Apple actually indexes
For search, the fields that matter are the name (30 characters), the subtitle (30) and the hidden keyword field (100). Apple indexes them together and combines words across them. Two practical rules follow:
- A word should appear in only one of the three fields. Repeating "camera" in the keywords when it is already in the name buys nothing and costs seven characters.
- You do not need whole phrases in the keyword field. If the subtitle has one half of a phrase, the keyword field only needs the other half.
The second rule matters a lot in Vietnamese, where matching happens per syllable. Stampzy's Vietnamese subtitle is "Chụp ảnh định vị, chấm công". Because công is already there, "công trình" (construction site) is covered by the single keyword trình. That is four characters instead of ten, and in a 100-character field that adds up.

The promotional text (170 characters) and the description are not indexed, so I treat them as conversion copy. Baton's partner sharing moved from the subtitle to the promotional text: it helps people decide, but almost nobody searches for "shared".
Research without a paid tool
Paid ASO tools sell search-volume estimates. I did without them and wrote that down. The docs say "no paid ASO tool was used" and label demand as qualitative: high, mid or low.
The signals I used instead:
- The public iTunes Search API. A query like
itunes.apple.com/search?country=vn&entity=software&term=…shows which apps rank for a term in a given storefront. If five of the top eight results carry the exact phrase in their title, the term has demand and competition. For Talkzy I also noted rating counts, because that shows how entrenched the top results are. - Native articles and how-to posts. For Vietnamese I read the how-to articles on local tech sites. That is how "chụp ảnh có ngày giờ" (photos with date and time) and "camera chấm công" (attendance camera) ended up in Stampzy's name and subtitle.
- Writing per language, not translating. The Talkzy doc says it directly: "Keywords written per language, not translated from English." Japanese creators say カンペ for a teleprompter script, German parents search "Stillen", Korean users type 보안폴더 for a secure folder. A translated English keyword list misses all of these.
It also turned up gaps. Since the 2025 province merger, Vietnamese people search for their new address ("địa chỉ mới", "sáp nhập"), and no camera app targets those words. Stampzy prints the new-structure address, so both went in.
The docs end with the same caveat: this is a ranked list of hypotheses, to be re-checked against Apple Search Ads popularity or App Store Connect search-term data once there is real traffic.
Words I removed on purpose
A good ASO pass removes words as well as adding them:
- Competitor brands. Stampzy's old Vietnamese keywords included a competitor's app name. Minivid's lists had messaging-app names. Both are gone. Under guideline 2.3.7, someone else's trademark in your metadata is a rejection waiting to happen.
- Price and "free". Talkzy was already rejected once under 2.3.7 for "Free" wording on its screenshots. Since then, no app puts a price, "free", "miễn phí", 無料, 免费 or 무료 in the name, subtitle or keywords, and neither does any superlative like "best". Pricing stays in the description, where the subscription terms have to be anyway.
- Claims the app cannot back. In Japanese, Stampzy dropped 黒板, because in Japan it suggests an electronic construction blackboard that meets an industry standard, and Stampzy is not that. It also dropped 証拠 (evidence) in Japanese and 证明 in Chinese. A timestamped photo is the photographer's own record, not proof.
Every claim in the new copy was checked against src/ first, in a table mapping claim to code.
The check script
Six of the seven apps share one layout: docs/app-store/locales/<locale>.json with name, subtitle, keywords, promo and description (Lockboxy keeps its listings in Markdown). Next to it sits a Python script with no dependencies (Stampzy's docs/app-store/check_aso.py, Talkzy's tools/app-store/check_metadata.py, and similar ones in the other repos). It exits with code 1 on any problem.

The core, trimmed:
LIMITS = {"name": 30, "subtitle": 30, "keywords": 100,
"promo": 170, "description": 4000}
def check(loc, d):
errs = [f"{k} is {len(d[k])} chars" for k, lim in LIMITS.items()
if len(d[k]) > lim]
if ", " in d["keywords"]:
errs.append("space after a comma in keywords")
head = words(d["name"] + " " + d["subtitle"], loc)
for kw in d["keywords"].split(","):
if words(kw, loc) & head:
errs.append(f"keyword {kw!r} repeats a name/subtitle word")
# + banned words (free, best, prices), competitor names, NFC
return errsThe details that took more than one try:
- Space after a comma.
a, bwastes one character per keyword. - NFC normalisation. Vietnamese text can store "ộ" as one code point or as a base letter plus combining marks. App Store Connect counts NFC code points, so a decomposed string looks longer than it is and the count is off. The script rejects anything that is not NFC.
- Korean particles. Korean attaches particles to nouns (
사진에), so the word splitter strips common trailing particles before it compares words. - Japanese and Chinese have no spaces. Splitting on spaces finds nothing there. For ja and zh, the Stampzy script flags a keyword that sits inside a name or subtitle segment, or that shares any two-character Han run with one. That is the overlap that got
水印相机dropped: its words were already in the Chinese name. - Per-app rules. Talkzy's script also requires the EULA line in every description. Lockboxy runs a second validator with an extra word list in every language, so the listing keeps the wording it was approved with: "an optional opening screen".
Here is a real run against Stampzy's locales, with the English keywords broken on purpose:
ok de: name=27 subtitle=30 keywords=95 promo=167 description=3316
FAIL en: name=29 subtitle=30 keywords=93 promo=162 description=3251
- space after a comma in keywords
- banned word 'free' in keywords
- keyword 'camera' repeats name/subtitle word(s) ['camera']
...
ok vi: name=28 subtitle=27 keywords=100 promo=167 description=3127The counts help even when everything passes: Baton's CJK keyword fields used only 56 to 68 of 100 characters, and now use 81 to 90.
One locale, before and after
Stampzy's Vietnamese listing shows the whole method in one example.
| Before | After | |
|---|---|---|
| Subtitle | Đóng dấu thời gian, địa chỉ | Chụp ảnh định vị, chấm công |
| Keywords | 90 characters, including a competitor's brand | 100 characters: timestamp, dấu thời gian, tọa độ, địa chỉ mới, sáp nhập, xã, tỉnh, trình, nghiệm thu, giao hàng, âm lịch, excel |
The subtitle now carries the two biggest Vietnamese intents. "Đóng dấu thời gian" moved into the keywords as dấu thời gian. The brand is gone, and the freed characters went to the merger-address wedge, the lunar date and Excel timesheets, all features the app actually ships. You can see the result on stampzy.io.vn.
Not every app got ten locales: Linkeeper's listing has only Vietnamese and English localizations, so that pass rewrote those two.
Custom product pages are the next layer
Keywords decide whether you show up. Custom product pages (CPPs) decide what someone sees after tapping an ad aimed at one specific intent. Lockboxy, Linkeeper and Ringsy each got a docs/app-store/cpp-2026-10.md that drafts three CPPs, one per search intent. Each has its own screenshots, promotional text and an ad URL template with the ppid App Store Connect assigns.
The same rules apply: no CPP frame shows the paywall or a price. Captions reuse the already-vetted screenshot lines. Ringsy skipped an alarm-tone CPP because the only alarm screenshot was an iPad capture, and an iPad frame in an iPhone slot would misrepresent the app. These are drafts for now: nothing has been created in App Store Connect yet.
Takeaways
- Treat name, subtitle and keywords as one 160-character budget where every word counts once.
- You can do useful research without paid tools: the public iTunes Search API, native articles and an honest "demand is qualitative" label.
- Write keywords natively per language, down to Vietnamese syllables and Korean particles.
- Put the rules in a script that exits 1 and run it before you paste into App Store Connect. Stray spaces, repeats and a competitor's brand all fail it on the spot.
The landing pages are the other half of discovery. I wrote that up in SEO and GEO for app landing pages. All seven apps are on apps.vanthuongdao.id.vn.
Related posts


