Methodology
Each ranking and counting surface on this site follows a printed rule, stated where the number appears. This page collects those rules in one place - what each surface measures, how it is counted, and what it cannot prove - so a skeptical reader can check the site against its own claims. If the site's behaviour and this page ever disagree, one of them is wrong - tell us and we will fix it and say so.
The ranked block: "Most opened - last 7 days"
The ranked block at the top of the homepage orders listings by counted opens of each listing's outbound link. A counted open is a qualifying request to the signed outbound link on a listing's profile, recorded on our servers at the moment of the hop. The exclusions below are a counting rule: they remove the automated and self-inflicted traffic we can recognise, and they are not proof that a person viewed the destination. A request counts only when all of the following hold:
- At most one per visitor, per listing, per UTC day. The visitor is a one-way daily-rotating code derived from the connecting address with a key that changes every UTC day, so the same person opening the same listing five times in a day is one counted open, and visitors cannot be linked across days. No address, browser identification string, or referrer URL is stored on the event.
- Signed links only. The outbound link on each profile carries a signature our server issued. A hop on a link without a valid signature is recorded and disclosed, but never counted.
- Graded before counting. Requests with an empty or crawler-shaped user agent, our own operator traffic, test links, link prefetches, and non-GET requests are excluded before anything is counted, and the exclusion reason is stored on the event itself (the full vocabulary is in the click receipt below).
- Organic origin only. Every click event carries its origin on the row.
A click that arrived through a paid placement is stamped
sponsoredat the moment it is recorded, and the ranked block's query filters toorganic- so paid clicks are recorded separately and can never move this order. The separation is carried on each event row, not just in the interface.
The window is the last 7 UTC dates - today and the six before it. A listing appears in the ranked block only after it clears the printed floor: at least 3 counted opens spread over at least 2 of those UTC days. Below the floor, a catalogue listing stays in the daily rotation; a listing accepted after the catalogue was last built appears there once it is rebuilt. Ties are ordered by case-insensitive listing name, then by the listing's address on this site; given the per-listing counts - each listing's receipt publishes its own - the printed rule determines the exact order. The number is computed from the stored events at read time - there is no stored total anyone could quietly edit.
The ranked block and the daily rotation are also readable as data, with this rule and these
numbers in machine-readable form, at /api/v1/arena - one of the public reads
listed at /api/v1.
The daily rotation
Listings that have not cleared the ranking floor are reordered once per UTC day. Each row's place is a deterministic function of exactly two inputs: the UTC date, which the server prints on the page, and the row's own link. That means:
- Every visitor sees the same order all day - the order does not react to visits, clicks, or anything about you.
- Anyone can recompute the order: each row's key is FNV-1a (32-bit) over the printed
UTC date, a
|, and the row's own link, sorted ascending, ties by link. - A listing that moves up into the ranked block does not reshuffle the rows that stay, because each row's place depends only on its own link and the date.
- Without JavaScript, the order is alphabetical.
The rotation is pure display. Nothing about the visitor is read or recorded to produce it.
Paid placement
Paid placement is a separate, labelled surface: a fixed set of sponsor seats at fixed
public prices, the same for everyone, printed on the offer. A sponsored
seat is labelled as sponsored everywhere it appears, and sponsored links carry
rel="sponsored noopener noreferrer". A seat can only be bought for a listing
whose domain the buyer has proved they control.
Paid spend is never an input to any organic order. What a sponsor buys is the labelled placement and a public receipt of the clicks counted during its term - never a position in the ranked block, and never a promised quantity of clicks. Money can buy exposure; money cannot buy truth.
Every placement currently live is published in the machine-readable disclosure feed at
/api/placements: which seat, for which listing,
the term, and the published price. A seat given away without payment is disclosed there as
complimentary - it is still a labelled placement, but calling it sold would be untrue.
The click receipt
Every published listing has a public receipt of the traffic this site sent it:
/api/clicks/<listing>, and the same truth in a versioned envelope at
/api/v1/clicks/<listing>
(a live example). Every event is graded when it is
recorded, and the grade vocabulary is closed:
counted- a signed open that survived every exclusion below. The grade is stored per event, raw; deduplication to one per visitor, per listing, per UTC day happens when the totals are computed, so the per-grade event table can read higher than the deduped totals - both are published. Paid and unpaid counted clicks are reported as separate totals, never pooled.excluded_bot- the user agent was empty or matched known crawler patterns.excluded_operator- the request came from our own addresses.excluded_test- the link was marked as a test link.excluded_prefetch- a browser prefetch, preview, or prerender fetch, not a person following the link.excluded_method- not a plain GET request.excluded_unsigned- the link carried no valid server-issued signature. Recorded and disclosed, never counted.excluded_burst- the same visitor had a counted open less than two seconds earlier, on any listing. Two listings opened inside two seconds means nobody read either one. The first open of a burst still counts: one visitor is one signal, which is the honest reading of a sweep rather than zero.excluded_sweep- the same visitor already has counted opens on ten different listings today. This catches a sweeper that paces itself past the rule above.excluded_unchecked- the two checks above could not be run for this request. A check that did not run is not a check that passed, so the open is recorded and disclosed rather than counted.
The last three were added on 2026-08-28 after this site's own ledger was measured against them. One visitor took 31 distinct listings in 1.8 seconds on 2026-08-26, and another took 8 in 1.7 seconds on 2026-08-27; every other visitor that week opened one or two. Those two clients had built the entire ranked block. The old rule - one counted open per visitor, per listing, per UTC day - is exactly right for repeat visits to one listing and said nothing at all about one visitor touching every listing once. It is the failure this site exists to point at, found in our own numbers, and it is written here rather than fixed quietly. Counts recorded before that date were graded under the older rule and are not comparable with counts after it.
Deduplication is the same everywhere: at most one counted click per visitor, per listing, per UTC day. Each paid term on a receipt reports the clicks counted inside that term's own start and end - a link minted for a seat keeps working after the seat ends, and those later clicks are real, but they are not what the buyer paid for and are not attributed to the term. The versioned receipt publishes the full grade-by-origin table with explicit zeroes, so "no such traffic" and "not reported" can never be confused.
Movement receipts
When a counted, organic, signed open changes a listing's standing in the ranked block -
it clears the floor rule, or it moves up past another listing - a movement receipt is
written at that moment: a permanent page at /r/<number> and the same truth
in a versioned envelope at /api/v1/receipts/<number>. The receipt stores
what was true when it was minted - the listing's name, the position it left, the position it
reached, the listings it passed, its counted opens, the exact 7-day window, and the ranking
rule's version - and is never updated afterwards. A receipt is evidence of a moment, so it
must not follow later renames or recomputation.
What cannot mint one is as fixed as what can:
- Money cannot. Every attention event carries its surface of origin on the row
itself, and the ranking both sides of the receipt are computed from filters to
placement_origin = 'organic'in the query. A sponsored click can therefore never produce or influence a movement receipt - the same schema-level rule that keeps paid spend out of every unpaid count. - Excluded traffic cannot. An event graded as bot, operator, prefetch, unsigned or otherwise excluded changed no count, so there is no movement to evidence.
- The calendar cannot. The 7-day window slides once a day, and a listing can rise or fall when someone else's old opens age out. That movement is real but nobody caused it, so no receipt is minted for it - a receipt marks the counted open that moved a listing, not arithmetic doing its rounds.
Each receipt has its own link preview image at /og/r/<number>.png, and it is
the only image on this site that carries a number. Every other card here is forbidden from
carrying a position or a count, for a specific reason: once a platform has scraped a card, that
copy lives on the platform's servers and cannot be corrected, and a number that cannot be
corrected is not a checkable one. That rule bans numbers that decay. A receipt's numbers
cannot decay - the row is written once, and the image repeats a single past instant rather than
describing the present, so it is as true later as it was when it was made. The image is composed
when it is asked for, from the stored row only.
Receipts are minted only for upward movement, because the receipt is the moved listing's artifact: the event that made one listing pass another mints one receipt, which names the listings that were passed. A receipt about a listing that is later taken down stops resolving, like every other surface that would otherwise keep naming it. The events behind a receipt roll into the same hourly roots as every other count, so a receipt's arithmetic can be checked against the proof layer below.
Corrections
When a counting rule is found to be wrong, the events already recorded under it have to be put right, and there is exactly one way this site is allowed to do that: a correction is a new row, never an edit. The click ledger is append-only. That is the basis of every claim made here against other people's numbers, and a site that quietly rewrote its own history to look better would have given up the argument. So the original events stay exactly as they were recorded, and each correction is a separate, dated row naming the event it corrects, the reason, and the version of the rule that produced it.
Every counted surface on this site nets corrections out - the ranked block, each listing's receipt, the profile pages and the public API all read the same rule, so a corrected event cannot survive in one number while disappearing from another. A correction that later proves wrong is reversed by appending a reversal, not by removing anything, and the reversal is visible too.
A correction is a public event: it moves published numbers, so it appears in the build log with its date, its reason and how many events it covered. A movement receipt whose causing open was later corrected keeps every number it was written with - it is a true record of what this site counted at that instant - and says on its face that the ledger behind it has since been corrected.
The first correction, 2026-08-28. The sweep rules described above were applied backwards to the events recorded before they existed, and only those rules: the same two-second burst rule and ten-listing daily rule, replayed in time order against the older events. No case was judged individually, so the result can be recomputed by anyone with the same rule and the same events. It corrected the counted opens produced by the two sweeping clients, which had been the bulk of the traffic behind the ranked block.
The proof layer: hourly roots
The click ledger is append-only, but that is a promise about our own behaviour, and this
product exists because operator promises about traffic numbers are worthless. So each closed
UTC hour gets a Merkle root over that hour's aggregate counts, published at
/api/v1/roots. Roots are frozen lazily: a read of
the roots API computes every closed hour after the last stored root, oldest first, in bounded
batches - and once a root is stored, it is never updated. A root deleted from the middle is
not silently recomputed; the verifier's gap check is what exposes it.
The leaf, in one sentence: one leaf per (hour, listing, grade, origin, signed-flag)
combination with its event count, serialized as
hour|entity_id|grade|placement_origin|signed|count. Leaves are sorted by the
UTF-8 byte sequence of that string and hashed with SHA-256; pairs of digests are concatenated
and hashed up the tree; an odd node is promoted unchanged; an hour with no events has the
SHA-256 of the empty string as its root. The tree covers aggregate counts only - no
pseudonyms, no timestamps finer than the hour, nothing about any visitor. Excluded traffic is
in the tree as firmly as counted traffic, so reclassifying an event's exclusion reason after
the fact moves two leaf counts and changes the root.
To check an hour, read /api/v1/roots/<hour>: it returns the frozen root
beside the current leaf aggregates, which is enough to recompute the root from the response
alone. If a change since the freeze alters that hour's aggregate counts - an event edited
into a different grade or origin, inserted, or deleted - recomputation yields a different
value, and the mismatch is visible to anyone holding the published root. The tree commits to
those aggregates only, not to every field of every event: a rewrite that leaves every leaf
count intact is outside what a root can catch. We also maintain a standalone verifier - plain
Python, standard library only - that recomputes every stored hour written under the published
algorithm (a row claiming a different algorithm is reported, not judged) directly from a database
export and additionally checks that every event carries a well-formed hour, that no event
predates the first rooted hour, and that no hour between the first and last stored root is
missing a root.
Each stored root also carries an Ed25519 signature, made with a key that is never stored
in the database, over the string tl-roots-sig-v1|algo|hour|root|prev_root -
where prev_root is the previous stored hour's root, or the literal
genesis for the first. The public key, the message format, and each row's
signature and predecessor root are printed in the API responses. A root is signed once, at
the moment it is frozen, and never afterwards: there is no path anywhere in this site that
signs a root already stored, so a rewritten row cannot be handed back to the key for a fresh
signature. Because every signature binds its predecessor, the signed rows form a chain:
rewriting a stored root, deleting the first row, or deleting a row from the middle breaks a
signature that database access alone cannot re-create. Signing began at a fixed hour, printed
in the API as sig_signing_began_at_hour; every root from that hour on must carry
a signature, so removing signatures from recent rows fails verification rather than passing as
history that predates signing. The standalone verifier checks every signature and every link
against the public key, offline.
What this does not prove yet, stated plainly: the signing key lives in the worker, the worker signs whatever the freeze computes, and it remembers nothing outside the database. So an operator who deletes a run of the newest signed rows and lets the next freeze pass re-sign a rewritten tail produces a chain the verifier alone cannot fault. What the signature changes is what your own record is worth: any reader who saves one signed row holds proof, because we cannot later claim that row was never published - and since each signature binds the previous root, one saved row pins every hour up to it, not just its own. The verifier accepts such a recorded row and fails if the table no longer matches it. Closing the remaining seam without any reader's help means putting the roots somewhere we do not control, which is what the next section is.
External timestamps: every root into Bitcoin
A signature proves who wrote a root. It cannot prove when, and nothing inside a system its operator controls ever can - a log file in our own repository is a note to self. So every root is also timestamped by parties who have nothing to gain from our numbers, using OpenTimestamps: free public calendar servers that batch submissions together and commit the batch into a Bitcoin transaction. The resulting proof chains our root to a block header that thousands of unrelated machines already agree on. No account, no key and no payment is involved on our side.
What gets timestamped is not the bare root. Every hour with no events has the same root -
the SHA-256 of the empty string - so a proof over the bare value could not tell one empty
hour from another. The timestamped value is the SHA-256 of
tl-roots-anchor-v1|algo|hour| followed by the 32 raw bytes of the
root, followed by |prev_root. The proof file still begins with this hour's
published root, because the three steps that build that statement - prepend, append,
SHA-256 - are themselves OpenTimestamps operations, recorded ahead of the calendar's own.
Open a proof and the first 32 bytes are the root you read from the API, with the hour and
the predecessor root sitting right after it in readable ASCII.
A receipt is not an anchor, and we will not print it as one. A calendar answers a submission in milliseconds with a pending receipt: one server's promise that the value is queued. Only hours later does the batch reach a block. Four separate words are used and never blurred:
- unanchored - nothing on file for that hour.
- pending - a calendar receipt exists. Nobody has attested anything.
- attested - the operations reach a Bitcoin block header, but that header has not been corroborated on this run.
- anchored - the operations reach a Bitcoin block header whose height, block hash and Merkle root at least two independent public explorers agree on, at least six blocks deep.
What "anchored" proves, exactly: that some party committed to that exact statement - this root, under this hour, chained to this predecessor - no later than that Bitcoin block. It does not prove that the root was served publicly at the time, that it was frozen when its label says, or that the events underneath it are genuine. An operator who rewrote an hour before anchoring it would anchor the rewrite just as happily; the anchor's power is against changes made after a proof exists. And the block header is corroborated, not validated: we query public explorer APIs and require them to agree, we do not run a Bitcoin node and check the work. The honest label is Bitcoin-attested, corroborated by independent public explorer APIs; not locally node-verified.
The proofs are published as bytes, not as a status word:
/api/v1/roots/<hour>/anchors returns every stored proof for an hour, plus
the SHA-256 of the file it was copied from. Download one, run its operations from the root
the API published, and check the block yourself - you need nothing from us but the bytes.
Deliberately absent is a field saying "anchored: true": a flag written by the operator into
the operator's own database, read back out of that same database, would be our word about
our own honesty. The state the API returns is the calendar's word for what the
proof contains, not our verdict on it.
Our own nightly job fails if a root older than 36 hours has no receipt from at least two independent calendar operators - independent by operator, not by hostname, since one party can run several calendars - or if a receipt has still not reached a block after a week. A late anchor is recorded as late permanently: a catch-up run closes the gap, it does not undo the miss. Roots frozen before external timestamping began were anchored after the fact, and their proofs establish that the value existed no later than the attesting block, not that it was fixed at the close of the hour it names. Roots from then on are anchored on the schedule above.
Destination screening
Every published listing's registrable destination domain is screened against the URLhaus active hostfile - a public list of hosts currently distributing malware. Checks run when the operator reads or forces the screening state - there is no scheduler - in batches of up to 15: never-checked listings first, then listings whose domain changed since their last check, then oldest first. A listing becomes due again once its last check is older than 24 hours; due means eligible for the next batch, not checked at that instant. A domain is flagged when it is listed itself or when any listed host sits under it; the match never runs the wider way.
- Scope limit, stated up front: URLhaus's published policy excludes hosts on the Tranco Top-1M list of popular domains, so a mainstream domain will not appear in it, and the screening inherits the feed's coverage as it stands on the day of the check. This measures malware-distribution listings only - it is not a rating of every kind of bad destination, and a clean verdict is not an endorsement.
- An error is never clean. If the hostfile cannot be fetched, arrives truncated, or parses empty, every listing in that batch records an error verdict. A failed checker is a fact about the checker and must not look like a clean domain.
- Unchecked is not zero. A listing that has never been checked is reported as unchecked, never folded into the clean count. A listing whose domain changed since its last check counts as unchecked again - though a non-clean verdict on the old domain stays visible rather than vanishing with the edit.
- Flags are decided by a human. A flagged destination is surfaced for a person to act on. Nothing is unpublished automatically.
Which listings are offered to search engines
Not every published listing is handed to a search engine. A listing's profile is offered
for indexing, and appears in sitemap.xml, once it clears one of
three bars: a person put it in the seed catalogue, or its owner proved the domain and
claimed it, or it has earned at least one counted organic open. A listing that clears none
of them is served with noindex,follow and left out of the sitemap.
- It is not a takedown, and not a demotion. A listing below the line serves normally, keeps its address, keeps its outbound link, and keeps counting its own opens. It is simply not offered to search until it is worth someone's search result. It is still ranked, still filtered, and still reachable from the site exactly as before.
- It leaves the state by itself. The moment the listing is claimed, or a single counted organic open lands, the directive is gone and the profile is back in the sitemap on the next read. Nobody has to do anything, and nothing is asked of the owner.
- One open, not three. This is not the ranked block's rule and is not a popularity test - the ranked block needs three counted opens across two days. One open is the difference between a page a person has visited and a page no person ever has. It is counted the same way every number here is counted: signed, one per visitor per day, with operator, bot, test and prefetch traffic removed first, so it cannot be manufactured by requesting an address repeatedly.
- Why the seed catalogue counts. A rule of "claimed, or opened once"
on its own would be circular: a listing earns an open only after somebody finds it, and
search cannot be what finds it first. Every listing here on day one would sit behind
noindexpermanently. The seed catalogue was assembled and checked by a person against published import rules, and that is the evidence standing in for the open a brand-new listing has not yet had the opportunity to earn. - Why the line exists at all. A profile nobody has claimed and nobody has ever opened carries little a search result can use. Offering an unbounded number of them is what makes a site look like it is filling an index rather than serving readers. The homepage, this page, and every other page on the site are unaffected: none of them is ever gated on clicks or claims.
The launch gate: how visits to this site are counted
Whether this site gets built past its trial is decided by one number: 200 qualified sessions within 7 days of the launch being published. The threshold and the window were written down before any traffic arrived. A number decided afterwards is one you can negotiate with, so this one is stated here rather than reported later.
A qualified session is a distinct (UTC day, visitor) pair that survives every exclusion below and is confirmed by a same-origin request the rendered page makes for itself. The confirmation step exists because a request arriving is not the same as a page being shown to somebody. Visitors browsing with scripting turned off, and several people sharing one network address, are undercounted rather than overcounted - the error runs against the number that decides in our favour, deliberately.
Excluded before counting, with the reason stored on the event itself: recognised automated traffic, our own operator traffic, requests that are not a page load (HEAD requests and prefetches), and test traffic. Each exclusion reason is counted and reported separately, never silently dropped.
Counting starts when the launch is published, not when the site is deployed
A domain is announced to the public certificate transparency logs the moment it is issued a TLS certificate, and there are scanners watching those logs specifically to find new domains. Some of them send an ordinary browser identification string, so a filter that matches known crawler strings sees nothing unusual and counts them as people.
That is not hypothetical here. This site was reached four times by visitors that passed every filter, on 2026-08-24 between 08:01:33 and 08:12:41 UTC, before its launch had been announced anywhere and before a single person had been told it existed. Left alone, background noise like that accumulates: given enough pre-launch days a 200-session gate drifts toward passing on its own, and the trial would be "passed" by a test nobody took.
So the count does not start at deployment. It starts at an explicit publication moment: one record, written when the first launch post goes out, holding the time it went out. Every gate query filters to events at or after that time. Anything before it is reported separately as pre-publication noise and never enters the total. Before that record exists the gate does not report a number at all - it says in plain words that nothing has been published yet, because a number shown there would look like a result.
The excluded pre-publication count stays visible rather than being quietly discarded. Hiding it would be the same failure in a politer form.
The numbers described here are also printed where they are made: each listing's profile shows its own counted opens beside the signed outbound link, and the homepage states the ranked block's rule above the block itself. Questions, corrections, or a claim you think this page overstates: use the report page - an accepted notice gets a reference number and an answer-by date, and decisions on it are made by a person.