Invisible Character Detector
Two strings look identical, but VLOOKUP says they do not match. The import says
"missing header" for a column that is clearly there. Paste the text and see what is actually in
it.
🔒 Your text never leaves your browser.
Why "identical" strings do not match
Text carries passengers. A product title copied from a supplier's web page can contain a zero-width space in the middle of a word. A CSV saved by Excel starts with a byte-order mark that glues itself to the first column name. Word turns your apostrophes into curly ones and your hyphens into en dashes. None of it is visible — all of it changes the bytes.
The consequences are the bugs you have already met:
- "Missing header: Title" — the BOM made the first column name
Title - VLOOKUP / exact match fails — a non-breaking space where you expect a normal one
- Duplicate products — two SKUs that differ only by an invisible character
- Illegal quoting on import — smart quotes inside an unquoted CSV field
- Byte limits exceeded for no reason — invisible characters still cost bytes
Not everything invisible should be deleted
A zero-width joiner in the middle of an emoji sequence is what makes the family emoji a single picture rather than three. Removing it corrupts the emoji. This tool reports those characters but leaves them alone when cleaning, and tells you which ones it kept and why — a blanket "strip all invisible characters" regex does not.
Characters this tool identifies (37 named, plus all full-width forms and control characters)
Zero-width characters
U+200B ZERO WIDTH SPACE
Where it comes from: Copied from web pages, or inserted by CMS editors as a line-break hint.
What it breaks: Splits a word invisibly. Exact-match lookups fail and search engines index a different string than the one you see.
Cleaning: deleted
U+200C ZERO WIDTH NON-JOINER
Where it comes from: Arabic, Persian and Indic text, where it controls letter shaping.
What it breaks: Meaningful in those scripts, but a stray one in Latin text breaks exact matching.
Cleaning: deleted
U+200D ZERO WIDTH JOINER
Where it comes from: Emoji sequences (family and profession emoji) and Indic scripts.
What it breaks: Removing it from an emoji sequence splits that emoji into several separate pictures.
Cleaning: left as-is (removing it could change meaning)
U+2060 WORD JOINER
Where it comes from: Typesetting tools preventing a line break at that position.
What it breaks: Invisible, but counts toward character and byte limits and breaks exact matching.
Cleaning: deleted
Byte-order mark
U+FEFF ZERO WIDTH NO-BREAK SPACE (byte-order mark)
Where it comes from: A byte-order mark left at the start of a UTF-8 file, usually by Excel or Notepad.
What it breaks: Attaches to the first column name, so the header "id" never matches "id" — the classic cause of "missing header" import errors.
Cleaning: deleted
Look-alike spaces
U+00A0 NO-BREAK SPACE
Where it comes from: Word, Google Docs and web pages ( ) — inserted automatically around units and after short words.
What it breaks: Looks exactly like a normal space but is a different character, so trimming and splitting on " " both miss it.
Cleaning: replaced with " "
U+202F NARROW NO-BREAK SPACE
Where it comes from: French typography and some spreadsheet locales, where it is the thousands separator.
What it breaks: Invisibly different from a normal space; breaks numeric parsing and matching.
Cleaning: replaced with " "
U+3000 IDEOGRAPHIC SPACE
Where it comes from: CJK input methods — the full-width space.
What it breaks: Twice as wide as a normal space, and not removed by trim() in some tools.
Cleaning: replaced with " "
U+2007 FIGURE SPACE
Where it comes from: Numeric tables where digits must align.
What it breaks: Not a normal space; breaks number parsing.
Cleaning: replaced with " "
U+2009 THIN SPACE
Where it comes from: Typesetting and PDF text extraction.
What it breaks: Not a normal space; breaks splitting and matching.
Cleaning: replaced with " "
Smart quotes
U+2018 LEFT SINGLE QUOTATION MARK
Where it comes from: Word and Google Docs autocorrect.
What it breaks: Breaks CSV quoting and code that expects a straight apostrophe.
Cleaning: replaced with "'"
U+2019 RIGHT SINGLE QUOTATION MARK
Where it comes from: Word and Google Docs autocorrect — the "smart apostrophe".
What it breaks: Breaks CSV quoting and exact matching on names containing apostrophes.
Cleaning: replaced with "'"
U+201C LEFT DOUBLE QUOTATION MARK
Where it comes from: Word and Google Docs autocorrect.
What it breaks: Not a CSV quote character, so quoting fails in ways that are hard to trace.
Cleaning: replaced with """
U+201D RIGHT DOUBLE QUOTATION MARK
Where it comes from: Word and Google Docs autocorrect.
What it breaks: Not a CSV quote character, so quoting fails in ways that are hard to trace.
Cleaning: replaced with """
Look-alike dashes
U+2013 EN DASH
Where it comes from: Word autocorrect turning "1-2" into "1–2".
What it breaks: Not a hyphen — SKU and range matching fails.
Cleaning: replaced with "-"
U+2014 EM DASH
Where it comes from: Word autocorrect turning "--" into "—".
What it breaks: Not a hyphen; breaks identifier matching.
Cleaning: replaced with "-"
U+2212 MINUS SIGN
Where it comes from: Spreadsheets and mathematical typesetting.
What it breaks: Looks like a hyphen-minus but is a different character; breaks numeric parsing.
Cleaning: replaced with "-"
U+00AD SOFT HYPHEN
Where it comes from: Word processors marking where a word may be hyphenated.
What it breaks: Invisible until the text wraps, then a hyphen appears from nowhere. Breaks exact matching in the meantime.
Cleaning: deleted
Exotic line breaks
U+0085 NEXT LINE (NEL)
Where it comes from: Mainframe and legacy EBCDIC exports.
What it breaks: Treated as a line break by some parsers and not others, so rows split unpredictably.
Cleaning: replaced with " "
U+2028 LINE SEPARATOR
Where it comes from: Shift+Enter in some editors, and JSON copied out of JavaScript.
What it breaks: Breaks a CSV row in half in some parsers and is invisible in others.
Cleaning: replaced with " "
U+2029 PARAGRAPH SEPARATOR
Where it comes from: Word and rich-text conversion.
What it breaks: Same as the line separator — unpredictable row splitting.
Cleaning: replaced with " "
Bidirectional controls
U+202A LEFT-TO-RIGHT EMBEDDING
Where it comes from: Mixed Arabic/Hebrew and Latin text.
What it breaks: Invisible, but makes displayed text differ from stored text. Must be closed by U+202C.
Cleaning: deleted
U+202B RIGHT-TO-LEFT EMBEDDING
Where it comes from: Mixed Arabic/Hebrew and Latin text.
What it breaks: Invisible, but makes displayed text differ from stored text. Must be closed by U+202C.
Cleaning: deleted
U+202C POP DIRECTIONAL FORMATTING
Where it comes from: Written by editors and libraries that emit bidirectional text, to close an embedding or override they opened.
What it breaks: Harmless on its own, but one too many means an embedding was closed that was never opened.
Cleaning: deleted
U+202D LEFT-TO-RIGHT OVERRIDE
Where it comes from: Almost never legitimate in product data.
What it breaks: Forces display order regardless of the characters — the same mechanism as U+202E, in the other direction.
Cleaning: deleted
U+202E RIGHT-TO-LEFT OVERRIDE
Where it comes from: Almost never legitimate in product data.
What it breaks: Reverses the display order of everything after it — a known trick for disguising file names and text. Treat its presence as suspicious.
Cleaning: deleted
U+2066 LEFT-TO-RIGHT ISOLATE
Where it comes from: Modern replacement for the embedding controls.
What it breaks: Isolates the run that follows from surrounding text. Must be closed by U+2069.
Cleaning: deleted
U+2067 RIGHT-TO-LEFT ISOLATE
Where it comes from: Modern replacement for the embedding controls.
What it breaks: Isolates the run that follows from surrounding text. Must be closed by U+2069.
Cleaning: deleted
U+2068 FIRST STRONG ISOLATE
Where it comes from: Used when the direction of the inserted text is not known in advance.
What it breaks: Isolates the run that follows, taking its direction from its first strong character. Must be closed by U+2069.
Cleaning: deleted
U+2069 POP DIRECTIONAL ISOLATE
Where it comes from: Written by editors and libraries that emit bidirectional text, to close an isolate they opened.
What it breaks: Harmless on its own, but one too many means an isolate was closed that was never opened.
Cleaning: deleted
U+200E LEFT-TO-RIGHT MARK
Where it comes from: Inserted by editors to pin the direction of neighbouring punctuation.
What it breaks: Legitimate in genuinely bidirectional text, but invisible — so it silently makes two otherwise identical strings unequal.
Cleaning: deleted
U+200F RIGHT-TO-LEFT MARK
Where it comes from: Inserted by editors to pin the direction of neighbouring punctuation.
What it breaks: Legitimate in genuinely bidirectional text, but invisible — so it silently makes two otherwise identical strings unequal.
Cleaning: deleted
Control characters
U+0009 CHARACTER TABULATION (tab)
Where it comes from: Copied from spreadsheets or code.
What it breaks: Splits a TSV field in two — one stray tab shifts every later column on that row.
Cleaning: replaced with " "
U+000B LINE TABULATION (vertical tab)
Where it comes from: Shift+Enter in Word, and some PDF extractors.
What it breaks: Acts as a line break in some tools and as nothing in others.
Cleaning: replaced with " "
U+000C FORM FEED
Where it comes from: Legacy printing control, occasionally left by PDF extraction.
What it breaks: Invisible; corrupts field parsing.
Cleaning: replaced with " "
Variation selectors
U+FE0F VARIATION SELECTOR-16
Where it comes from: Emoji — forces the colourful rendering of a symbol.
What it breaks: Invisible, counts toward length limits, and turns an otherwise plain symbol into an emoji that many marketplaces reject.
Cleaning: left as-is (removing it could change meaning)
U+FE0E VARIATION SELECTOR-15
Where it comes from: Emoji — forces the monochrome text rendering.
What it breaks: Invisible but stored, and counts toward length limits.
Cleaning: left as-is (removing it could change meaning)