<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Davis Scott</title>
    <description>The latest articles on DEV Community by Davis Scott (@davisscott).</description>
    <link>https://dev.to/davisscott</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4106752%2Ff3a53f9d-44ea-46ef-9934-e536efba713d.png</url>
      <title>DEV Community: Davis Scott</title>
      <link>https://dev.to/davisscott</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/davisscott"/>
    <language>en</language>
    <item>
      <title>Does Paste as Plain Text Remove Zero-Width Spaces?</title>
      <dc:creator>Davis Scott</dc:creator>
      <pubDate>Thu, 03 Sep 2026 14:04:42 +0000</pubDate>
      <link>https://dev.to/davisscott/does-paste-as-plain-text-remove-zero-width-spaces-3dah</link>
      <guid>https://dev.to/davisscott/does-paste-as-plain-text-remove-zero-width-spaces-3dah</guid>
      <description>&lt;h2&gt;
  
  
  Two clipboards, two jobs
&lt;/h2&gt;

&lt;p&gt;A modern copy puts more than one flavour on the clipboard.&lt;br&gt;
text/html: spans, styles, data-message-* from a ChatGPT bubble select.&lt;br&gt;
text/plain: the Unicode string, hidden characters included.&lt;/p&gt;

&lt;p&gt;"Paste as plain text" means "please take text/plain." The destination throws away the HTML flavour. It does not run a Unicode allow-list. U+200B is a legal letter-like code point in that string. U+00A0 is a legal space. The OS is correct to keep them.&lt;/p&gt;

&lt;p&gt;Wikimedia and others have noted that selecting a ChatGPT bubble can copy HTML bookkeeping (data-message-author-role, data-message-id). The Copy button is cleaner on that layer. Neither gesture promises a U+200B-free string. You can do everything right on HTML and still be dirty on Unicode.&lt;/p&gt;
&lt;h2&gt;
  
  
  What plain text actually strips
&lt;/h2&gt;

&lt;p&gt;Usually gone: font-family, colour, heading styles, data-message-* attributes, most spans from the chat bubble, Docs comments, Word's mso- junk if you came through Office.&lt;/p&gt;

&lt;p&gt;Still there: letters, punctuation, emoji, U+200B, U+200C, U+200D, U+00A0, U+202F, U+FEFF if it was in the string, and ordinary \n.&lt;/p&gt;

&lt;p&gt;If your sanitizer is strip_tags, you have not sanitised U+200B. If your sanitizer is encode('ascii', 'ignore'), you have destroyed names and emoji. Target the code points.&lt;/p&gt;
&lt;h2&gt;
  
  
  Prove it in thirty seconds
&lt;/h2&gt;

&lt;p&gt;Word's Keep Text Only path is the same experiment with more UI. Save as .txt after a Keep Text Only paste and inspect hex. The e2 80 8b UTF-8 sequence for U+200B will still be there if it was in the source.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;dirty&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;pipe&lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;u200Bline&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;el&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;textarea&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;dirty&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// this is what a "plain" paste into a form looks like&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;([...&lt;/span&gt;&lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;codePointAt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;)));&lt;/span&gt;
&lt;span class="c1"&gt;// still contains 200b&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Word's Keep Text Only path is the same experiment with more UI. Save as .txt after a Keep Text Only paste and inspect hex. The e2 80 8b UTF-8 sequence for U+200B will still be there if it was in the source.&lt;/p&gt;

&lt;h2&gt;
  
  
  Node, if you want a file:
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;writeFileSync&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;fs&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nf"&gt;writeFileSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;out.txt&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;pipe&lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;u200Bline&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;utf8&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// xxd out.txt  →  70 69 70 65 e2 80 8b 6c 69 6e 65&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;textarea.value, .txt, JSON.stringify, and git diff all agree: plain text kept the character.&lt;/p&gt;

&lt;h2&gt;
  
  
  “What to run after plain-text paste.”
&lt;/h2&gt;

