Engineering

Building an Anonymous Message Link System: The Architecture Decisions That Matter

Personal anonymous message links look simple on the surface. The engineering decisions underneath especially around identity severance and metadata handling determine whether the anonymity promise is real or performative.

K

Kwame Osei

Full-Stack Developer

8 min read

A personal anonymous message link is a deceptively simple product to describe: someone gets a URL, shares it, and anonymous messages appear in their inbox. The implementation that makes this work without compromising sender anonymity is considerably less simple and the differences between a careful implementation and a careless one are invisible to users until something goes wrong.

Where Anonymity Actually Lives (and Dies)

The most common mistake in anonymous messaging systems is treating anonymity as a front-end property rather than a back-end one. You can build a submission form that collects no name, displays no user information, and gives no indication of sender identity to the recipient and still have a back-end that logs the sender's IP address on every request, making it trivial to identify who sent what to whom through server log analysis.

Genuine anonymity requires that no persistent record connecting a message to a sender exists anywhere in the system. This means the server-side request handler must explicitly discard the sender's IP before writing the message to the database. It means access logs, if they exist at all, must not be correlated with message records. And it means the database schema must make it structurally impossible to link a message back to request metadata not just policy-level impossible, but architecturally impossible.

The Route Handler Pattern for Identity Severance

In a Next.js application, the correct pattern for anonymous message submission involves receiving the request, immediately extracting only the message content and the recipient token, and passing only those values to the database write function. The request object which contains the sender's IP, headers, and user agent should never be passed to any function that touches the database. The separation must be explicit in the code, not assumed from the database write not including those fields.

If you are using a Cloudflare Worker for the submission endpoint, the same principle applies. The worker receives the full request, extracts only the content and token from the JSON body, and writes only those values. The sender's IP is available in the request object throughout the worker's execution the discipline of not using it is the only thing standing between claimed anonymity and actual anonymity.

Rate Limiting Without Identity Records

Every anonymous submission endpoint needs rate limiting to prevent spam floods. The standard approach tracking submissions by IP address creates exactly the identity record that anonymity requires avoiding. The solution is ephemeral, hash-based rate limiting: hash the sender's IP using a short-lived key that changes every hour or so, use the hash as the rate-limit bucket key, and discard the hash after the rate limit window expires.

The hash cannot be reversed to recover the IP, the key rotation means hashes from different windows are not correlated, and the expiry means no permanent record exists. This provides functionally adequate spam protection while maintaining the structural commitment to not storing sender identity data. Cloudflare Workers KV with a short TTL is an ideal storage backend for this pattern.

The Inbox Side: Recipient Privacy

Anonymous messaging is not only about protecting senders. Recipients also have privacy interests that system design should respect. A recipient's inbox contains sensitive information the honest things the people around them think. It should not be accessible to third parties, and the recipient should have genuine, immediate control over its contents.

This means the inbox must be behind authentication, messages must be retrievable only by the authenticated recipient, and the delete function must execute a hard deletion rather than a soft one. It also means the platform should not use inbox content for any purpose other than delivering it to the recipient no analysis, no content targeting, no data retention after deletion.

Testing Your Own Anonymity Claims

If you are building a system that promises anonymity, the most important engineering task is adversarial self-testing: assume you are a bad actor with full database access and full server log access, and ask whether you could identify who sent a specific message. If you can through any combination of timing, IP logs, request metadata, or database correlation then the anonymity promise is false, regardless of what the privacy policy says. Fix the architecture before the policy.

#engineering#anonymous links#privacy architecture#Next.js#Cloudflare
K

Written by Kwame Osei

Full-Stack Developer · AnonLink Social Research Team