
Why obfuscate an email at all?
If you paste your email address directly into the HTML of a page, a basic scraper can often grab it with a simple regular expression. That does not mean every bot will succeed, but it does mean you are making the easiest version of the problem available.
A lightweight obfuscation pattern can reduce that exposure while keeping the address readable for real visitors. The goal is not perfect secrecy. The goal is to avoid publishing a plain, easy-to-match email string in your markup.
This is friction, not security. It helps against basic scrapers, not determined bots that execute JavaScript.
The idea
A practical approach is:
- Store the email as character code points instead of plain text
- Rebuild it in the browser with JavaScript
- Insert invisible word joiners between each character for display
- Copy the plain email to the clipboard when someone clicks it
To a person, the address looks normal. To many simpler scrapers scanning the raw HTML, it no longer appears as one clean email string.
The core logic
Here is the essential JavaScript:
const EMAIL_CODEPOINTS = [
104, 101, 108, 108, 111, 64, 101, 120, 97, 109, 112, 108, 101, 46, 99, 111, 109
];
const emailPlain = String.fromCharCode(...EMAIL_CODEPOINTS);
const WORD_JOINER = '\u2060';
const emailDisplay = emailPlain.split('').join(WORD_JOINER);
The important piece is \u2060, the word joiner character. It
is invisible to visitors, but it breaks up the exact email pattern in the
rendered text.
A full Svelte component example
If you are using SvelteKit, this gives you a copyable button that shows the obfuscated address visually but copies the clean version to the clipboard.
<script lang="ts">
import { onDestroy } from 'svelte';
const EMAIL_CODEPOINTS = [
104, 101, 108, 108, 111, 64, 101, 120, 97, 109, 112, 108, 101, 46, 99, 111, 109
];
const contactEmailPlain = String.fromCharCode(...EMAIL_CODEPOINTS);
const WORD_JOINER = '\u2060';
const contactEmailDisplay = contactEmailPlain.split('').join(WORD_JOINER);
let copied = $state(false);
let copyTimer: ReturnType<typeof setTimeout> | null = null;
async function copyEmail() {
try {
if (navigator?.clipboard?.writeText) {
await navigator.clipboard.writeText(contactEmailPlain);
} else {
const textarea = document.createElement('textarea');
textarea.value = contactEmailPlain;
textarea.style.position = 'fixed';
textarea.style.left = '-9999px';
textarea.style.top = '0';
document.body.appendChild(textarea);
textarea.select();
document.execCommand('copy');
document.body.removeChild(textarea);
}
copied = true;
if (copyTimer) clearTimeout(copyTimer);
copyTimer = setTimeout(() => {
copied = false;
copyTimer = null;
}, 1600);
} catch {
// no-op
}
}
onDestroy(() => {
if (copyTimer) clearTimeout(copyTimer);
});
</script>
<button
type="button"
onclick={copyEmail}
class="inline-flex items-center rounded-full border px-4 py-2 text-sm"
aria-label="Copy email address"
>
{contactEmailDisplay}
</button>
{#if copied}
<p class="mt-2 text-sm text-muted-foreground">Email copied.</p>
{/if}Why this works better than a plain mailto link
A direct mailto:hello@example.com link puts the plain address
right back into the DOM. If your goal is obfuscation, that weakens the
strategy immediately.
A copy button is usually the cleaner tradeoff. Visitors still get the address with one click, but you avoid publishing the raw string in a simple attribute value.
What this does not protect against
This will not stop advanced bots that render JavaScript, inspect the live DOM, or simulate user interaction. If your address is especially sensitive, use a contact form, server-side filtering, or both.
- Good for reducing low-effort scraping
- Good for keeping the UI simple
- Not a replacement for spam filtering
- Not a privacy guarantee
Final thought
Email obfuscation is one of those small frontend details that is worth doing when you want to stay accessible to humans without being overly convenient for bots. Keep the real address out of the initial HTML, rebuild it in the browser, and let users copy it cleanly.
Want more practical frontend patterns?
Browse the tools and articles library for more clear, implementation-first advice.
Free resources, checklists, and templates