DEV Community

Simple Memo
Simple Memo

Posted on Originally published at simplememofast.com

iOS 26 didn't kill custom vocabulary — you're adding it to the wrong module

This is a condensed version. The full write-up — the module decision table, the customized language-model option, troubleshooting, and FAQ — lives on the full iOS 26 SpeechAnalyzer custom-vocabulary guide, and the runnable live-mic sample is on GitHub (MIT).

The most common thing I've heard since I wrote up wiring iOS 26's SpeechAnalyzer to a live mic is some version of: "nice, but the new Speech framework dropped custom vocabulary, so it's useless for anything with proper nouns."

It's half true, and the false half cost me an afternoon. Here's the whole picture.

Where the myth comes from

On SFSpeechRecognizer, biasing toward known terms was one property: contextualStrings. The new stack still has a contextual-strings concept — the trap is where it lives. Reach for the module most tutorials start with, SpeechTranscriber (the long-form workhorse), wire hints to it, and it compiles and changes nothing. Your proper nouns still come out wrong. That silent no-op is where "there is no custom vocabulary" is born.

The strings didn't disappear. They moved.

The mental model: it's a modular framework now

iOS 26 didn't ship one new recognizer — it shipped a small kit you compose under a SpeechAnalyzer session:

  • SpeechTranscriber — long-form, low-overhead. Meetings, lectures, long memos. Tuned for throughput, not biasing.
  • DictationTranscriber — short-form dictation. Adds punctuation and accepts contextual hints.
  • SpeechDetector — voice-activity detection alongside a transcriber.

Custom vocabulary is a property of the dictation path, not the long-form one.

The part that actually biases recognition

// Short-form path: DictationTranscriber adds punctuation and accepts hints.
let dictation = DictationTranscriber(locale: locale)   // configure options as your build requires
let analyzer  = SpeechAnalyzer(modules: [dictation])

// The lines that actually move recognition toward your terms:
let context = AnalysisContext()
context.contextualStrings[.general] = ["Obsidian", "SwiftData", "TestFlight"]
try await analyzer.setContext(context)
Enter fullscreen mode Exit fullscreen mode

Three things I wish were in bold:

  1. setContext(_:) replaces the whole context — it's not additive. A second call wipes the first. Merge before you set.
  2. Soft ceiling: brief phrases, ~100 across tags. Not your whole glossary — the terms recognition gets wrong most.
  3. Hints bias, they don't guarantee. Names acoustically close to common words still flip.

DictationTranscriber also has a heavier customized language-model hint if phrase hints aren't enough — test it against your real terms.

The decision table I wish I'd had on day one

Your need Module Custom vocabulary?
Short dictation with domain terms DictationTranscriber + contextualStrings Yes — phrase hints
Long-form, no special vocabulary SpeechTranscriber Not the point of this module
Long-form and vocabulary-sensitive Neither new module biases; stay on SFSpeechRecognizer + contextualStrings for now
Just need voice-activity detection SpeechDetector N/A

That third row is the honest one: "new API" doesn't have to mean "migrate everything."

What I'd tell myself before the afternoon I lost

  • If proper nouns aren't landing, check which module got the hints before concluding the feature is missing. 90% of the time, that's it.
  • setContext is a replace — the "hints randomly stopped working" bug is usually a second call clobbering the first.
  • Test the exact words + locale on a device. Behavior isn't uniform across languages; publish device + OS + locale next to any claim.

If you've wired DictationTranscriber with contextualStrings for real proper nouns, I want one datapoint: did it measurably move recognition, or did the hard names still slip? That's the number I can't get from the docs.


Further reading: the full guide — module decision table, the customized language-model option, and the primary Apple-doc sources — is here, the live-mic pipeline is written up in the SpeechAnalyzer live-mic guide, and the MIT sample is on GitHub.

I'm a solo iOS developer building Simple Memo. I write here every few days about the unglamorous parts of shipping alone — usually when an Apple API surprises me.

Top comments (0)