Your grep can't see the text your framework rendered
A launch day earlier this month. Pages pushed, and we wanted proof the published site carried the right copy. So we curled each URL and grepped the served HTML for literal sentences lifted straight from the source. Several greps came back empty, on sentences we could read on the live page in any browser.
The pages were fine. The greps were the bug.
Where the sentence went
React server rendering, Next.js included, does not always emit a sentence as one unbroken run of text. When JSX assembles a sentence from more than one piece, a string here, an expression there, a {" "} between them, each piece becomes its own text node. The server marks the boundary between adjacent text nodes with an empty HTML comment, so hydration on the client can split them back apart.
So the served markup for one on-screen sentence can look like this:
We build<!-- --> automation systems <!-- -->for Montana businesses.
A browser reads that and renders the full sentence. textContent returns the full sentence. An exact substring match against the raw HTML returns nothing, because a comment sits in the middle of your needle.
A negative grep points you the wrong way
The failure is silent, and it lies in a specific direction. Grep finds nothing, so you conclude the deploy dropped your copy. You rebuild, redeploy, diff the output, and burn time on a page that was right the whole time. That is what stung: the tool did not error, it confidently reported an absence that was not there.
Comment markers are not the only splitter, either. Inline tags land mid-sentence, entities replace characters, and whitespace shifts between source and served output. Raw served HTML is an encoding of the page, not the page. Grepping it for a sentence is judging a finished wall from the lumber invoice.
Verify the page the way a browser reads it
The honest fix compares rendered text, not raw markup. Load the page in a headless browser and read document.body.textContent, then search that. Or parse the HTML with a real DOM parser and extract the text, since comments and tags drop out of text extraction. Normalize whitespace before comparing, and the false negatives disappear.
If you want a quick pass without a browser, strip the empty comments first:
curl -s URL | sed 's/<!-- -->//g' | grep 'your sentence'
That patches this one splitter and none of the others, so treat it as a stopgap, not a method.
One more habit, and it is the one that would have saved us: feed any detector a known positive before you trust its negatives. Grep for a sentence you can see on screen right now. If that comes back empty too, the method stands indicted in one try, before it sends you hunting a ghost.
We got lucky in one sense. The false negatives showed up on pages we knew were right, so suspicion fell on the tooling fast. On a page we trusted less, we would have shipped a "fix" for working copy.
A negative grep against raw served HTML is not evidence the text is missing. It is evidence you asked the wrong layer. Ask the layer your reader sees, and the answer comes back true.