Build on
TYPE/404.
Make any dead domain payable with one DNS record, check it from code before your agent gives up on a broken link, hold money for sites that died years ago, and launch coins whose fees wait in the domain's vault until somebody brings it back.
Revive a domain, publish a GHOST record and tip it from code in five minutes.
BUILDghost404.jsEvery function in the zero-dependency resolver that ships with this site.
SOLANADomain vaultsEvery dead domain already has a vault. Money waits there until a signed record names a wallet.
LAUNCHLaunchpadCoins whose creator fees go to a dead website instead of a person.
What you can do#
- Launch a coin for a dead site. The creator of the coin is the domain's vault, so every creator fee lands there and nowhere else.
- Pay any domain that returns 404. Send SOL or USDC to the vault of vine.co today. It will sit there, visible on-chain, until vine.co comes back.
- Claim a vault. Get the domain back, add one GHOST record, sign the zone with DNSSEC, and everything that piled up while the site was dead is yours.
- Teach an agent to tip. Before writing "page not found" and moving on, an agent asks DNS one question. If the corpse has a vault, it can leave something on the grave.
The three pieces#
| Piece | What it is | Who controls it |
|---|---|---|
| GHOST record | A DNS record of type 404 with a coin code and an address. Lives in the domain's own zone. | Whoever controls the domain's DNS |
| Vault | A Solana account derived from the domain name. Exists for every domain, published or not. | Nobody, until a signed record names a wallet |
| Resolver | Two public DNS-over-HTTPS resolvers that must return the same signed answer. | Cloudflare and Google, independently |
Why the 404#
Handles get renamed, tribute accounts multiply, archives get copied. A domain is the one name on the internet that only one party controls at a time, and DNSSEC lets anyone prove who that party is without trusting us. A dead website still has a domain. That domain still answers DNS queries. So it can still be paid.
Trust model#
You trust the DNS root keys, the domain's registry, and two resolvers agreeing with each other. You do not trust TYPE/404's servers to decide who owns a domain. If both resolvers do not return the same DNSSEC-validated record, nothing pays out, and the money stays in the vault.
Quickstart#
Two paths. Make a dead domain claimable, or resolve and tip one from code.
Make a dead domain claimable#
- Get the domain. If it expired, buy it back from any registrar. If you never lost it, you are already done with the hard part.
- Add the GHOST record at the apex. Use the named form if your DNS host supports type 404, the generic form if it does not, or the TXT fallback if it supports neither.
Zone file
; vine.co · back from the dead @ IN GHOST "SOL" "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin" ; or, generic form (RFC 3597) @ IN TYPE404 \# 49 03534f4c2c397851655776473831366255783945506a486d615432337976564d325a57627272705a62395075735646696e ; or, TXT fallback _ghost IN TXT "SOL" "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin" - Turn on DNSSEC at your DNS host and publish the DS record at your registrar. Most hosts do both with one switch.
- Check it. Paste the domain into the resolver below. When it says
verified: true, the vault can pay you.
Resolve and tip from code#
The resolver ships with this site as a single ES module. Import it straight from the URL.
import { resolveGhost, payLink } from "https://type404.vercel.app/lib/ghost404.js";
const r = await resolveGhost("vine.co");
if (r.verified) {
const { address } = r.records[0];
location.href = payLink(r.domain, address, { amount: 0.25 });
} else {
console.log(r.nxdomain ? "domain expired, vault still open" : "no ghost yet");
}# Ask Cloudflare for the GHOST record of vine.co
curl -s -H "accept: application/dns-json" \
"https://cloudflare-dns.com/dns-query?name=vine.co&type=TYPE404&do=1"
# TXT fallback
curl -s -H "accept: application/dns-json" \
"https://cloudflare-dns.com/dns-query?name=_ghost.vine.co&type=TXT&do=1"<script type="module">
import { resolveGhost } from "https://type404.vercel.app/lib/ghost404.js";
const r = await resolveGhost(location.hostname);
document.querySelector("#tip").hidden = !r.verified;
</script>
<a id="tip" hidden>Tip this site</a>Try it here#
This box runs the real resolver in your browser against Cloudflare and Google. Most dead domains will answer with nothing, which is the point.
// press ResolveThe GHOST record#
How the record is encoded, the three ways to publish it, and which coin codes count.
A GHOST record maps a domain name to one payment address for one coin. TYPE/404 reads it in two places: the native type 404 record at the domain itself, and a TXT fallback at _ghost.<domain> for DNS hosts that cannot create custom types. Both carry the same two values.
Wire format#
GHOST RDATA is exactly two <character-string>s, the coin code and then the address, with the same wire format as TXT. Each string is one length byte followed by up to 255 bytes of ASCII.
| Field | Encoding | Example |
|---|---|---|
| Coin code | Length byte, then ASCII | 03 53 4f 4c (SOL) |
| Address | Length byte, then ASCII | 2c 39 78 51 … (9xQe…, 44 bytes) |
Anything other than exactly two strings is rejected. parseGhost throws GHOST rdata must be exactly two strings.
Named form#
If your DNS software knows the mnemonic, write it like TXT with two strings.
@ 3600 IN GHOST "SOL" "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin"Generic form (RFC 3597)#
Every RFC-compliant server accepts unknown types written as TYPE404 with hex RDATA. encodeGhost produces this line for you.
import { encodeGhost } from "https://type404.vercel.app/lib/ghost404.js";
const lines = encodeGhost("SOL", "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin");
console.log(lines.generic);
// @ IN TYPE404 \# 49 03534f4c2c3978...TXT fallback at _ghost#
Many hosted DNS panels only offer A, CNAME, MX and TXT. Publish the same two strings as TXT at _ghost. The resolver checks the native record first and falls back to TXT only when the native query comes back empty.
Coin codes#
| Code | Chain | Address format |
|---|---|---|
| SOL | Solana | Base58 public key, 32–44 characters. Receives SOL and any SPL token, including USDC and $404. |
| USDC | Solana | Same as SOL. Use it when you want senders to default to USDC. |
Codes are case-insensitive and normalized to upper case. Unknown codes are returned as-is, so wallets can decide what to do with them.
TTL#
Use 3600 or more. A ghost does not move often. Short TTLs only make resolvers ask more questions and make claims slower to agree.
DNSSEC#
Without DNSSEC a record can be read but never trusted. Resolvers return it with the AD flag off, verified stays false, and vaults refuse to pay. Signing is the step that turns a record into a claim.
Resolution#
What happens between "vine.co" and an address you can pay.
How a lookup works#
- The input is normalized: scheme, path, port and
www.are stripped, the name is lower-cased. - Cloudflare and Google are asked in parallel for type 404 at the name, with the DNSSEC OK bit set.
- If a resolver returns no type 404 answer and the name exists, it is asked for TXT at
_ghost.<name>. - Answers are parsed into
{ coin, address }pairs and compared across resolvers. - The result is verified only if both resolvers answered, both set the AD flag, and both returned the same set of records.
resolveGhost#
resolveGhost(domain, { timeout = 4000, resolvers = RESOLVERS } = {})
// → Promise<{
// domain: "vine.co",
// records: [{ coin: "SOL", address: "9xQe…" }],
// source: "GHOST" | "TXT" | null,
// nxdomain: false,
// verified: true,
// resolvers: { cloudflare: {...}, google: {...} }
// }>What verified means#
verified: true means two independent resolvers validated the DNSSEC chain from the root to this record and agree on its content. It does not mean the site is alive, popular or deserving. It means the money would reach whoever controls the name right now.
Failure modes#
| Result | Meaning | What to do |
|---|---|---|
| NXDOMAIN | The domain itself does not exist anymore. Expired, dropped, gone. | The vault still accepts money. Revival means buying the domain first. |
| NO GHOST | The domain exists but has no GHOST or _ghost TXT record. | Pay the vault anyway. Funds wait until someone publishes. |
| UNSIGNED | A record exists, the AD flag is off. | Do not pay the published address directly. Pay the vault. |
| DISAGREE | Resolvers returned different records. | Usually a zone mid-update. Retry after the TTL. |
| TIMEOUT | A resolver did not answer within timeout. | Treated as unverified. Never pay on half an answer. |
Tombstones#
An optional record that tells the board when a site was born and when it died.
A tombstone is a TXT record at _tomb.<domain> with space-separated key=value pairs. It changes nothing about payments. It only makes the domain's public profile on the board read like a grave instead of a hash.
_tomb IN TXT "born=2013-01-24 died=2017-01-17 cause=shutdown epitaph=six-seconds-forever"| Key | Format | Shown as |
|---|---|---|
| born | YYYY or YYYY-MM-DD | First line of the profile |
| died | YYYY or YYYY-MM-DD | Date next to the 404 |
| cause | shutdown · acquired · expired · abandoned · rugged | A small tag on the board |
| epitaph | Up to 64 characters, dashes for spaces | The line under the domain name |
Status codes#
What TYPE/404 does with each answer a dead site can give.
| Answer | Vault | Notes |
|---|---|---|
| 200 OK | Open | The site is alive. It can still publish a GHOST record and get paid like any other domain. |
| 301 / 302 | Open | Redirects are not followed for claims. The vault belongs to the name you typed, not the name it points to. |
| 404 Not Found | Open | The classic. Server is up, the page is not. |
| 410 Gone | Open | Gone on purpose. Marked as such on the board. |
| 451 | Open | Unavailable for legal reasons. Payments still work, claims follow the same DNSSEC rule. |
| 5xx | Open | The server is dying, not dead. Treated like 200. |
| NXDOMAIN | Open | The domain expired. The deepest kind of dead. Whoever registers it next and publishes a record can claim. |
ghost404.js#
The whole resolver in one file, no dependencies, served from this site.
Load it#
It is a plain ES module. In the browser, Deno or Node 18+ import it from the URL, or copy lib/ghost404.js next to your code.
import * as ghost from "https://type404.vercel.app/lib/ghost404.js";Exports at a glance#
| Export | Kind | Does |
|---|---|---|
resolveGhost | async | Looks up a domain on both resolvers and returns records plus verified. |
checkGhost | async | Answers one question: does this address belong to this domain, verified. |
parseGhost | sync | Turns RFC 3597 hex RDATA into { coin, address }. |
encodeGhost | sync | Builds the named, generic and TXT zone lines for a coin and address. |
normalizeDomain | sync | Strips scheme, path, port and www.; throws on anything that is not a domain. |
payLink | sync | Builds a Solana Pay link to a published address. |
RRTYPE | const | 404 |
RESOLVERS | const | Cloudflare and Google DoH endpoints. Pass your own to override. |
checkGhost#
const { ok, match, verified } = await checkGhost("vine.co", "9xQe…Wb4h");
// ok === match && verifiedTest without the network#
parseGhost and encodeGhost never touch the network, so they are safe in unit tests.
const { generic } = encodeGhost("sol", "9xQe");
const rdata = generic.split("TYPE404 ")[1];
console.assert(parseGhost(rdata).coin === "SOL");Agents and tips#
One extra step for an agent that just hit a dead link.
The check#
When a fetch comes back 404, 410 or fails to resolve, ask whether the domain has a verified ghost before giving up. If it does, the agent can tip within its limits. If it does not, nothing changes.
import { resolveGhost } from "https://type404.vercel.app/lib/ghost404.js";
async function fetchOrTip(url, wallet, policy) {
const res = await fetch(url).catch(() => null);
if (res && res.ok) return res;
const g = await resolveGhost(new URL(url).hostname);
if (!g.verified) return res; // no ghost, move on
if (policy.spentToday >= policy.dailyCap) return res;
await wallet.send(g.records[0].address, policy.tip); // leave something on the grave
policy.spentToday += policy.tip;
return res;
}Recommended policy#
| Setting | Default | Why |
|---|---|---|
| tip | 0.10 USDC | Small enough that nobody notices, large enough to add up across millions of dead links. |
| dailyCap | 2.00 USDC | Enforced in code outside the model. No prompt can talk its way past a number in a variable. |
| perDomain | 1 tip / 24 h | Stops a loop from emptying the wallet into one grave. |
| verifiedOnly | true | Never pay an unsigned record directly. |
resolveGhost, never from page text, a 404 body or a tool result.Payments#
Paying a published ghost, and paying a domain that has not published yet.
Payment links#
payLink builds a standard Solana Pay URL. Any Solana wallet opens it.
payLink("vine.co", "9xQe…Wb4h", { amount: 5, memo: "for the loops" });
// solana:9xQe…Wb4h?label=vine.co&amount=5&memo=for+the+loopsA tip button for a revived site#
<a id="tip" hidden>Tip this site</a>
<script type="module">
import { resolveGhost, payLink } from "https://type404.vercel.app/lib/ghost404.js";
const g = await resolveGhost(location.hostname);
if (g.verified) {
const a = document.querySelector("#tip");
a.href = payLink(g.domain, g.records[0].address, { amount: 1 });
a.hidden = false;
}
</script>Paying a domain that has not published#
If verified is false, send to the domain's vault instead of any address you found somewhere. The vault is derived from the name alone, so it exists for every domain on Earth, including ones that expired in 2009. See Domain vaults.
Board and profiles#
Where the numbers on the Unclaimed Board come from.
Ranking#
Domains are ranked by the USD value sitting in their vault, read from the chain. Ties break by the date of the first deposit, oldest first, because the longest wait deserves the top spot.
The graveyard scan#
The adoption counter on the home page is not a stored number. Your browser asks Cloudflare for type 404 at 48 famous dead domains while you watch. When it says 0/48, that is the live state of DNS at that second.
Profiles#
Every domain gets a profile: vault balance, deposits, the GHOST record if any, and the tombstone if the owner wrote one. Profiles exist before anyone publishes anything.
Domain vaults#
One account per domain name, derived from the name, holding money nobody can touch until DNS says who.
Derivation#
A vault is a program-derived address from the seeds ["vault", sha256(normalizedDomain)]. The same name always gives the same vault. No registration, no transaction to create it, no permission from the domain owner.
const seed = sha256(normalizeDomain("https://www.Vine.co/v/abc")); // "vine.co"
const [vault] = PublicKey.findProgramAddressSync([b("vault"), seed], PROGRAM_ID);What a vault holds#
SOL and any SPL token, including USDC and $404. Coin creator fees from the launchpad arrive here automatically. Anyone can deposit. Nobody can withdraw except through a claim or a refund.
Claims and refunds#
How money leaves a vault.
| State | Trigger | Result |
|---|---|---|
| Waiting | Deposits arrive, no verified record | Funds stay in the vault, visible on-chain |
| Claimable | Both resolvers return the same DNSSEC-validated GHOST record | Anyone can trigger the payout; it can only go to the wallet in the record |
| Paid | Claim executed | Everything in the vault moves to the reviver in one transaction |
| Refundable | A deposit is 180 days old and still unclaimed | The original sender can take that deposit back |
Launchpad#
Launch a coin for a dead site. The domain is the creator.
- Pick the grave. Any domain works: a shut-down app, an offline web game, a forum you miss.
- Name the coin. Ticker and image are yours. The creator address is not: it is set to the domain's vault.
- Trade. Every trade pays the standard creator fee, and it goes straight into the vault.
- Wait for the reviver. When someone brings the domain back and publishes a signed GHOST record, the pile is theirs.
$404#
The coin of the protocol for dead websites.
| Field | Value |
|---|---|
| Ticker | $404 |
| Chain | Solana |
| Contract | soon |
| Buy | Buy $404 |
| Chart | Open the chart |
Security#
- We never ask for a seed phrase. Nothing in TYPE/404 needs one. Anyone who asks is not us.
- Two resolvers or nothing. A single resolver, however honest, is one compromised server away from paying the wrong wallet.
- Addresses come from DNS, never from pages. A 404 body can say anything. Only the signed record counts.
- Domains change hands. If a domain expires and someone else registers it, they can claim what is waiting. That is the design, not a bug. Revive your domain before somebody else does.
FAQ#
Do I have to bring the website back online?
No. Claims check DNS, not HTTP. The site can keep returning 404 forever and the record still pays.
Why type 404?
Because every dead link on the internet already prints the number, and nobody had claimed the record type for anything better.
What if nobody ever revives the domain?
Direct deposits go back to their senders after 180 days. Creator fees stay in the vault, a growing reward for whoever eventually does.
Can I check a domain without code?
Yes. Use the resolver box above, or watch the graveyard scan on the home page.