# mcp-server-serp-title-width
Check whether Chinese, Japanese and Korean page titles fit in Google search
results, measured by **rendered pixel width** instead of character count.
Ships as an MCP server (for AI agents) and a CLI (for builds and CI).
Documentation and background: [adsandcode.com/en/open-source/serp-title-width](https://adsandcode.com/en/open-source/serp-title-width/)
## The problem
Site auditors and SEO plugins usually judge title length by counting
characters, with limits around 60. That rule of thumb comes from Latin text.
In the font Google uses for result titles, a CJK ideograph, a kana or a Hangul
syllable is 22px wide, roughly twice an average Latin letter. Sixty of them
come to 1320px, about twice the 652px desktop result column. A character-count
check passes CJK titles that Google will cut in half.
Google says only that the title link is truncated as needed; its documentation
gives no length in characters or pixels:
> "the title link is truncated in Google Search results as needed"
> ([Google Search Central, "Influencing your title links in search results"](https://developers.google.com/search/docs/appearance/title-link))
So the width has to be measured.
## The model
Measured on **2026-09-18** on google.com with the **zh-TW** (Traditional
Chinese, Taiwan) interface, **Chrome on Windows**, by reading the computed style
of a result title and measuring glyph advances with a canvas in the same page.
| Item | Value |
|---|---|
| Result title font | Arial 22px, line-height 28px |
| Desktop result column | 652px, the same at 1366px and 1920px viewport widths |
| Desktop truncation | done by Google's server (text cut, `...` appended), not by CSS |
| Mobile | two lines, 343px per line |
| Full-width character | 22.0px (1em). Full width means East Asian Width W or F ([UAX #11](https://www.unicode.org/reports/tr11/)): ideographs, kana, Hangul, full-width punctuation, most emoji |
| Printable ASCII (U+0020-U+007E) | Arial's own advance widths, all 95 characters: for example `W` 20.76px, `O` 17.11px, `A` 14.67px, digits 12.24px, `i` 4.89px, space 6.11px |
| Other half-width characters | 12.2px (estimate, not measured) |
| Zero-width characters | 0px: U+200B-U+200D, U+2060, U+FEFF, variation selectors, emoji skin-tone modifiers |
| Emoji sequences | each grapheme cluster counts once: a family emoji, a flag or a letter with combining accents is one character |
Thresholds:
| Tier | Width | Result | Why |
|---|---|---|---|
| `safe` | up to 572px (26 full-width characters) | pass | Conservative line. Leaves room for narrow screens and for differences between your `
` and the title Google displays |
| `long` | over 572px | warning | Over the conservative line, below the edge zone |
| `edge` | over 630px | **fail** | Near the measured single-line limit on desktop |
| `cut` | over 648px | **fail** | Wider than the desktop column: desktop results truncate it |
A digit costs about 0.56 of a full-width character, so "2026" takes the
space of 2.2 ideographs. Capital letters are much wider than digits: an
all-caps product name can push a title over the line that a character count,
or a model that treats every Latin letter alike, says it fits.
The ASCII widths come from the font file (Arial Version 7.01 on Windows), in
font units, measured with `scripts/measure-arial.py` and cross-checked three
ways: Pillow at 2048px, the font's advance-width table read with fontTools,
and `measureText()` on a Chrome canvas set to `22px arial`. All 95 agree to
within 0.0001px.
### Re-measuring
If Google changes the title font size, every number above is wrong. Open a
google.com results page in the interface language you care about and run this
in the browser console:
```js
(() => { const h = document.querySelector('a h3'), s = getComputedStyle(h);
const c = document.createElement('canvas').getContext('2d');
c.font = s.fontSize + ' ' + s.fontFamily;
return { font: s.fontSize + ' ' + s.fontFamily,
col: h.closest('div[data-hveid],div').getBoundingClientRect().width,
cjk: c.measureText('貓').width, digit: c.measureText('0').width }; })()
```
If `cjk` is no longer 22, update `EM` and the thresholds in `src/width.ts`.
If the font changes, regenerate the ASCII table with
`python scripts/measure-arial.py path/to/font.ttf`. Do not measure with
Pillow at 22px directly: hinting rounds each advance to a whole pixel
(`W` becomes 21), while browsers use the unhinted widths.
## Install
Requires Node.js 18 or later. No API keys, no network access.
### MCP server
```json
{
"mcpServers": {
"serp-title-width": { "command": "npx", "args": ["-y", "mcp-server-serp-title-width"] }
}
}
```
### CLI
```sh
npx -y -p mcp-server-serp-title-width serp-title-width ./public
```
or install it once with `npm install -g mcp-server-serp-title-width` and run
`serp-title-width`.
## CLI usage
```
serp-title-width ... check in .html/.htm files (directories are recursive)
serp-title-width --titles "t1" "t2" ... check title strings
serp-title-width ... --json machine-readable output
serp-title-width --selftest run the ruler's positive and negative controls (use alone)
```
Example:
```
$ serp-title-width --titles "家常料理食譜站|滷肉飯做法・便當菜色・120道快速晚餐" \
"旗艦手機開箱|SAMSUNG GALAXY S26 ULTRA VS GOOGLE PIXEL" "京都三天兩夜行程"
Checked 3 title(s). Safe <= 572px / edge > 630px / cut > 648px (Arial 22px, measured 2026-09-18).
------------------------------------------------------------------------------
[FAIL] (input 2)
旗艦手機開箱|SAMSUNG GALAXY S26 ULTRA VS GOOGLE PIXEL
688.3px / 31.3 full-width characters / cut
[FAIL] Cut: 688px (31.3 full-width characters), 40px over the 648px line. Desktop results will truncate it.
[warn] Keyword zone (text before the first ?:、,) is 688px, wider than the 343px first line on mobile, so the line breaks inside it.
[warn] (input 1)
家常料理食譜站|滷肉飯做法・便當菜色・120道快速晚餐
564.7px / 25.7 full-width characters / safe
[warn] Keyword zone (text before the first ?:、,) is 565px, wider than the 343px first line on mobile, so the line breaks inside it.
[ok] (input 3)
京都三天兩夜行程
176.0px / 8.0 full-width characters / safe
------------------------------------------------------------------------------
Passed 2 / must fix 1
```
The second title is 47 characters, under a typical 60-character limit, and
688px wide. When scanning files, only titles with a finding are listed, each
with its path under the folder you gave. Check a whole site at once so
boilerplate tails across pages are detected.
What is read from disk:
- A directory is searched recursively for `.html` and `.htm` files.
`node_modules` and anything starting with `.` (such as `.git`) are skipped,
and symbolic links to folders are not followed.
- A file named explicitly is read whatever its extension, so
`serp-title-width page.php.txt` works.
- A scan stops with exit code 2 after 20,000 HTML files, which usually means
the path is not a site's build output.
- Only the `` in the document head counts. Titles inside comments,
`