Tested in Blink and WebKit.

Which browsers, and when · How all of this works

geodzkdocs

reading plane · What this is, what it keeps, and how to drive it without a browser.

Getting started

From an invitation to a link on a poster.

You need an account, and accounts here are made by the person who runs the box — there is no open sign-up unless they have turned it on. What arrives is an invitation link that works once.

Setting up

  • Open the invitation, pick the name you want to sign in with, and set a pass phrase of at least 12 characters.
  • Your name is also your namespace, so choose one you are happy to see on the front of every link you make. It can be changed later, with a wait between changes, and the old one is never given to anybody else.
  • Set up a six-digit code from an app on your phone. Keep the ten backup codes it shows you: there is no email address on file here, so those codes are the way back in if the phone goes.
  • Add a passkey afterwards if the device supports one. It is one step instead of two, and a passkey that asks for a fingerprint or a PIN is already two factors on its own.
  • The Appearance button (top right) also has Color vision: Protanopia, Deuteranopia and Tritanopia each swap the state colors, and the link color where it would clash, for a set tuned and tested for that type. Every state also has a word or a shape, so nothing depends on color alone. Like the theme, it is kept in this browser only.
  • Appearance → Cursor: the pointer is drawn in your theme's colors. Tick Use the system cursor to keep your own, which also keeps your operating system's pointer size and color settings. High contrast, e-ink, Windows High Contrast and touch screens always use the system cursor.

Paste a URL into Target URL on the dashboard and press Shorten. You get back https://geodzk.com/l/your-name/something, copied to the clipboard and ready to send. Leave Code empty for a short random one, or type your own.

curl -s -X POST https://geodzk.com/api/links \
  -H "X-API-Key: $GEODZK_KEY" -H 'Content-Type: application/json' \
  -d '{"url":"https://example.com/hello","code":"hello"}'

Codes, and why they never come back

  • A code is one to sixty-four characters of A-Za-z0-9_-. Omit it and you get a random one of 5 characters.
  • Delete a link and its code is retired, not freed. That address will never point at anything again, for you or for anybody else — because the old one may be on a poster somebody still has.
  • So never delete a link to tidy up. Retarget it instead, or let it expire.
  • If you want a retired code, you can ask the operator to release it, and they can. Nobody else can take it in the meantime.
  • The bare space at https://geodzk.com/l/code belongs to the operator. Short, memorable top-level codes are held from the start so they stay available for the service's own use rather than going to whoever asked first.
FieldEffect
titleA label for your own list. Never shown to a visitor.
group_idPut it in one of your groups, which is what a collection is made of.
active_fromNot live until then. Before that it answers as if it does not exist.
expires_atDead after then.
max_clicksWorks a set number of times, then stops. If the count cannot be written, it is held back rather than served.
fallback_urlWhere an expired or used-up link goes instead of a dead end. Worth setting on anything printed.

Channels are the one way to learn where a link's visits come from without learning anything about the visitors. Register tags with PUT /api/links/{code}/channels — poster, sheet, newsletter — and put one in the address you hand out: …/l/alice/party?via=poster. Each visit is counted against the tag. Nothing is read from the visitor; the tag names the poster, never the scanner. A tag nobody registered counts nothing, so a stranger cannot invent one. /print/l/{code}?via=poster puts the tag into the printed QR so a whole print run is counted as one channel.

When a link is followed is kept as 168 counters — weekday × hour, UTC — bumped at the click; no timestamp is written and the click's own second goes no further than that statement. GET /api/links/{code}/when releases them only above thresholds: nothing at all under 20 visits, and any cell under 3 as few rather than a number, because a cell of one is a person when you know who you handed the link to. The dashboard draws it as the field's own nodes. Beside it, readings: what those counters can say in a line each — quiet since, weekday share, busiest hours, how each printed tag did, refusals on a capped link — arithmetic under the same thresholds, nothing stored to produce it. ?further=1 computes the guesses (the crowd's time zone, which tag is ahead as ranges, next week from the average) only when asked; each refuses below its own floor and says in words that it is about everyone at once and never anyone.

None of these say whether a code ever existed, who owned it, or why it stopped. The recipient's next step is the same in every case, which is to go back to whoever sent it.

SituationThe page says
Never a link hereThat link doesn't exist
Deleted by its ownerThat link has been retired
Held by the operatorThat one is taken
Past its expiryThat link has expired
Used up its clicksThat link has been used up
Turned off by an administratorThat link has been turned off

Your ceilings

Every account has a quota, and the dashboard shows where you are against it. Nought means no limit, never none allowed.

CeilingDefaultSet by
Links per account500dashboard, and per account
Groups per account25dashboard, and per account
Links shown on one collection500environment
Live API keys per account20environment
Keys an account may ever mint100environment
Passkeys per account10environment
Accounts on the instance100dashboard
Links on the instance50,000dashboard
Masked links on the instance5,000environment
Target URL length2,048 charactersenvironment
Code length5 random, up to 64 chosenenvironment
Session lifetime14 daysenvironment
Invitation lifetime14 daysper invitation
Wait between username changes90 daysenvironment
Shortest password12 charactersenvironment

Back to top

The same page as text, for a program: GET https://geodzk.com/api/docs/start — needs a key holding docs:read.

Sign in · geodzk.com