A minimal, refined link shortener where users enter "magic words" instead of cryptic codes.
Live: magicword.val.run
Traditional link shorteners produce URLs like bit.ly/3xK7m2Q — functional but forgettable. Magic Word reimagines this as a human-first experience:
Traditional: brand.com/promo?code=xK7m2&utm_source=twitter&utm_medium=...
Magic Word: "The magic word is SUMMER" → redirects to your campaign
The interface is radically minimal: a single text input asking "What is the magic word?" Nothing else. Enter a word, get redirected. That's it.
- Marketing campaigns: "Use magic word FREEBIE for 20% off"
- Event access: "The magic word for the afterparty is VELVET"
- Memorable branded links: Share "crystal-beacon" instead of a 50-character URL
- Easter eggs: Hide content behind discoverable words
The same input field handles everything:
| Input | Action |
|---|---|
summer | Look up magic word → redirect |
please | Open create/management UI |
a] | Verify admin key → edit/delete UI |
| Tier | Format | Example | Price |
|---|---|---|---|
| Free | Two-word compound | crystal-beacon, amber-grove | £0 |
| Premium | Single dictionary word | summer, free, win | £12/year |
Free-tier compounds are surprisingly brandable ("thundercat", "moonpie") while keeping the namespace virtually unlimited (~576 combinations from current word lists).
Every lookup requires a proof-of-work computation, preventing enumeration attacks:
- Page load → client receives a PoW challenge (nonce + difficulty)
- User enters word → client computes
SHA-256(nonce:word:counter)until hash has N leading zeros - Submit → server verifies proof is valid AND challenge hasn't been used before
- One-time use → challenge marked as consumed, preventing replay
Why this works:
- Scraping 10,000 words requires 10,000× the computation (~500ms each = 83 minutes)
- Legitimate users experience a brief "working..." delay (acceptable UX)
- No CAPTCHAs, no user accounts, no friction
- Difficulty is tunable (currently 4 leading zeros ≈ 200-500ms)
Each magic word gets a UUID admin key on creation. This key:
- Is shown exactly once (on creation)
- Allows editing the destination URL
- Allows deleting the word
- Can be shared with teammates
- Requires no account or authentication system
┌─────────────────────────────────────────────────────────┐
│ Val.town Edge │
│ ┌─────────────────────────────────────────────────┐ │
│ │ main.tsx (HTTP handler) │ │
│ │ - Serves HTML UI with embedded challenge │ │
│ │ - API routes for CRUD + PoW verification │ │
│ │ - Server-side React rendering │ │
│ └─────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────┐ │
│ │ Val.town SQLite │ │
│ │ - magic_words table (word, url, admin_key_hash)│ │
│ │ - pow_challenges table (one-time use tokens) │ │
│ └─────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────┘
│
Client-side PoW computation
(SHA-256 in browser, ~200-500ms)
CREATE TABLE magic_words (
id INTEGER PRIMARY KEY AUTOINCREMENT,
word TEXT UNIQUE NOT NULL, -- "summer" or "crystal-beacon"
url TEXT NOT NULL, -- destination URL
admin_key_hash TEXT NOT NULL, -- SHA-256 hash of admin UUID
tier TEXT NOT NULL, -- "free" or "premium"
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
expires_at DATETIME, -- NULL for free tier
redirect_count INTEGER DEFAULT 0 -- analytics
);
CREATE TABLE pow_challenges (
id TEXT PRIMARY KEY, -- UUID
nonce TEXT NOT NULL, -- random string for PoW
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
used BOOLEAN DEFAULT FALSE -- one-time use enforcement
);
| Method | Path | Purpose |
|---|---|---|
GET | / | Serve HTML UI with fresh PoW challenge |
GET | /api/challenge | Issue new PoW challenge |
POST | /api/lookup | Look up word (requires PoW proof) |
POST | /api/create | Create new magic word |
POST | /api/verify-admin | Verify admin key, return word details |
PUT | /api/update | Update URL (requires admin key) |
DELETE | /api/delete | Delete word (requires admin key) |
- Runtime: Val.town (Deno-based serverless)
- Database: Val.town SQLite (Turso/libSQL)
- Frontend: Server-rendered React, vanilla JS for interactions
- Fonts: Crimson Pro (serif) + JetBrains Mono (monospace)
- PoW: SHA-256 via Web Crypto API
It's a delightful easter egg that teaches the interface paradigm. The small cost (one reserved word) is worth the whimsy. Users remember it.
Single words are valuable namespace ("free", "win", "sale") and should be monetized. Compound words like "crystal-beacon" or "amber-grove" are:
- Still memorable and brandable
- Virtually unlimited namespace
- No squatting concerns
- Actually quite pleasant to say aloud
Rate limits can be bypassed with distributed IPs or slow enumeration. PoW makes enumeration economically infeasible regardless of how it's distributed. The computation cost is fundamental, not infrastructural.
- Stateless and simple
- No email/password management
- No password reset flows
- Single-purpose access tokens
- Easy to share (give key to a teammate)
- Works offline (no session to expire)
The magic word IS the link. You share the word, not a URL. "The magic word is SUMMER" is the entire instruction. The URL is just magicword.info (or wherever it's hosted).
- Custom domains:
yourbrand.com/magic→ magic word lookup - QR codes: Generate QR that encodes the magic word
- Analytics dashboard: Redirect counts, referrers, geography
- Expiry warnings: Email before premium words expire
- API keys: Programmatic management for integrations
- Bulk creation: CSV upload for campaigns
- A/B destinations: Rotate URLs for testing
- Time-based redirects: Different URLs by time of day
- Marketplace: Buy/sell/transfer premium words
- Teams: Shared admin access with roles
- Webhooks: Notify on redirect events
- Custom PoW difficulty: Per-word anti-abuse settings
This is a single-file Val.town project. To modify:
- Edit
main.tsxin the Val.town web editor - Changes deploy instantly
- Database persists across deployments
To run locally (if extracted):
# Would require Deno + SQLite setup # Val.town handles all this automatically deno run --allow-net --allow-env main.tsx
Built with Val.town — serverless TypeScript with built-in SQLite.
Inspired by the elegance of promo codes and the frustration of ugly URLs.
MIT — do whatever you want with it.