Creem.io
Merchant of record payments for SaaS and digital products, handling checkout, subscriptions, taxes, invoices, and global payment operations.
Sponsor this newsletter · reach 9,500+ active developers
Your readers already paste your articles into AI chats. They want a summary, a version of your code for their stack, or an answer to the question your article almost covered. So they select the page, copy, paste.
What the AI gets is a mess: menu links, “Copy” button labels, line numbers glued to the code, and prose and code mashed together with no clear edges. Docs sites have started fixing this with a “Copy for AI” button that hands over a clean Markdown version of the page instead. You can add one in about 30 lines.
The fix #
Walk the article and turn each element into its Markdown equivalent:
function toMarkdown(node) {
if (node.nodeType === Node.TEXT_NODE) {
return node.parentNode.closest('p, li, h1, h2, h3') ? node.textContent.replace(/\s+/g, ' ') : '';
}
if (node.nodeType !== Node.ELEMENT_NODE || node.matches('button, nav, script, style, [data-no-copy]')) return '';
const inner = [...node.childNodes].map(toMarkdown).join('');
const text = inner.trim();
switch (node.tagName) {
case 'H1': return `# ${text}\n\n`;
case 'H2': return `## ${text}\n\n`;
case 'H3': return `### ${text}\n\n`;
case 'P': return `${text}\n\n`;
case 'UL': case 'OL': return `${inner}\n`;
case 'LI': return `- ${text}\n`;
case 'STRONG': return `**${text}**`;
case 'EM': return `_${text}_`;
case 'A': return `[${text}](${node.href})`;
case 'CODE': return `\`${node.textContent}\``;
case 'PRE': {
const lang = node.querySelector('code')?.className.match(/language-(\w+)/)?.[1] ?? '';
return `\`\`\`${lang}\n${node.textContent.trim()}\n\`\`\`\n\n`;
}
default: return inner;
}
}
Then copy it on click, with the page URL on top so the AI can point back to the source:
copyButton.addEventListener('click', async () => {
const markdown = toMarkdown(document.querySelector('article')).trim();
await navigator.clipboard.writeText(`Source: ${location.href}\n\n${markdown}`);
copyButton.textContent = 'Copied!';
});
This post has the button. Click “Copy for AI” next to the date at the top, paste it into any AI chat or text editor, and compare it with a plain select-and-copy of the same page.
What the converter handles #
- Headings, paragraphs, lists: become
#, plain text, and-items. - Links: keep their full URL, because
node.hrefis always absolute. Relative links would be useless outside your site. - Code blocks: become fenced blocks, and the
language-jsclass most syntax highlighters add becomes the fence’s language. Inlinecodekeeps its backticks. - Noise: buttons, navigation, scripts and styles are skipped. Anything else you want left out, like a newsletter signup box in the middle of the article, gets a
data-no-copyattribute. - Whitespace: text outside paragraphs, list items and headings is dropped. That is almost always the indentation of your HTML, which would otherwise end up as stray spaces.
It is not a full HTML-to-Markdown converter. Tables, images and nested lists are not covered. Add a case when your content needs one: it is one line each.
Why not just give them the URL? #
Some AI tools can open a link. Many cannot, some get blocked by the site, and some read a cached copy from months ago. Pasted text always works, and it is exactly what the reader is looking at right now.
Markdown is also the format models handle best. A heading is one # instead of a wrapper of classes, and code fences mark exactly where code starts and ends, so the model stops mixing your explanation into your code.
Where this comes up #
- Tutorials and blog posts: “rewrite this for my framework” is the most common thing readers do with them.
- Documentation: developers paste docs pages into their coding assistant to get help on your API.
- Changelogs and release notes: “what changed that affects me?”
- Long policies and guides: support articles, terms, onboarding checklists.
Why this matters #
- Readers are already doing it: the button only decides whether the AI gets your content clean or garbled.
- Better answers about your content: clean structure means fewer wrong explanations of your code.
- It works everywhere: the Clipboard API is supported in every modern browser. It needs HTTPS and a click, which a button already gives you.
If you like where this is going, my issue on letting AI agents use your site with 3 HTML attributes covers the other side: agents using your features, not just reading your content. And if you’d rather offer one button for every app, the native share button is four lines.
Put the button next to your article’s title and paste the result into an AI chat. You will see the difference in the first answer.
Happy coding!
Marko