A tiny piece of vanilla JavaScript, no dependencies, that keeps e-mail addresses away from spammers while staying clickable for humans.
Problem
Put your e-mail address on a website and robots will find it. They crawl the web around the clock, copying every address they see into spam lists that get sold and resold. Show it once, get spam and scam mail for years. So most sites hide behind contact forms, and real people who want to reach you give up halfway through.
Solution
safe-email lets you have it both ways. Your visitors get a normal e-mail link that opens their mail app with your address filled in. The robots find nothing to copy, because the address they’re hunting for is never actually on the page. Every e-mail link on this website goes through it, and has since 2020, so I keep it maintained by depending on it myself.
See it in action. Both panes below hold the same element:
The Disguise
Three layers, and the address never appears in plain text. Not in the source, not in the rendered page:
- Encoded in the markup. The HTML carries only an encoded attribute, so bots grepping page source for e-mail patterns find nothing.
- Obfuscated rendering. The library scrambles what it puts on the page, using different techniques like CSS tricks and hidden junk text. Your eyes see the correct address. A scraper reading the page gets what the demo above shows: reversed garbage with noise in every gap.
- No
mailto:anywhere. The link is assembled only at click time, from encoded pieces. Even themailto:prefix itself sits encoded inside the script.
None of these alone would stop a determined scraper. Stacked, they defeat the pattern matching that harvesters actually run, because scraping only pays when it’s cheap.
The Encoder
You need your address in its encoded form, so I built a small companion site: the
safe-email generator .
Type your e-mail, get the encoded value and a ready-to-paste snippet.
Instead of pulling in a framework for one input field, I wrote its reactivity myself: a hundred-line data binding built on a JavaScript Proxy, with mustache templates and data-if attributes.
Probably the smallest frontend framework I’ll ever ship, serving exactly one text box.