Privacy

What we see, and what we don’t.

LinxMax is short links, link trees, hosted pages, webrings, guestbooks, hit counters, polls, and status pills. This page describes everything the servers record about a visitor. Last updated: 2026-09-11.

Who we are

LinxMax is built and operated by Spergs, LLC, a Florida limited liability company. Reach us at privacy@spergs.com for anything privacy-related, or to point out something on this page that isn't accurate.

We don't sell, rent, or trade data, and we don't run ads. That isn't going to change.

The short version

If you visit a short URL or a link tree we increment a counter and write a timestamp. That row has no IP, no User-Agent, and no identifier of any kind in it — it is literally a mapping ID and a clock reading. We set no cookies on the redirect.

If you vote in a poll we store a salted hash of your IP address so the same visitor can't vote twice. We never write the raw IP to the database. See "About the IP hash" below, which is specific about what that does and doesn't protect.

If you load a hit counter it depends on which of two modes the owner chose, and the difference runs the opposite way to how it sounds. A unique-visitor counter stores a salted hash of your IP so a refresh doesn't inflate it. An every-load counter stores nothing about you at all — telling visitors apart is the only reason a hash is ever kept, so a counter that counts every load has nothing to remember. The counter that records less is the one that counts more.

If you sign a guestbook we store what you typed — name, optional URL, message — plus the same salted IP hash, which lets the owner see that several pending messages came from one submitter. Guestbook entries are published publicly on the owner's site once the owner approves them. Don't put anything in a guestbook you wouldn't post in public.

If you create or manage short URLs (via the web app, CLI, or REST API), the server stores the mapping you created. That's a row in our Postgres database with the slug, target, optional campaign label, and timestamps.

If you join a webring or run one, we store the public-facing membership (site name, URL, status) in the database. There's no email, no password, no private account; ring owners moderate the same shared rows.

If you create or manage widgets (banners, counters, polls, status pills, link trees), we store the widget and its content. Those are yours, authored by you, and gated behind an API key.

What we collect

URL mappings

  • The short slug, the target URL, an optional campaign label, created/updated timestamps, and a hit counter.
  • No per-visit data: no IP, no User-Agent, no Referer, no fingerprint.

Link trees

  • The page's title, bio, avatar URL, theme, and its ordered list of links.
  • A click count per link. Clicks are counted in aggregate — the click row carries no visitor data.

Hosted pages

  • The page's title, tagline, theme, background image, and its ordered list of blocks — the headings, text, images and HTML the owner wrote.
  • A view count. It is a plain tally with no per-visitor ledger behind it — unlike a unique-visitor counter, a page view writes nothing that could tell one visitor from another, so there is no hash and no row about you.
  • An unpublished page is not visible to anyone but its owner; it answers as "not found", exactly as a page that never existed would.

Webring rosters

  • For each ring: its name, description, owner name + URL, and a list of member sites (name, URL, approval status).
  • Join requests carry the same fields plus a generated ID and a "pending" status until the ring owner approves.
  • A pending request is not shown publicly — not on the ring page and not in the ring's API response — until it is approved. Only the ring's moderator sees it.

Guestbook entries — the one place we store content you wrote

  • The author name, optional author URL, and message body you submitted, plus a timestamp and a moderation status.
  • A salted hash of the submitting IP. Never the raw IP.
  • The operator's moderation queue uses that hash to show which pending messages came from the same submitter, so a run of spam can be rejected as one. What the queue displays is a position in the list — "submitter A, 3 in queue" — computed fresh for each view; the hash itself is not sent to it and nothing links one view to another.
  • Entries sit pending and invisible until the guestbook's owner approves them. Approved entries are public.
  • The IP hash is never returned by any API response or rendered in any widget. It stays in the database; only the grouping described above is derived from it.

Hit counters and polls

  • Counters, unique-visitor mode (the default): a row of (counter, salted IP hash, date) so one visitor counts once per day. The visible number is a count of those rows, not of page loads.
  • Counters, every-load mode: no per-visitor row at all. The visible number is a plain tally the server increments; nothing is written that could distinguish one visitor from another, or one visit from the next. There is no ledger to keep, prune or reset.
  • Polls: a row of (poll, salted IP hash, chosen option) so one visitor votes once. This one is permanent — it has to be, or the dedup stops working.
  • That same row is how the widget knows to show you results instead of the form: when it loads, the server checks whether your salted IP hash already has a vote in that poll and answers with the results if so. It says only that a vote exists from your address, never which option — the row is per address, not per person, so everyone sharing one (a household, an office) sees the results once any of them has voted. Nothing is stored in your browser. Until 2026-09-11 the widget kept a localStorage key instead, which is why a fresh browser used to show the form again; that key is no longer set or read, and one left over from before does nothing.

