Unlock Your ChatGPT Conversations: Extracting and Copying Search Data with a Bookmarklet

Unlock Your ChatGPT Conversations: Extracting and Copying Search Data with a Bookmarklet

ChatGPT has become an invaluable tool for countless tasks, from brainstorming to research. As conversations grow longer and more complex, you might find yourself wishing you could easily extract the underlying “thoughts,” “search queries,” and “search results” that ChatGPT generates, especially when using features like Browse with Bing or custom GPTs. These hidden gems often contain valuable context, research trails, and source information.

While ChatGPT doesn’t offer a built-in “export search data” button, a simple JavaScript bookmarklet can bridge this gap. This article will walk you through a powerful bookmarklet designed to extract this rich data and present it in an easily copiable format. We’ll also dive into the fascinating challenge of making the “Copy All” button work reliably across different browsers.

What Does This Bookmarklet Do?

This bookmarklet, when clicked on an active ChatGPT conversation page, performs three key actions:

  1. Extracts Hidden Data: It taps into ChatGPT’s internal APIs (securely, using your existing session) to pull out:
    • 💭 Thoughts: The internal reasoning and steps ChatGPT took to formulate its responses.
    • 🔍 Search Queries: The actual queries ChatGPT used when Browse the web (e.g., via “Browse with Bing”).
    • 🌐 Search Results: The titles, URLs, and snippets of the web pages ChatGPT referenced.
  2. Presents Data in a New Tab: It opens a clean, well-formatted new browser tab (or window) displaying all the extracted information, categorized and easy to read.
  3. Enables One-Click Copying: A “Copy All” button allows you to quickly grab all the extracted text for use in your notes, documents, or other applications.

search the web

Why is This Useful?

  • Deeper Understanding: See how ChatGPT arrived at its answers, understanding its reasoning process.
  • Research Trail: Quickly gather all search queries and source links for verification or further research.
  • Knowledge Management: Easily transfer valuable information from your conversations into your personal knowledge base.
  • Debugging: If ChatGPT gives an unexpected answer, seeing its internal thoughts and search process can help you understand why.

The Bookmarklet Code

Here’s the complete JavaScript code for the bookmarklet. To use it:

  1. Copy the entire code block below.
  2. In your web browser (Chrome, Firefox, Edge, Safari, Brave, etc.), open your Bookmarks Manager.
  3. Create a new bookmark.
  4. In the “URL” or “Location” field, paste the copied JavaScript code.
  5. Give your bookmark a memorable name (e.g., “ChatGPT Data Extractor”).
  6. Save the bookmark.
  7. Now, open any ChatGPT conversation and click your new bookmarklet from your bookmarks bar or menu!

 

