How it works
This is an ordinary web app that you can open from an X post. Sign in with your X account, leave an optional message, and add your name to a shared guestbook.
The trick: an X Player Card
When you share guestbook.stupidtech.net, X reads metadata in the page’s HTML. The metadata describes a preview image and a 480 × 480 player page:
<meta name="twitter:card" content="player" />
<meta name="twitter:image"
content="https://guestbook.stupidtech.net/card.png" />
<meta name="twitter:player"
content="https://guestbook.stupidtech.net/play/poc-1" />
<meta name="twitter:player:width" content="480" />
<meta name="twitter:player:height" content="480" />
Player Cards normally contain audio or video. Here, the player page contains the guestbook instead. The metadata is served by the backend, so X can discover it without running JavaScript.
Why it looks different on mobile
On x.com, the player can run in an iframe inside the post. The native X app opens it in a fullscreen web viewer. In the native app, you may need to open the post’s detail view before its Player Card preview appears.
X controls this presentation. The same guestbook also works as a normal page when you open its link directly.
Signing in with X
Being inside an X post does not tell this app who you are. To verify your identity, the guestbook uses X’s OAuth 2.0 authorization flow with PKCE. You authorize through X, and the backend retrieves your account ID, username, display name, and profile image.
The requested scopes are tweet.read and users.read, which X
requires for the profile lookup. The app uses the access token on the backend to retrieve
your profile; it does not send that token to the guestbook page or use it as your guestbook
session.
Inside an iframe, sign-in opens in a separate tab and the card checks the backend for completion. In a fullscreen viewer or a normal browser page, sign-in happens in the same view and automatically returns you to the original book.
The launch link is prepared before you tap. Pending sign-in credentials are saved in session storage so the app can resume after navigation. Each attempt expires after ten minutes, and the launch and polling credentials are separate.
What a signature contains
Signatures are public. Each entry contains the verified profile, an optional message of up to 280 characters, and the signing time. There is one signature per X account per book; signing again updates your entry rather than adding a duplicate.
You can read recent signatures before signing in. The list refreshes periodically and shows relative timestamps.
Remembering your sign-in
After authorization, the backend issues a separate guestbook session that lasts up to 30 days. The browser stores its session token locally, and the backend stores a hash of that token. Sign out revokes the session; your public signature remains in the book.
Standalone sign-in needs writable session storage to restore the pending attempt after returning from X. If that storage is unavailable, the page explains the problem before starting navigation.
Under the hood
The frontend uses vanilla TypeScript and Vite. A Hono app runs on Cloudflare Workers, with Cloudflare D1 storing signatures, sign-in attempts, and sessions. The backend validates requests and accepts signatures only from verified sessions.
Iframe context, referrers, and incoming messages are not treated as proof of identity. Authentication comes from the completed OAuth flow.