suggested_key is a suggestion: commands.getAll() can hand you an
empty shortcut
You declare Alt+Shift+R in the manifest, the extension loads
without complaint, and the key does nothing. Nothing is broken. The shortcut was simply never
assigned, and the only place that says so is a field you probably never read.
8 September 2026 · measured on a shipped extension, 6 September 2026
1. What we actually saw
The manifest declares one command with a suggested_key of
Alt+Shift+R. On a freshly loaded profile we asked the browser what it had done
with it:
chrome.commands.getAll()
// [{ name: "read-toggle", description: "…", shortcut: "" }, …]
The command exists. Its shortcut is the empty string. There was no exception,
no console warning and no entry anywhere in the extension's own logs. The word in the
manifest key is suggested, and the browser is within its rights to decline.
2. The failure is invisible from inside the extension
chrome.commands.onCommand is an event. When the key is unassigned, the event
never fires — which is byte-for-byte what a user who has not pressed the key looks
like. There is no callback, no error, and no state to inspect after the fact. If your only
evidence is "our shortcut handler is not running," you cannot tell the two apart, and both
readings suggest completely different fixes.
The one field that distinguishes them is the shortcut string above, and it is
only true at the moment you ask: the user can assign or clear the key at any time, so a value
you read at install and cached is a value that can quietly go stale.
3. Your interface is the thing that lies
The real damage is not the missing key — a toolbar button still works. It is that
the shortcut has usually been copied by hand into three places that no longer agree with the
browser: the popup, the options page and the store listing. Each of them states
Alt+Shift+R as a fact, because at the time somebody wrote them it was a fact in
the manifest.
So the user reads a specific key combination in your own words, presses it, gets nothing, and concludes the extension is broken. That is a worse outcome than shipping no shortcut at all, and it is entirely self-inflicted: we told them something that the browser had already declined to do.
The fix is to stop printing the manifest. Read getAll() when you render the
surface, print the string that comes back, and when it is empty say so in the same breath as
where to fix it. For text you cannot generate at runtime — a store listing is written
once and read by strangers — the honest form is conditional: name the default and say
the browser does not always assign it.
4. You cannot assign it for them
There is no API that binds a shortcut. Assigning one is a user action on the browser's own
shortcuts page, and a page on the open web cannot link to a chrome:// URL
— the browser blocks the navigation — so instructions that live on your website
have to be something the reader can type or paste, not something they can click.
Which makes this a copy problem rather than a code problem, and copy problems do not surface in tests. It is worth saying plainly in the one place a confused user actually looks: the key may not be assigned, here is where to assign it.
How we know
This is one measurement, not a rule we derived: we loaded the extension, called
chrome.commands.getAll() from its own service worker, and read back an empty
shortcut for a command whose manifest asks for Alt+Shift+R. We are
deliberately not telling you when the browser declines — how many commands can
hold keys, or which combinations are taken — because we did not measure that, and a
confident rule with no measurement behind it is the thing that put the wrong key in our own
interface in the first place. What we changed on the evidence we have is our wording: the
listing on the store today names the default and then says the browser does not always assign
it.
Where this came from
It came out of Highlight Reader, a Chrome extension that reads a page aloud and highlights each sentence as it speaks. It is free on the Chrome Web Store, needs no account, and uses the voices the browser already ships. A paid add-on — word-level highlighting and higher-quality voices — is described here, and it is an add-on, not the extension.
The API and the code are the easy half. The half that costs days is the store: the slot cap on a new account, the listing text going read-only mid-review, the uninstall URL you cannot change after you ship. The ten that caught us — three of them in full, no signup.
More from the same build
Every one of these is something we hit while shipping the two extensions on this site, written up from our own code and measurements.
- Your extension’s keyboard shortcut dies when focus is inside an iframe
- A timeout watchdog will fire while the user has it paused
- A saved DOM Range does not survive a repaint, and nothing tells you
- chrome.i18n formats nothing, and getUILanguage() is not the locale your strings came from
- Reading a page aloud in Chrome and highlighting each sentence
- chrome.tts can fire start, stay silent, and never fire error