A small widget to display on websites so people can contact you. Includes contact obfuscation so scrapping bots cannot copy your email or telegram (at least the not clever ones).
Created as a Web Component: Best for any website - Hugo, Jekyll, WordPress, plain HTML, or even React/Vue.
Made by Rémi Valade · 𝕏
Works anywhere with a single <script> tag.
- Shadow DOM encapsulation - No CSS conflicts with your site
- Glassmorphism effect - Blur + transparency
- Shine animation - Sweep effect on the CTA button
- Contact obfuscation - Email and Telegram handles are not exposed in HTML
- Auto source tracking - Automatically detects hostname for analytics
- Dark mode - Auto-detects system preference or set manually
<!-- Include the script (in head or before </body>) -->
<script src="path/to/made-by-widget.js"></script>
<!-- Use the component -->
<made-by-widget
name="Jane"
subtitle="Designer & Developer"
photo="https://your-server.com/photo.jpg"
linkedin="janedoe"
twitter="janedoe"
tg="amFuZWRvZQ=="
email-u="amFuZS5kb2U="
email-d="ZXhhbXBsZS5jb20="
></made-by-widget>| Attribute | Default | Description |
|---|---|---|
name |
"JaneDoe" | Display name in greeting |
subtitle |
"Cool human who likes shiny buttons" | Tagline text |
label |
"Let's talk" | Text shown in collapsed state |
photo |
(relative to script) | Profile image URL (see below) |
linkedin |
- | LinkedIn username |
twitter |
- | X/Twitter username |
tg |
- | Telegram handle (base64 encoded) |
email-u |
- | Email username part (base64 encoded) |
email-d |
- | Email domain part (base64 encoded) |
cta-text |
"Send an email" | CTA button text |
source |
(auto: hostname) | Custom source for tracking |
dark |
(auto-detects) | Force dark mode |
The widget automatically matches your site's theme using this detection order:
darkattribute on the widget — if set, the widget is always dark, no auto-detectiondata-themeon<html>— if your site setsdata-theme="dark"ordata-theme="light"on the<html>element, the widget follows itclass="dark"on<html>— if your site uses Tailwind's default dark mode (adding/removing thedarkclass on<html>), the widget follows it- OS preference — falls back to
prefers-color-scheme: dark
The widget watches for changes live via a MutationObserver, so toggling your site's theme will update the widget instantly — no page reload needed.
Examples:
<!-- Always dark -->
<made-by-widget dark></made-by-widget>
<!-- Auto-detect (works with data-theme or class="dark" on <html>) -->
<made-by-widget></made-by-widget>If your site uses a different attribute for theming (e.g. data-mode or data-color-scheme), you would need to adapt the widget's setupDarkMode() function.
If no photo attribute is provided, the widget looks for an image file named remi-valade-square.jpg next to the JS file. You can handle the photo in two ways:
Option A: Self-host alongside the script
Place your image in the same directory as made-by-widget.js. It will be resolved automatically.
your-server.com/widgets/made-by-widget.js
your-server.com/widgets/your-photo.jpg
Option B: Host anywhere and pass the URL
Host the image wherever you like (your server, Cloudflare Images, Imgur, etc.) and pass the URL as an attribute:
<made-by-widget
photo="https://wherever.com/your-photo.jpg"
...
></made-by-widget>Sensitive contact info uses base64 encoding to prevent bot scraping. To encode your values, open your browser console and run:
btoa('janedoe') // → "amFuZWRvZQ==" (for tg)
btoa('jane.doe') // → "amFuZS5kb2U=" (for email-u)
btoa('example.com') // → "ZXhhbXBsZS5jb20=" (for email-d)Or use the command line:
echo -n "janedoe" | base64If you need to change your email or Telegram handle later:
-
Encode the new value using one of the methods above:
btoa('new.email') // → "bmV3LmVtYWls" btoa('newdomain.com') // → "bmV3ZG9tYWluLmNvbQ=="
-
Update the attributes in your HTML wherever the widget is used:
<made-by-widget ... email-u="bmV3LmVtYWls" email-d="bmV3ZG9tYWluLmNvbQ==" ></made-by-widget>
-
To decode and verify an existing value:
atob('amFuZWRvZQ==') // → "janedoe"
<!-- In layouts/partials/footer.html or layouts/_default/baseof.html -->
<script src="{{ "js/made-by-widget.js" | relURL }}"></script>
<made-by-widget
name="Jane"
photo="/images/photo.jpg"
linkedin="janedoe"
twitter="janedoe"
tg="amFuZWRvZQ=="
email-u="amFuZS5kb2U="
email-d="ZXhhbXBsZS5jb20="
source="hugo-blog"
></made-by-widget>- Copy
made-by-widget.jsto your static assets folder - Optionally place your photo in the same folder (or pass a
photoURL) - Reference it with a
<script>tag - Add the
<made-by-widget>element anywhere in your HTML
Host the JS file on any CDN (jsDelivr, unpkg, Cloudflare, your own server) and reference it from all your sites:
<script src="https://your-cdn.com/made-by-widget.js"></script>Email and Telegram handles use base64 encoding to prevent bot scraping:
- Values are stored as encoded strings (e.g.,
tg="amFuZWRvZQ==") - Bots scanning for patterns like
@gmail.comort.me/won't find them - The component decodes values only when the user clicks
- Not cryptographically secure, but stops 99% of automated scrapers