javascript:(function()%7Bjavascript%3A(async%20()%20%3D%3E%20%7B%0A%20%20%20%20try%20%7B%0A%20%20%20%20%20%20%20%20%2F*%20----------%201.%20Collect%20data%20----------%20*%2F%0A%20%20%20%20%20%20%20%20const%20cid%20%3D%20location.pathname.match(%2F%5C%2Fc%5C%2F(%5B%5E%2F%5D%2B)%2F)%3F.%5B1%5D%3B%0A%20%20%20%20%20%20%20%20if%20(!cid)%20%7B%20alert(%22Open%20a%20ChatGPT%20conversation%20first.%22)%3B%20return%3B%20%7D%0A%0A%20%20%20%20%20%20%20%20let%20sess%2C%20convo%3B%0A%20%20%20%20%20%20%20%20try%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20sess%20%3D%20await%20fetch(%22%2Fapi%2Fauth%2Fsession%22).then(r%20%3D%3E%20r.json())%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20(!sess%20%7C%7C%20!sess.accessToken)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20alert(%22Failed%20to%20get%20session%20or%20access%20token.%20Login%20to%20ChatGPT%3F%22)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20return%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%7D%20catch%20(e)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20alert(%22Error%20fetching%20session%3A%20%22%20%2B%20e.message%20%2B%20%22.%20Are%20you%20logged%20into%20ChatGPT%3F%22)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20return%3B%0A%20%20%20%20%20%20%20%20%7D%0A%0A%20%20%20%20%20%20%20%20try%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20convo%20%3D%20await%20fetch(%60%2Fbackend-api%2Fconversation%2F%24%7Bcid%7D%60%2C%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20headers%3A%20%7B%20%22Authorization%22%3A%20%22Bearer%20%22%20%2B%20sess.accessToken%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D).then(r%20%3D%3E%20r.json())%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20(!convo%20%7C%7C%20!convo.mapping)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20alert(%22Failed%20to%20get%20conversation%20data.%20The%20conversation%20might%20be%20too%20old%20or%20the%20API%20changed.%22)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20return%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%7D%20catch%20(e)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20alert(%22Error%20fetching%20conversation%20data%3A%20%22%20%2B%20e.message%20%2B%20%22.%20The%20ChatGPT%20API%20might%20have%20changed.%22)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20return%3B%0A%20%20%20%20%20%20%20%20%7D%0A%0A%20%20%20%20%20%20%20%20const%20thoughts%20%3D%20%5B%5D%3B%0A%20%20%20%20%20%20%20%20const%20queries%20%3D%20new%20Set()%3B%0A%20%20%20%20%20%20%20%20const%20results%20%3D%20%5B%5D%3B%0A%0A%20%20%20%20%20%20%20%20Object.values(convo.mapping%20%7C%7C%20%7B%7D).forEach(node%20%3D%3E%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20const%20m%20%3D%20node.message%20%7C%7C%20%7B%7D%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20const%20meta%20%3D%20m.metadata%20%7C%7C%20%7B%7D%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20const%20c%20%3D%20m.content%20%7C%7C%20%7B%7D%3B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20(c.content_type%20%3D%3D%3D%20%22thoughts%22)%20(c.thoughts%20%7C%7C%20%5B%5D).forEach(t%20%3D%3E%20t.content%20%26%26%20thoughts.push(t.content))%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20(meta.search_queries%20%7C%7C%20%5B%5D).forEach(sq%20%3D%3E%20sq.q%20%26%26%20queries.add(sq.q))%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20(meta.search_result_groups%20%7C%7C%20%5B%5D).forEach(g%20%3D%3E%20(g.entries%20%7C%7C%20%5B%5D).forEach(e%20%3D%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20results.push(%7B%20url%3Ae.url%2C%20title%3Ae.title%2C%20snippet%3Ae.snippet%20%7D)%0A%20%20%20%20%20%20%20%20%20%20%20%20))%3B%0A%20%20%20%20%20%20%20%20%7D)%3B%0A%20%20%20%20%20%20%20%20const%20queriesArr%20%3D%20%5B...queries%5D%3B%20%2F%2F%20Convert%20Set%20to%20Array%20here%0A%0A%20%20%20%20%20%20%20%20%2F*%20----------%202.%20Build%20HTML%20in%20new%20tab%20(Programmatic%20DOM%20Building)%20----------%20*%2F%0A%20%20%20%20%20%20%20%20const%20w%20%3D%20window.open(%22%22%2C%20%22_blank%22)%3B%0A%20%20%20%20%20%20%20%20if%20(!w)%20%7B%20alert(%22Pop-up%20blocked.%20Please%20allow%20pop-ups%20for%20this%20site.%22)%3B%20return%3B%20%7D%0A%0A%20%20%20%20%20%20%20%20const%20doc%20%3D%20w.document%3B%0A%20%20%20%20%20%20%20%20doc.open()%3B%20%2F%2F%20Start%20writing%20to%20the%20document%0A%20%20%20%20%20%20%20%20doc.close()%3B%20%2F%2F%20Finish%20writing%20the%20initial%20blank%20document%0A%0A%20%20%20%20%20%20%20%20%2F%2F%20Define%20CSS%0A%20%20%20%20%20%20%20%20const%20cssContent%20%3D%20%60%0A%20%20%20%20%20%20%20%20%20%20%20%20body%7Bfont-family%3A-apple-system%2CBlinkMacSystemFont%2C'Segoe%20UI'%2CRoboto%2Csans-serif%3Bmax-width%3A800px%3Bmargin%3A40px%20auto%3Bpadding%3A20px%3Bbackground%3A%23f8fafc%3Bline-height%3A1.6%3B%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20.header%7Bdisplay%3Aflex%3Balign-items%3Acenter%3Bgap%3A15px%3Bmargin-bottom%3A20px%3B%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20.clipboard-btn%7Bbackground%3A%234299e1%3Bcolor%3Awhite%3Bborder%3Anone%3Bpadding%3A8px%2012px%3Bborder-radius%3A6px%3Bcursor%3Apointer%3Bfont-size%3A14px%3Btransition%3Aall%200.2s%3Bdisplay%3Aflex%3Balign-items%3Acenter%3Bgap%3A6px%3B%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20.clipboard-btn%3Ahover%7Bbackground%3A%233182ce%3Btransform%3AtranslateY(-1px)%3B%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20.clipboard-btn%3Aactive%7Bbackground%3A%232c5282%3Btransform%3AtranslateY(0)%3B%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20.clipboard-icon%7Bwidth%3A16px%3Bheight%3A16px%3B%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20.success-toast%7Bposition%3Afixed%3Btop%3A20px%3Bright%3A20px%3Bbackground%3A%2348bb78%3Bcolor%3Awhite%3Bpadding%3A12px%2020px%3Bborder-radius%3A6px%3Bbox-shadow%3A0%204px%2012px%20rgba(0%2C0%2C0%2C0.15)%3Bopacity%3A0%3Btransform%3AtranslateX(100%25)%3Btransition%3Aall%200.3s%20ease%3Bz-index%3A1000%3B%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20.success-toast.show%7Bopacity%3A1%3Btransform%3AtranslateX(0)%3B%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20h1%7Bcolor%3A%232d3748%3Bborder-bottom%3A3px%20solid%20%234299e1%3Bpadding-bottom%3A10px%3Bmargin%3A0%3B%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20p%7Bcolor%3A%23718096%3Bmargin-bottom%3A30px%3Bfont-size%3A16px%3B%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20.block%7Bbackground%3Awhite%3Bmargin%3A15px%200%3Bpadding%3A20px%3Bborder-radius%3A8px%3Bbox-shadow%3A0%202px%208px%20rgba(0%2C0%2C0%2C0.1)%3Bborder-left%3A4px%20solid%20%234299e1%3Btransition%3Aall%200.2s%3B%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20.block%3Ahover%7Btransform%3AtranslateY(-2px)%3Bbox-shadow%3A0%204px%2012px%20rgba(0%2C0%2C0%2C0.15)%3B%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20.count%7Bcolor%3A%23718096%3Bfont-size%3A14px%3Bmargin-bottom%3A8px%3Bfont-weight%3A500%3B%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20.query-text%7Bfont-family%3AMonaco%2CMenlo%2C'Ubuntu%20Mono'%2Cmonospace%3Bcolor%3A%232d3748%3Bfont-size%3A15px%3Bbackground%3A%23f7fafc%3Bpadding%3A10px%3Bborder-radius%3A4px%3Bborder%3A1px%20solid%20%23e2e8f0%3B%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20a%20%7B%20color%3A%20%23007bff%3B%20text-decoration%3A%20none%3B%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20a%3Ahover%20%7B%20text-decoration%3A%20underline%3B%20%7D%0A%20%20%20%20%20%20%20%20%60%3B%0A%0A%20%20%20%20%20%20%20%20const%20style%20%3D%20doc.createElement('style')%3B%0A%20%20%20%20%20%20%20%20style.textContent%20%3D%20cssContent%3B%0A%20%20%20%20%20%20%20%20doc.head.appendChild(style)%3B%0A%0A%20%20%20%20%20%20%20%20doc.title%20%3D%20%22ChatGPT%20Extracted%20Data%22%3B%20%2F%2F%20Set%20title%0A%0A%20%20%20%20%20%20%20%20%2F%2F%20Create%20elements%20for%20the%20body%0A%20%20%20%20%20%20%20%20const%20container%20%3D%20doc.createElement('div')%3B%0A%20%20%20%20%20%20%20%20container.style.maxWidth%20%3D%20'800px'%3B%20%2F%2F%20Re-apply%20max-width%20as%20it's%20not%20in%20body%20style%20now%0A%20%20%20%20%20%20%20%20container.style.margin%20%3D%20'40px%20auto'%3B%0A%20%20%20%20%20%20%20%20container.style.padding%20%3D%20'20px'%3B%0A%0A%20%20%20%20%20%20%20%20const%20header%20%3D%20doc.createElement('div')%3B%0A%20%20%20%20%20%20%20%20header.className%20%3D%20'header'%3B%0A%0A%20%20%20%20%20%20%20%20const%20title%20%3D%20doc.createElement('h1')%3B%0A%20%20%20%20%20%20%20%20title.textContent%20%3D%20'%F0%9F%A7%A0%20Extracted%20ChatGPT%20Data'%3B%0A%0A%20%20%20%20%20%20%20%20const%20clipboardBtn%20%3D%20doc.createElement('button')%3B%0A%20%20%20%20%20%20%20%20clipboardBtn.className%20%3D%20'clipboard-btn'%3B%0A%20%20%20%20%20%20%20%20clipboardBtn.innerHTML%20%3D%20%60%F0%9F%93%8B%20Copy%20All%60%3B%0A%0A%20%20%20%20%20%20%20%20const%20toast%20%3D%20doc.createElement('div')%3B%0A%20%20%20%20%20%20%20%20toast.className%20%3D%20'success-toast'%3B%0A%20%20%20%20%20%20%20%20toast.id%20%3D%20'successToast'%3B%0A%20%20%20%20%20%20%20%20toast.textContent%20%3D%20'Copied%20to%20clipboard!%20%F0%9F%93%8B'%3B%20%2F%2F%20General%20message%20for%20all%20data%20types%0A%20%20%20%20%20%20%20%20doc.body.appendChild(toast)%3B%20%2F%2F%20Append%20toast%20to%20main%20body%2C%20not%20container%0A%0A%20%20%20%20%20%20%20%20header.appendChild(title)%3B%0A%20%20%20%20%20%20%20%20header.appendChild(clipboardBtn)%3B%0A%20%20%20%20%20%20%20%20container.appendChild(header)%3B%0A%0A%20%20%20%20%20%20%20%20%2F%2F%20Thoughts%20section%0A%20%20%20%20%20%20%20%20const%20thoughtsHeading%20%3D%20doc.createElement('h2')%3B%0A%20%20%20%20%20%20%20%20thoughtsHeading.textContent%20%3D%20'%F0%9F%92%AD%20Thoughts'%3B%0A%20%20%20%20%20%20%20%20container.appendChild(thoughtsHeading)%3B%0A%20%20%20%20%20%20%20%20if%20(thoughts.length%20%3E%200)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20thoughts.forEach(t%20%3D%3E%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20const%20item%20%3D%20doc.createElement('div')%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20item.className%20%3D%20'block'%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20item.textContent%20%3D%20t%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20container.appendChild(item)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D)%3B%0A%20%20%20%20%20%20%20%20%7D%20else%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20const%20noThoughts%20%3D%20doc.createElement('div')%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20noThoughts.className%20%3D%20'block'%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20noThoughts.textContent%20%3D%20'No%20thoughts%20found.'%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20container.appendChild(noThoughts)%3B%0A%20%20%20%20%20%20%20%20%7D%0A%0A%20%20%20%20%20%20%20%20%2F%2F%20Search%20Queries%20section%0A%20%20%20%20%20%20%20%20const%20queriesHeading%20%3D%20doc.createElement('h2')%3B%0A%20%20%20%20%20%20%20%20queriesHeading.textContent%20%3D%20'%F0%9F%94%8D%20Search%20Queries'%3B%0A%20%20%20%20%20%20%20%20container.appendChild(queriesHeading)%3B%0A%20%20%20%20%20%20%20%20if%20(queriesArr.length%20%3E%200)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20queriesArr.forEach(q%20%3D%3E%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20const%20item%20%3D%20doc.createElement('div')%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20item.className%20%3D%20'block'%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20item.textContent%20%3D%20q%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20container.appendChild(item)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D)%3B%0A%20%20%20%20%20%20%20%20%7D%20else%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20const%20noQueries%20%3D%20doc.createElement('div')%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20noQueries.className%20%3D%20'block'%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20noQueries.textContent%20%3D%20'No%20search%20queries%20found.'%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20container.appendChild(noQueries)%3B%0A%20%20%20%20%20%20%20%20%7D%0A%0A%20%20%20%20%20%20%20%20%2F%2F%20Search%20Results%20section%0A%20%20%20%20%20%20%20%20const%20resultsHeading%20%3D%20doc.createElement('h2')%3B%0A%20%20%20%20%20%20%20%20resultsHeading.textContent%20%3D%20'%F0%9F%8C%90%20Search%20Results'%3B%0A%20%20%20%20%20%20%20%20container.appendChild(resultsHeading)%3B%0A%20%20%20%20%20%20%20%20if%20(results.length%20%3E%200)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20results.forEach(r%20%3D%3E%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20const%20item%20%3D%20doc.createElement('div')%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20item.className%20%3D%20'block'%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20item.innerHTML%20%3D%20%60%3Cstrong%3ETitle%3A%3C%2Fstrong%3E%20%24%7Br.title%20%7C%7C%20%22N%2FA%22%7D%3Cbr%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3Cstrong%3EURL%3A%3C%2Fstrong%3E%20%3Ca%20href%3D%22%24%7Br.url%7D%22%20target%3D%22_blank%22%3E%24%7Br.url%7D%3C%2Fa%3E%3Cbr%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3Cstrong%3ESnippet%3A%3C%2Fstrong%3E%20%24%7Br.snippet%20%7C%7C%20%22N%2FA%22%7D%60%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20container.appendChild(item)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D)%3B%0A%20%20%20%20%20%20%20%20%7D%20else%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20const%20noResults%20%3D%20doc.createElement('div')%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20noResults.className%20%3D%20'block'%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20noResults.textContent%20%3D%20'No%20search%20results%20found.'%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20container.appendChild(noResults)%3B%0A%20%20%20%20%20%20%20%20%7D%0A%0A%20%20%20%20%20%20%20%20doc.body.appendChild(container)%3B%20%2F%2F%20Append%20the%20main%20container%20to%20the%20body%0A%0A%20%20%20%20%20%20%20%20%2F*%20----------%20Clipboard%20Logic%20in%20new%20tab's%20context%20----------%20*%2F%0A%20%20%20%20%20%20%20%20%2F%2F%20This%20is%20the%20core%20logic%20from%20the%20%22working%22%20example%2C%20adapted%20for%20our%20data%0A%20%20%20%20%20%20%20%20clipboardBtn.addEventListener('click'%2C%20()%20%3D%3E%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20const%20textToCopy%20%3D%20%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22%F0%9F%92%AD%20Thoughts%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20thoughts.length%20%3E%200%20%3F%20thoughts.join(%22%5Cn%5Cn%22)%20%3A%20%22N%2FA%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22%F0%9F%94%8D%20Search%20Queries%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20queriesArr.length%20%3E%200%20%3F%20queriesArr.join(%22%5Cn%22)%20%3A%20%22N%2FA%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22%F0%9F%8C%90%20Search%20Results%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20results.length%20%3E%200%20%3F%20results.map(r%20%3D%3E%20%60Title%3A%20%24%7Br.title%20%7C%7C%20%22N%2FA%22%7D%5CnURL%3A%20%24%7Br.url%7D%5CnSnippet%3A%20%24%7Br.snippet%20%7C%7C%20%22N%2FA%22%7D%60).join(%22%5Cn%5Cn%22)%20%3A%20%22N%2FA%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%5D.join(%22%5Cn%22)%3B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%2F%2F%20Function%20to%20show%20toast%0A%20%20%20%20%20%20%20%20%20%20%20%20const%20showToast%20%3D%20()%20%3D%3E%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20toast.classList.add('show')%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20setTimeout(()%20%3D%3E%20toast.classList.remove('show')%2C%203000)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%3B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%2F%2F%20Clipboard%20write%20attempt%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20(navigator.clipboard%20%26%26%20navigator.clipboard.writeText)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20navigator.clipboard.writeText(textToCopy).then(()%20%3D%3E%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20showToast()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D).catch(err%20%3D%3E%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20console.error('Failed%20to%20copy%20using%20navigator.clipboard%3A'%2C%20err)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%2F%2F%20Fallback%20if%20modern%20API%20fails%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20const%20textArea%20%3D%20doc.createElement('textarea')%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20textArea.value%20%3D%20textToCopy%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20doc.body.appendChild(textArea)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20textArea.select()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20try%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20doc.execCommand('copy')%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20showToast()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%20catch%20(execErr)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20console.error('Fallback%20copy%20failed%3A'%2C%20execErr)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20alert('Could%20not%20copy%20to%20clipboard.%20Please%20copy%20manually%20from%20the%20page.')%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%20finally%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20doc.body.removeChild(textArea)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%20else%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%2F%2F%20Fallback%20for%20browsers%20without%20navigator.clipboard%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20const%20textArea%20%3D%20doc.createElement('textarea')%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20textArea.value%20%3D%20textToCopy%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20doc.body.appendChild(textArea)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20textArea.select()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20try%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20doc.execCommand('copy')%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20showToast()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%20catch%20(execErr)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20console.error('Fallback%20copy%20failed%3A'%2C%20execErr)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20alert('Could%20not%20copy%20to%20clipboard.%20Please%20copy%20manually%20from%20the%20page.')%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%20finally%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20doc.body.removeChild(textArea)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%7D)%3B%0A%0A%20%20%20%20%7D%20catch%20(e)%20%7B%0A%20%20%20%20%20%20%20%20alert(%22An%20unexpected%20error%20occurred%3A%20%22%20%2B%20e.message%20%2B%20%22.%20Check%20console%20for%20details.%22)%3B%0A%20%20%20%20%20%20%20%20console.error(%22Bookmarklet%20errosr%3A%22%2C%20e)%3B%0A%20%20%20%20%7D%0A%7D)()%3B%7D)()%3B


Our initial attempts to implement the “Copy All” functionality faced common browser security hurdles. Modern browsers are incredibly protective of clipboard access to prevent malicious scripts from copying sensitive user data. Especially within new windows opened by a bookmarklet, direct programmatic copy attempts often trigger security restrictions.

The key to overcoming this lay in a subtle but crucial change in how the new tab’s content was generated:

  • From document.write() to Programmatic DOM Construction: Initially, we injected the entire HTML content into the new window using window.document.write(). While convenient, this method can sometimes be treated with more suspicion by browser security. By contrast, the successful approach involved programmatically building the HTML document element by element using document.createElement() and document.appendChild(). This more “native” DOM manipulation seemed to establish a more trusted context for subsequent JavaScript actions, including clipboard access.
  • Layered Clipboard Strategy: We adopted a two-tiered approach for copying:
    1. Modern navigator.clipboard.writeText(): This is the preferred, asynchronous API for clipboard access. If the browser allows it, it’s efficient and clean.
    2. Classic document.execCommand('copy') Fallback: When navigator.clipboard is unavailable or fails due to security restrictions, this older method provides a reliable fallback. It works by temporarily creating a hidden <textarea> element, populating it with the text to be copied, selecting that text, and then executing the copy command. This simulates a user’s manual copy action, which browsers are more likely to permit.

By combining these strategies – building the DOM programmatically and using a robust, layered approach for clipboard operations – we’ve created a bookmarklet that not only extracts valuable insights from your ChatGPT conversations but also ensures that you can reliably copy that data for your needs.

Future Considerations

While this bookmarklet is powerful, it’s worth noting:

  • ChatGPT API Changes: As a third-party tool relying on internal ChatGPT APIs, future changes to OpenAI’s backend could potentially break the data extraction portion of the bookmarklet.
  • Browser Updates: Browser security policies are constantly evolving. What works today for clipboard access might require minor adjustments in the future.

Despite these possibilities, this bookmarklet remains a fantastic example of how a few lines of JavaScript can unlock hidden functionalities and streamline your workflow with web applications. Enjoy gaining deeper insights from your ChatGPT interactions!