Helpers — Naming & Lookups
The small utility procedures — registrable-apex and public-suffix tests, top-ASN ranking, and Tor and TLS-fingerprint lookups — each with the exact YIELD column names, because today you cannot write one without guessing.
On this page (6)
Helpers — Naming & Lookups Documentation
Beyond the investigation and identity procedures, WhisperGraph ships a handful of small utilities — the naming, ranking, and lookup calls you reach for inside a larger query. None of them need a deep traversal; each answers one focused question. Every YIELD column named below came from a live call on 2026-08-09, so you can write the YIELD clause without guessing.
Public-suffix functions
The PSL functions apply the Public Suffix List so you can find the registrable apex of a hostname or test whether a label is itself a public suffix. They are the reliable way to reduce a messy hostname to the domain you actually want to anchor on.
CALL whisper.psl.tldPlusOne("mail.google.co.uk") YIELD apex RETURN apex
| Function | Argument | Yields | Returns |
|---|---|---|---|
whisper.psl.tldPlusOne(host) | a hostname | apex | the registrable apex (mail.google.co.uk → google.co.uk) |
whisper.psl.isPublicSuffix(label) | a label | result | true if the label is itself a public suffix |
whisper.psl.affiliation(host) | exactly one host | found, suffix, submitterLogin, submitterOrg, evidenceKind, confidence | the affiliation group for the host |
whisper.psl.affiliation() takes exactly one argument; passing more returns a 400. Use tldPlusOne before an anchored lookup when your input might be a subdomain — anchoring on the apex is usually what you want.
whisper.topAsnsByPrefixCount(n)
Rank the autonomous systems announcing the most prefixes — a quick way to find the largest networks without scanning the ASN label.
CALL whisper.topAsnsByPrefixCount(10) YIELD asn, prefixCount
RETURN asn, prefixCount ORDER BY prefixCount DESC
Tor & TLS-fingerprint lookups
Two direct lookups return the full record behind a Tor exit IP or a known TLS fingerprint, without composing the underlying edges yourself.
CALL whisper.lookupTorRelay("185.220.101.1") YIELD indicator, found
RETURN indicator, found
| Procedure | Argument | Yields | Answers |
|---|---|---|---|
whisper.lookupTorRelay(ip) | an IP | indicator, found, fingerprint, exitAddresses, exitAddressCount, exitAddressesV6, exitAddressCountV6, source, ingestedAt | the full Tor relay record for an exit IP |
whisper.lookupTlsFingerprint(fingerprint) | a JA3/JARM fingerprint (ja3: or jarm: prefixed) | indicator, found, kind, hash, category, label, family, vendor, client, trustTier, sourceCount, firstSeen, lastSeen, licensePosture | the record for that TLS fingerprint |
Both return found: false rather than zero rows when they have nothing, so the absence is always a populated row you can branch on.
TLS-fingerprint coverage is partial. Expect most indicators to return nothing. A zero-row result here means Whisper holds no observation — not that the host shares no infrastructure.
whisper.search(token)
When a token arrives unclassified — it could be an IP, hostname, ASN, CIDR, prefix, or suffix — whisper.search runs a bounded, type-aware lookup instead of an unanchored scan. It works out what the token is and looks it up as that node type, so it stays fast where a label-wide scan would run away.
CALL whisper.search("185.220.101.1")
YIELD query, kind, name, matchedField, matchType
RETURN query, kind, name, matchedField, matchType
kind is the label it decided on (IPV4 here; HOSTNAME, ASN, and PREFIX are the others you will see), and matchType says whether the token hit a node exactly or was widened to find one. The procedure also declares a warning column, which stays empty on an exact hit and fills in when the lookup had to widen — prefix_expansion when a partial hostname was extended to a real one, for instance. Yield the columns you intend to read.
Once you know what the token is, anchor on it directly — whisper.search is the entry point, not the traversal.
whisper.version()
The liveness check. It reports the engine build answering your request, and it is the first thing to run when the graph is behaving oddly — a version string proves you reached the engine rather than something in front of it.
CALL whisper.version() YIELD version, buildTime RETURN version, buildTime
Sample output (measured 2026-08-09):
[{"version": "<version>", "buildTime": "<iso-8601 timestamp>"}]
Quote the version when you report a problem: engine behaviour differs between builds, and the first question anyone will ask is which one you hit. CALL whisper.quota() is the companion call that tells you whether the server recognised your key at all.
Schema introspection
The db.* calls describe the live schema, and they are cheap — they answer immediately: db.labels(), db.relationshipTypes(), db.propertyKeys(), and db.schema(). db.schema() also accepts a format argument — db.schema('json'), db.schema('markdown'), or db.schema('details') — and db.schema.nodeTypeProperties() / db.schema.relTypeProperties() list the properties on each label and edge type. They are covered on the Graph Schema pages and in the Procedures overview.