What text actually is, and why tools disagree about it
A text file is bytes plus an encoding, and the encoding is not stored in the file. Nothing but a convention tells a program that a particular byte means "é" — which is why the same file opens correctly in one place and as "é" in another. UTF-8 is the modern answer and stores common Latin letters in one byte, accented letters in two, and most of Chinese, Japanese, Arabic and every emoji in three or four. UTF-16 is what Windows and JavaScript use internally and stores almost everything in two bytes and the rest in four. Windows-1252 and Latin-1 are the single-byte encodings older systems still produce, and they are the usual source of mojibake. Worth knowing about these pages: the CSV Viewer detects the encoding of a file you drop in, including UTF-16 and Windows-1252, and will let you override it. The plain text boxes do not — a dropped file is read as UTF-8, so a Latin-1 export will show its accented letters wrongly and the fix is to convert it first.
"Character" has four meanings and the one you need depends on who is doing the limiting. What a person sees as one character is a grapheme cluster. What a regular expression matches is a code point. What JavaScript's string.length reports is UTF-16 units. What a database column or an HTTP header measures is UTF-8 bytes. For plain English all four agree, which is why nobody notices — and then a family emoji is one grapheme, seven code points, eleven UTF-16 units and twenty-five bytes, and a 200-character message is rejected by a 255-character field. The Character Counter shows all four for exactly this reason.
Invisible characters are real characters. A non-breaking space looks identical to a space and is a different character entirely — it arrives constantly in text copied from a web page or a word processor, and it breaks searches, CSV parsing and code that splits on spaces. Zero-width joiners are what hold a multi-person emoji together. Soft hyphens, direction marks and byte-order marks all travel with pasted text. None of them show up on screen, so the only signal you get is a count that disagrees with what you can see — which is one honest use for a character counter. Note that the ignore-spacing option in Text Compare collapses ordinary spaces and tabs; it does not treat a non-breaking space as a space, because they are not the same thing.
Line endings are the reason a diff sometimes shows every line as changed. Windows ends a line with carriage return and line feed; everything else uses line feed alone. Save an LF file from a Windows editor and every line in it now differs by one invisible byte, so a byte-level comparison — git diff, diff(1) — reports the entire file as rewritten and hides the one change you actually made. Our Text Compare and Duplicate Line Remover split on all three conventions before comparing, so a file that merely changed its line endings does not show up here as a wall of red. That is a convenience in a reading tool and a trap in a repository: fix it at the source with your editor or with git's own line-ending settings.
Two identical-looking strings can compare as different, and normalisation is usually why. Unicode can write "é" two ways: as one code point, or as a plain "e" followed by a combining acute accent. They render the same and they are different sequences of bytes, so a comparison, a deduplication or a database lookup treats them as two different values. macOS and Windows have historically disagreed about which form to use for filenames, which is how a list gathered from two machines ends up with what look like exact duplicates that will not deduplicate. The Character Counter is how you spot it — the two forms have the same grapheme count and a different code point count. None of these tools convert between the forms; that is a one-line job for a script with a Unicode library, such as Python's unicodedata.normalize.
"Word count" is a judgement, not a measurement. Splitting on whitespace is an English rule, and applying it to Chinese, Japanese or Thai — which do not put spaces between words — reports a long article as one word. Our counter uses the browser's Unicode word segmentation instead, which knows where words begin in every script. The remaining disagreements are about hyphens ("well-known" is one word here and in Word, two in some tools), standalone numbers, and what counts as a sentence — "We met Dr. Smith" is one sentence and a naive splitter says two. Reading time is a further estimate on top: 238 words per minute for silent reading, from a meta-analysis rather than the round number that gets copied between blog posts.
Where a browser is genuinely the wrong tool
Everything in this module runs on your own device, which is what makes it safe to paste an unpublished draft or proprietary source into. It also sets the ceiling, and we would rather say where it is than have you find out halfway through.
Large files. The whole text is held in the tab's memory and re-examined as you type. A few megabytes is comfortable; a multi-hundred-megabyte log file is not, and a phone gives up sooner than a laptop. The command line does not have this problem because it streams: grep and ripgrep search files larger than your memory, sed and awk transform them line by line, and sort with the unique flag deduplicates a list of tens of millions of lines by spilling to disk. All of those are free and already installed on macOS and Linux.
Very different documents. Text Compare stops at 8,000 differences, because past that the algorithm's memory cost grows fast enough to freeze the tab and a diff that large is unreadable anyway. Two versions of the same document almost never reach it; two unrelated documents reach it immediately. For reviewing code, diff and git diff handle any size, and a proper three-way merge tool does something this page cannot do at all.
Changing an encoding, or normalising Unicode. These pages read and report; they do not convert between encodings. iconv converts between every encoding there is, the file command guesses what you have, and Unicode normalisation is a line of Python or a call to ICU's uconv. If you are repairing a mojibake export, that is the toolchain.
Anything repeated. These tools run when a person clicks. Counting words across four hundred documents, or minifying a directory on every commit, is a script or a build step — and for minifying specifically, your build tool is running the same engines this page does, with source maps, watch mode and caching that a paste box cannot offer. This page is for the one file you have in front of you.
Modern CSS. The CSS Minifier refuses native nesting and modern media range syntax rather than minifying them, because the engine behind it predates both and silently deletes what it does not understand. That is an honest refusal rather than a feature, and the answer is to compile the nesting away first with Sass, PostCSS or Lightning CSS — which your build tool almost certainly already does.
Choosing between the tools that sound alike
Word Counter vs Character Counter. The same engine with different headline numbers. Word Counter leads with words, sentences, paragraphs and reading time, which is what an essay, an article or a speech is measured in. Character Counter leads with characters, characters without spaces and UTF-8 bytes, which is what a meta description, an SMS segment or a database field is measured in. If something rejected your text for being too long, you want the character one and specifically its byte count.
Text Compare vs Duplicate Line Remover. Compare answers "what changed between these two versions" and needs two texts. The duplicate remover works on one list and answers "what appears more than once in here", and it will also tell you which entries repeated and how often, sort naturally so item2 comes before item10, or keep only the lines that appeared exactly once. Finding the entries unique to one of two lists is the duplicate remover's job, not the comparer's.
HTML Minifier vs CSS Minifier vs JavaScript Minifier. Three languages, three engines, and one overlap worth knowing: the HTML minifier also minifies the CSS inside style blocks and the JavaScript inside script blocks, using the same two engines as the other pages. So a single HTML file needs one tool, not three. Separate .css and .js files need their own pages.
XML Viewer vs XML Formatter and XML Validator. The viewer here gives you a collapsible tree to explore, which is what you want when the document is large and you are looking for something. The formatter and validator, in the developer tools, give you indented text to paste back into a file and the exact line and column of a break. Reading, versus editing and fixing.
CSV Viewer vs opening the file in Excel. Not a rival tool, but it is the comparison people are actually making. Excel converts as it opens and does not ask: a product code of 00123 becomes 123, a part number of 5-3 becomes 5 March, a long order number becomes scientific notation, and a semicolon-separated export from a German system lands entirely in column A. The viewer shows every value as text, exactly as stored, so you can see what you were actually sent.
Markdown Preview vs Markdown to PDF. The preview is for checking that a README renders the way GitHub will render it, live as you type. Markdown to PDF, in the document tools, is for producing a finished document with page breaks. Check here, publish there.