&lt;p&gt;Strip the zero-width set, and replace no-break spaces with U+0020:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;[\u&lt;/span&gt;&lt;span class="sr"&gt;200B&lt;/span&gt;&lt;span class="se"&gt;\u&lt;/span&gt;&lt;span class="sr"&gt;200C&lt;/span&gt;&lt;span class="se"&gt;\u&lt;/span&gt;&lt;span class="sr"&gt;200D&lt;/span&gt;&lt;span class="se"&gt;\u&lt;/span&gt;&lt;span class="sr"&gt;FEFF&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;/g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;[\u&lt;/span&gt;&lt;span class="sr"&gt;00A0&lt;/span&gt;&lt;span class="se"&gt;\u&lt;/span&gt;&lt;span class="sr"&gt;202F&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;/g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Python:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;
&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sub&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;[\u200b\u200c\u200d\ufeff]&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sub&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;[\u00a0\u202f]&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt; &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or paste into GPTCleanup, scan, and copy the character-clean version. You do not need an account for the Unicode-clean copy. Phrase humanization is paid and irrelevant to this bug.&lt;br&gt;
If you only do the homepage scan and then paste rich into Word, you can pick up new HTML from whatever you copied in between. Scan, then paste as text, is the pair.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why the myth exists
&lt;/h2&gt;

&lt;p&gt;"Paste as plain text" fixed a generation of Word-to-CMS disasters caused by styles. People generalised it to "plain text means only the letters I can see." Unicode includes letters and a pile of format characters. Zero-width space is in the second pile. The myth is a category error, and it is sticky because the first layer (HTML) really does disappear, so the ritual feels complete.&lt;/p&gt;

&lt;p&gt;A second source of the myth: some Windows Notepad builds used to drop or mangle certain controls when the encoding was ANSI. People remember "Notepad cleaned it." Modern Notepad on UTF-8 will keep U+200B. Do not rely on folklore from XP.&lt;/p&gt;

&lt;p&gt;A third source: Google Docs "paste without formatting" is described in help articles as removing styles. Readers hear "formatting" and think "anything invisible." U+200B is content.&lt;/p&gt;

&lt;h2&gt;
  
  
  A pipeline that does both layers
&lt;/h2&gt;

&lt;p&gt;Copy with the ChatGPT message Copy control (cuts a lot of HTML at the source).&lt;/p&gt;

&lt;p&gt;Paste as plain text into a scratch buffer (kills remaining HTML).&lt;/p&gt;

&lt;p&gt;Strip hidden Unicode (kills U+200B and friends).&lt;/p&gt;

&lt;p&gt;Then parse JSON, paste into Word, or commit the fixture.&lt;/p&gt;

&lt;p&gt;Skip 2 and you fight styles. Skip 3 and you fight ghosts. Do both and the ticket closes.&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>software</category>
      <category>tools</category>
    </item>
    <item>
      <title>Why ChatGPT Paste Breaks Microsoft Word Formatting</title>
      <dc:creator>Davis Scott</dc:creator>
      <pubDate>Wed, 02 Sep 2026 20:46:26 +0000</pubDate>
      <link>https://dev.to/davisscott/why-chatgpt-paste-breaks-microsoft-word-formatting-3a7e</link>
      <guid>https://dev.to/davisscott/why-chatgpt-paste-breaks-microsoft-word-formatting-3a7e</guid>
      <description>&lt;p&gt;Word breaks ChatGPT paste because it honours characters the chat window hid from you. No-break spaces stop wrapping. Zero-width spaces glue fragments of a word together for spellcheck and find. A select-and-copy can bring HTML that Word maps onto styles you never asked for. The paragraph looks like the chat, then the print layout, the table cell, or the mail merge field misbehaves.&lt;/p&gt;

&lt;h2&gt;
  
  
  The wrapping bug
&lt;/h2&gt;

&lt;p&gt;If a line in a narrow column refuses to break, inspect for U+00A0 or U+202F. Word treats both as glue. Replace them with U+0020 and the line will wrap like a human-typed paragraph.&lt;/p&gt;

&lt;p&gt;Show formatting marks (Ctrl+Shift+8). A no-break space often appears as a degree-like mark between words. Zero-width spaces will not show as a gap. You still need a code-point view for those.&lt;/p&gt;

&lt;h2&gt;
  
  
  The style bug
&lt;/h2&gt;

&lt;p&gt;Paste Options in Word offers Keep Source Formatting, Merge Formatting, and Keep Text Only. Keep Source Formatting is how chat HTML becomes a Heading 2 or a hyperlink style you then fight for ten minutes. Keep Text Only drops most of that. It keeps Unicode spaces.&lt;/p&gt;

&lt;p&gt;Order of operations that wastes less time:&lt;/p&gt;

&lt;p&gt;Copy with the ChatGPT Copy button, not a drag select.&lt;br&gt;
Paste as text only.&lt;br&gt;
Strip hidden Unicode.&lt;br&gt;
Apply the Word style you actually want.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.gptcleanup.com/" rel="noopener noreferrer"&gt;Use a clean ChatGPT &lt;/a&gt;paste if step 3 is a long draft. Copy the character-clean version for free. Phrase rewrites are paid and they will not fix a wrap.&lt;/p&gt;

&lt;h2&gt;
  
  
  The field and mail-merge bug
&lt;/h2&gt;

&lt;p&gt;Merge fields and content controls are strict about the characters inside them. A U+200B in a name field can make two records look identical and compare unequal. Clean the source column before you map it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Does Word detect AI from a ChatGPT paste?
&lt;/h2&gt;

&lt;p&gt;Word is a layout engine. OpenAI has not shipped a text watermark. Detectors that people mention next to Turnitin score prose. Cleaning Word-breaking characters is document hygiene, including for drafts a person typed in another app that also inserts U+00A0.&lt;/p&gt;

&lt;p&gt;If spellcheck lights up a word that looks perfect, select it and arrow through it. A zero-width space feels like the cursor stuck for one keystroke on nothing. Delete that nothing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Styles, templates, and why "Clear Formatting" is incomplete
&lt;/h2&gt;

&lt;p&gt;Clear Formatting in Word removes local bold, colour, and style overrides. It does not walk the Unicode. A Heading 1 that still will not wrap after you clear formatting still has U+00A0 in it.&lt;/p&gt;

&lt;p&gt;If you paste into a tightly locked corporate template, the template's styles win for fonts and then lose to no-break spaces inside the runs. Clean the string outside Word, then paste into the content control.&lt;/p&gt;

&lt;p&gt;Mail merge from Excel has the same bug when the spreadsheet cells were filled from a chat. Clean the column in a text editor or with a formula that substitutes CHAR(160) and the zero-width set, then merge.&lt;/p&gt;

&lt;h2&gt;
  
  
  Track Changes noise
&lt;/h2&gt;

&lt;p&gt;If you clean a document that already has Track Changes on, Word will record every space substitution as an edit. That is correct and ugly. Copy the article to a new file, clean it, paste back as one replacement, or accept that the review pane will fill with "spaces." Tell reviewers before they open it.&lt;/p&gt;

&lt;h2&gt;
  
  
  A VBA-free check
&lt;/h2&gt;

&lt;p&gt;Save a copy as .txt with Unicode encoding, open it in an editor that can show code points, and search for 00A0 and 200B. If they appear, clean the .txt and open that in Word. You skipped the HTML clipboard entirely.&lt;/p&gt;

&lt;p&gt;That round trip is crude and it works when you are not allowed to install anything. When you can use a site, GPTCleanup is faster. Same bytes out.&lt;/p&gt;

&lt;h2&gt;
  
  
  Headers, footers, and content controls
&lt;/h2&gt;

&lt;p&gt;Word content controls (the grey boxes in a lot of enterprise templates) validate on exit. A hidden character inside the control can fail validation with a message that does not mention Unicode. If a control rejects a value that looks legal, paste the value into Notepad and back. If it then accepts, you had clipboard junk.&lt;/p&gt;

&lt;p&gt;Headers and footers copy independently. Cleaning the body and leaving a U+00A0 in the header is a classic "I cleaned it and page 3 still overflows" report. Repeat the clean for header, footer, footnotes, and comments. Word stores those as separate stories. A site that only sees what you paste will not see the header unless you paste the header.&lt;/p&gt;

&lt;h2&gt;
  
  
  Numbered lists from the chat
&lt;/h2&gt;

&lt;p&gt;ChatGPT often emits lists that Word pastes as manual numbers plus tabs, or as a list style you do not use. That is visible formatting, not hidden Unicode. Fix it with Word's list tools after the Unicode pass. Doing list repair first, then a clean that collapses spaces, can merge 1. into the paragraph. Hidden-character cleanup first, list repair second.&lt;/p&gt;

&lt;p&gt;Once that order is a habit, ChatGPT-to-Word stops feeling cursed. The model is outputting text. Word is being precise about characters. You just have to meet Word at its level of precision.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Why ChatGPT Paste Looks Different in Google Docs</title>
      <dc:creator>Davis Scott</dc:creator>
      <pubDate>Wed, 02 Sep 2026 19:26:10 +0000</pubDate>
      <link>https://dev.to/davisscott/why-chatgpt-paste-looks-different-in-google-docs-1pnh</link>
      <guid>https://dev.to/davisscott/why-chatgpt-paste-looks-different-in-google-docs-1pnh</guid>
      <description>&lt;p&gt;ChatGPT paste looks different in Google Docs because the clipboard often carries more than the glyphs you saw in the chat. Docs then interprets no-break spaces, zero-width code points, and leftover HTML the way a word processor should: it refuses to wrap where a no-break space sits, it treats a zero-width space as part of the word, and it can keep rich-text residue from a select-and-copy.&lt;/p&gt;

&lt;p&gt;The words did not change. The code points around them did.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Docs does with a no-break space
&lt;/h2&gt;

&lt;p&gt;A normal space (U+0020) is a wrap opportunity. A no-break space (U+00A0) is a glue. Chat UIs and many editors insert U+00A0 when they want "100 km" or "Mr. Smith" to stay on one line. When that character is scattered through a paragraph, Docs will not break the line where you expect. On a narrow column, or in a comment, the line overflows or leaves an awkward hole.&lt;/p&gt;

&lt;p&gt;The narrow no-break space (U+202F) is the same idea with a thinner glyph. In April 2025 it showed up in longer o3 and o4-mini pastes. OpenAI called it a training quirk. It looks identical to a space in Docs until you put the cursor in the middle of a "word" that will not hyphenate.&lt;/p&gt;

&lt;h2&gt;
  
  
  What a zero-width space does to search inside the doc
&lt;/h2&gt;

&lt;p&gt;U+200B has no width. Docs will still store it. Find in document can miss marketing if the file contains market[U+200B]ing. Word count can drift by a few characters. Collaborators who copy a heading into a URL slug get a character they cannot see and a link that does not match the heading they typed later.&lt;/p&gt;

&lt;p&gt;This is why "it looks fine in ChatGPT and weird in Docs" is usually a clipboard story, not a font story.&lt;/p&gt;

&lt;h2&gt;
  
  
  Select-all versus the Copy button
&lt;/h2&gt;

&lt;p&gt;If you drag-select the reply, the browser may put an HTML fragment on the clipboard. ChatGPT's UI has used data-message-* attributes to track the bubble. Docs then has to decide whether to keep any of that markup. The Copy control on the message has more often produced a plainer payload.&lt;/p&gt;

&lt;p&gt;When a paste into Docs brings unexpected bold, extra spans, or a style that will not clear with "paste without formatting," try the Copy button first, then paste again. Ctrl+Shift+V (or Cmd+Shift+V) strips a lot of rich formatting. It does not always strip valid Unicode spaces, because those are still plain text.&lt;/p&gt;

&lt;h2&gt;
  
  
  A 30-second check in Docs
&lt;/h2&gt;

&lt;p&gt;Paste the ChatGPT output into a new Doc.&lt;br&gt;
Put the cursor where wrapping looks wrong and use the right-arrow key. If the cursor hesitates on an empty column, you likely have U+00A0 or U+202F.&lt;br&gt;
Search for a word you can see. If Docs finds nothing, try pasting that word from the chat again, or inspect code points in a text editor.&lt;br&gt;
If you need a clean copy, run a Unicode cleaner, then paste the result with paste-without-formatting.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.gptcleanup.com/" rel="noopener noreferrer"&gt;GPT CLEAN UP&lt;/a&gt; will scan the draft on the homepage, show what it found, and let you copy a character-clean version without a plan. Phrase suggestions and humanization are paid. The Docs problem is almost always the free layer: hidden spaces and paste HTML.&lt;/p&gt;

&lt;h2&gt;
  
  
  Does this mean Docs is detecting AI?
&lt;/h2&gt;

&lt;p&gt;No. Docs is laying out characters. It has no idea who wrote the paragraph. AI detectors that people worry about in school or publishing score writing patterns: predictability, burstiness, vocabulary. Originality.ai's own test of adding or removing invisible characters did not move those scores. Cleaning the paste so Docs wraps correctly is a formatting fix.&lt;/p&gt;

&lt;p&gt;OpenAI has not shipped a text watermark in ChatGPT. Image and audio files can carry C2PA and SynthID. A Google Doc is neither.&lt;/p&gt;

&lt;h2&gt;
  
  
  When the paste is still ugly after a clean
&lt;/h2&gt;

&lt;p&gt;Then the remaining issues are visible: smart quotes, long dashes, markdown &lt;strong&gt;bold&lt;/strong&gt; that never rendered, extra blank lines from the chat column. Those are optional. Strip hidden characters first so you can see the real layout, then decide whether you want ASCII punctuation. Mixing those two jobs in one panic pass is how people delete meaning they meant to keep.&lt;/p&gt;

&lt;h2&gt;
  
  
  Docs-specific moves that actually help
&lt;/h2&gt;

&lt;p&gt;Paste without formatting as the default. In Docs, Ctrl+Shift+V (Cmd+Shift+V on Mac) is the gesture that avoids inheriting chat-bubble styles. Pair it with a Unicode strip so you are not keeping U+00A0.&lt;/p&gt;

&lt;p&gt;Clear direct formatting after a bad paste. Select the paragraph, then Format → Clear formatting. This drops local overrides. It will not delete U+200B.&lt;/p&gt;

&lt;p&gt;Watch comments and suggestions. A no-break space inside a suggested edit is painful to select. If a comment thread looks like the text is "stuck" to the next word, inspect that join.&lt;/p&gt;

&lt;p&gt;Tables. Docs tables already fight wrapping. A single U+00A0 in a cell is enough to force horizontal scroll on a laptop. Clean the source, then paste into the cell.&lt;/p&gt;

&lt;p&gt;Add-ons and "markdown in Docs." Some add-ons re-parse the paste and reintroduce spans. If a clean paste becomes dirty after an add-on runs, the add-on is the second clipboard. Turn it off for the paste step.&lt;/p&gt;

&lt;h2&gt;
  
  
  A small QA checklist before you share the Doc
&lt;/h2&gt;

&lt;p&gt;Search for a distinctive word from the ChatGPT output. If Docs cannot find a word you can see, suspect zero-width characters.&lt;br&gt;
Shrink the browser window. If a paragraph overflows instead of wrapping, suspect no-break spaces.&lt;br&gt;
Copy a heading into the document outline or a link. If the URL looks identical to a later typed heading and the two do not match in a script, print code points.&lt;br&gt;
Keep the original chat until a second person can open the Doc on their machine. Clipboard bugs are local until they are in the file.&lt;/p&gt;

&lt;p&gt;That is the whole Docs problem: the file stored different characters than the screen showed. Once you believe that, the cleaner is obvious and the "watermark" story is optional.&lt;/p&gt;

</description>
      <category>chatgpt</category>
      <category>productivity</category>
      <category>tools</category>
    </item>
  </channel>
</rss>