Status pills and banner strips

  • Owner-authored content only — the status text and emoji, or the badge images and their link targets. Loading one records nothing about the visitor.

Reverse-proxy access logs

  • The nginx in front of the LNX servers writes its standard combined access log. That line contains your IP address, the timestamp, the request line, the status code, the response size, the Referer, and the User-Agent.
  • This is the one place a raw IP address is written down. Everywhere else — counter dedup, poll dedup, guestbook grouping — we store only a salted hash. The access log is the exception, it is a plain server log rather than a feature, and it is worth knowing about rather than burying: while that log is kept there is a file on our server with your address and what you requested in it.
  • They are rotated and aged out by the host's standard logrotate policy, and we don't join them to any account, mapping, hash or database row. They exist for troubleshooting. We deliberately don't quote a number of days here: log rotation is the machine's policy rather than something this application configures, so a figure on this page would be one we can't promise stays true.

What we don't collect

  • No accounts on LinxMax (today). There's nothing to sign up for; the app is single-tenant.
  • No cookies, anywhere — not on the marketing site, not on the app, not in any embedded widget — and, since 2026-09-11, no localStorage or other browser storage in anything a visitor loads either. (The one user of browser storage is the operator's own admin panel, which keeps its API key there.)
  • No raw IP addresses in the database. Where we need to tell visitors apart — counter dedup, poll dedup, guestbook abuse — we store a salted hash and never the address itself.
  • No analytics, behavioural tracking, Sentry, or third-party advertising pixels. There is no SDK on the page that phones home.
  • No User-Agent, Referer, or device fingerprinting stored against any hit, click, vote, or entry.
  • No cross-widget or cross-site correlation. Counters, polls and guestbooks each hash under a different label, so the same visitor's counter hash, poll hash and guestbook hash are three unrelated values and none of the ledgers can be joined to another. This was not true until 2026-09-04 — counters and polls shared a salt because they share a server, and we said so here for the two days between noticing and fixing it. Moving to a secret salt the same day invalidated the rest of the stored values, so the dedup ledgers were emptied rather than left holding fingerprints that can never match again; the visible counter totals and poll tallies are kept in their own columns and did not change.
  • No contact-book or address-book sync. There's no concept of contacts.
  • No fonts, scripts, or analytics from third-party CDNs on the marketing site. One decorative animated GIF in the footer is hotlinked from x.allcdn.net; loading it discloses your IP and User-Agent to that host, as any hotlinked image would. Nothing else on this site is third-party.

About the IP hash

Three features need to tell one visitor from another without knowing who they are: the hit counter in unique-visitor mode (count you once a day), the poll (let you vote once), and the guestbook (spot someone submitting spam fifty times). All three do it the same way — we take your IP, add a secret salt, hash it, and store only the result. Each of the three mixes in a different label, so the three values for one visitor are unrelated and no ledger can be matched against another. A hit counter in every-load mode is not on this list, because it never needs to tell you apart from anyone.

Being straight with you about what that does and doesn't mean. The salt is a random secret, generated on our own server the first time it is set up, kept in a root-owned file outside the database, and never sent anywhere. The hash is SHA-256. That combination is what makes a leaked database dump useless on its own: the space of possible IP addresses is small enough to test exhaustively — a few minutes of one computer — so a fingerprint salted with a value anyone could look up would be reversible no matter how good the hash was. Until 2026-09-04 ours was exactly that: a fixed string compiled into the server, which anyone reading the source knew. It isn't any more, and we'd rather say what changed than quietly improve.

What it still does not mean is that the value is anonymous in a strong technical sense. Someone who holds both the database and our server's configuration can test the address space against these values, and no amount of hashing changes that — the input is short, and we have to be able to recompute it on every request for dedup to work at all. So treat the protection as "your address is not in the table, and the table alone won't give it up", which is real, and not as "nobody could ever work it out", which would be false. We treat these values as pseudonymous personal data, not as anonymised data, and we don't publish them, export them, or return them from any API.

Practical consequence worth knowing: dedup is per-IP, so people sharing an address — an office, a school, a phone carrier's NAT — look to a counter or a poll like one visitor. The first person to vote from your network votes for it. We'd rather say this plainly than quietly overcount.

Third parties

The marketing site's footer hotlinks a small decorative animated GIF from x.allcdn.net. Your browser fetches it directly, which tells that host your IP address and User-Agent the same way any hotlinked image would. It sets no cookie and runs no script. It is the only asset on this site not served from linxmax.net.

Otherwise the only third party in the loop is our hosting vendor. Our servers run on a virtual private server hosted in the United Kingdom. Standard hosting operations involve the vendor having physical access to the underlying hardware. They do not have credentialed access to our service.

When a short URL targets an external site (e.g. you set /gh → https://github.com/...), the visitor's browser follows our 302 redirect to that external site, which has its own privacy policy. We have nothing to do with what happens after the redirect.

Where data lives

On our servers (United Kingdom):

  • A single Postgres database. The tables that can hold anything about a visitor are:
  • mappings + mapping_hits — short URLs and their hit timestamps. No visitor data.
  • link_trees + link_tree_items — hosted link pages and per-link click totals. No visitor data.
  • webrings + webring_sites — rings and their membership rosters, as submitted.
  • guestbooks — the guestbook itself: its name and description, written by its owner. No visitor data.
  • guestbook_entriesvisitor-written content, plus a salted IP hash.
  • counter_hits — (counter, salted IP hash, date). Dedup ledger.
  • poll_votes — (poll, salted IP hash, option). Dedup ledger, permanent.
  • pages + page_blocks — hosted pages, their authored blocks, and a plain view tally. No visitor data.
  • banners, banner_sets, banner_set_items, polls, poll_options, counters, status_widgets — owner-authored content only. (poll_options holds the answer labels and their running vote totals; the totals are aggregate counts, with nothing in them about who voted.)
  • previewsnot owner-authored: the title, description, preview image and favicon our server fetches from the site a short URL points at, cached so the link preview doesn't re-scrape on every view. It is third-party content about a third-party page, gathered by us rather than written by us. No visitor data — the fetch is made by our server, not by your browser, and nothing about who requested it is stored.
  • Nginx access logs, rotated and aged out by the host's standard logrotate policy.

If you're outside the UK, using LinxMax means your request metadata transits to and rests on our UK servers. The contents of your short links are public by design; there's no private payload being transferred.

Retention & deletion

  • URL mappings and link trees live until you delete them via the app, CLI, or API. Deleting one removes its hit and click rows with it.
  • Hosted pages live until their owner deletes them. Deleting a page removes its blocks with it. There is no per-visitor row to remove, because none is written.
  • Webring members stay listed until the ring owner removes them.
  • Guestbook entries live until the guestbook's owner rejects or deletes them, or until we remove one on request. Deleting the guestbook deletes its entries and their IP hashes.
  • Counter dedup rows exist only for counters in unique-visitor mode. They are cleared whenever the owner resets the counter, and switching a counter to every-load mode stops new ones being written. Absent a reset they are currently kept indefinitely; a periodic prune of old rows is planned and not yet built, and we'd rather say so than imply a retention window we don't enforce.
  • Poll vote rows are kept for the life of the poll by design — that record is the only thing preventing a second vote. Deleting the poll deletes them.
  • Nginx access logs are rotated and aged out by the host's standard logrotate policy. They are not kept indefinitely, and we'd rather say that than name a window we don't set.

Your rights

Because LinxMax today is a single-tenant deploy without per-user accounts, there isn't a per-user dataset to export in the usual sense. What there can be is something you submitted: a webring join request or a guestbook entry. Email privacy@spergs.com and we'll remove either one within 30 days — whether or not it's been approved, and without asking you to justify it. Tell us roughly where and when you posted so we can find it.

We won't look you up by IP — and the word is "won't", not "can't". We hold the salt, so given an address we can compute its hash and search on it. That is a promise about what we do, not a limit on what we are able to do, and "About the IP hash" above is specific about the difference. Asking you where and when you posted is us finding your entry the way we're willing to find it.

You can also ask for a copy of what's associated with you (the join request row, or your guestbook entries). We won't hand over an IP hash — it isn't meaningful to you and disclosing it would only weaken it.

If you're in the UK and aren't happy with how we've handled a data request, you can complain to the Information Commissioner's Office (ICO). EU/EEA users can complain to their national data protection authority.

Our terms say disputes are governed by Florida law, and we don't read that as taking the paragraph above away from you. The two cover different things: Florida law is about a disagreement between you and us over the agreement itself, and a complaint to a data protection authority about data sitting on our UK servers is a right you have rather than something we granted you in the terms. We would rather name both than let a governing-law clause quietly imply the other one is gone.

Minors

LinxMax is for adults. Our terms of service require you to be at least 18 years old. We don't knowingly collect data from anyone under 18; if you believe we have, email privacy@spergs.com and we'll delete it.

Changes to this policy

If something material changes (e.g. we add accounts, or hit counters start carrying per-visit data), we'll update the "Last updated" date at the top and call the change out on this page. We won't make changes that surprise existing users.

Contact

Spergs, LLC
privacy@spergs.com

Also worth reading

The terms, in plain English

Acceptable use, what is deliberately not promised, and how disputes work.