The Form Fill Is a Lagging Indicator
In B2B, the demo request arrives at the end of the story. By the time someone types their work email into your form, a group of colleagues has usually already read your pricing page, compared you to alternatives, and argued about you in a meeting you'll never see. Most B2B visitor identification tools respond to this by looking your visitors up in a third-party IP-to-company database — someone else's data, of unknown age, matched by methods you can't inspect.
ClickStream takes a different approach: it clusters the anonymous visitors you already have, inside your own tenant of the identity graph, using only your own first-party traffic. Two shipped features do this work — household clustering (migration 0008 of the identity graph schema) and workplace clustering (migration 0009). This essay walks through exactly how both work, including the parts where the system deliberately refuses to draw conclusions.
Household Clustering: One Hashed IP, One Tenant
A household cluster is the simplest environmental grouping in the graph: visitors whose events arrive from the same network egress. The graph never stores the IP address itself — the cluster is keyed on a hash:
-- migrations/0008_household_clustering_edge_ttl.sql (abridged)
CREATE TABLE IF NOT EXISTS household_nodes (
id TEXT PRIMARY KEY, -- UUID
ip_hash TEXT NOT NULL, -- HMAC or SHA-256 hashed IP
tenant_id TEXT NOT NULL, -- Tenant scope
connection_type TEXT DEFAULT 'unknown', -- residential, business, mobile, hosting
member_count INTEGER DEFAULT 0,
confidence REAL DEFAULT 0.6, -- Household confidence (decays with age)
expires_at INTEGER, -- 30-day TTL from last activity
UNIQUE(ip_hash, tenant_id)
);
Three properties of this table are load-bearing:
- The IP is hashed before it becomes a key. The clustering logic operates on
ip_hash, an HMAC or SHA-256 digest — the household table has no raw-IP column to leak. - Not every connection qualifies. The graph maintains an explicit exclusion list, and any connection classified as VPN, hosting, proxy, or Tor never forms a household. A VPN egress point or a datacenter IP would otherwise manufacture fake "households" out of thousands of strangers.
- Membership is a probability, not a verdict. A visitor's link to a household starts at 0.5 confidence and climbs by 0.05 per repeat observation, capped at 0.9. The system never reaches certainty from an IP alone, by construction.
The exclusion list is one line in the graph service, and it reads exactly like you'd hope:
// apps/identity-graph/src/services/graph.ts
const EXCLUDED_CONNECTION_TYPES = new Set(['hosting', 'vpn', 'proxy', 'tor']);
For B2B2C products — where a business sells through to consumers — the household is the natural unit of decision-making: the family plan researched on two phones and a laptop, the insurance quote one partner starts and the other finishes. Household clustering lets you see that these sessions belong to one decision, without ever claiming they belong to one person.
Workplace Clustering: Geohash, ASN, and Business Hours
Workplaces need a stricter definition than households, because office buildings share networks with the café downstairs and coworking floors churn tenants. The workplace cluster is keyed on three things at once:
-- migrations/0009_geo_location_workplace_clustering.sql (abridged)
CREATE TABLE IF NOT EXISTS workplace_nodes (
id TEXT PRIMARY KEY,
geohash TEXT NOT NULL, -- Precision 7 for tight clustering
tenant_id TEXT NOT NULL,
asn INTEGER,
as_organization TEXT,
member_count INTEGER DEFAULT 0,
confidence REAL DEFAULT 0.4,
expires_at INTEGER, -- 60-day TTL (longer than household)
UNIQUE(geohash, tenant_id, asn)
);
Unpacking the key:
- Precision-7 geohash — a cell of roughly 153 × 153 meters. That's a building or a small block, not a neighborhood. (The graph also keeps precision-6 cells, roughly 1.2 km × 0.6 km, for broader proximity matching — but those never define a workplace.)
- ASN — the autonomous system number of the network the traffic arrives from. Two companies in the same building on different networks form different clusters.
- Business hours only. An observation feeds workplace clustering only if it lands between 9am and 5pm on a weekday in the visitor's local timezone. The same coordinates at 11pm on a Saturday build no workplace edge at all.
Confidence is tuned even more conservatively than for households: a member link starts at 0.3 and grows by just 0.03 per business-hours observation, capped at 0.85. The workplace node itself starts at 0.4 and gains 0.05 per distinct member, with the same 0.85 ceiling. It takes sustained, repeated, weekday-daytime activity from multiple people before the graph treats a location as a workplace with any conviction — and it never becomes fully convinced.
What a Cluster Buys You Before the Form Fill
Now the B2B payoff. When several distinct visitors cluster in the same precision-7 cell on the same ASN, during business hours, across multiple weeks — that is what a buying committee looks like in first-party data. You can see that a group at one location is reading your integration docs, returning to pricing, and comparing plans, while each member is still individually anonymous. Combined with per-visitor intent and frustration scores from the Signals API, that turns "some traffic from somewhere" into "a team somewhere is evaluating us, and they're accelerating."
Two honest limits, stated plainly:
- The
as_organizationfield names the network operator, not necessarily the employer. When an office egresses through its own corporate network, the AS organization is often the company itself. When it sits behind a generic business ISP, the field names the ISP. The cluster still tells you a group of people at one location on one network; it does not, by itself, tell you which company — and ClickStream won't pretend otherwise. - We don't quote match rates or coverage percentages for clustering, here or anywhere. Cluster formation depends on your traffic, your visitors' networks, and their consent choices. Any vendor quoting you a universal number for this is describing their marketing, not your site.
The cluster becomes dramatically more useful the moment any one member stops being anonymous. When one person on the team signs up, logs in via a social login, or fills the form, their person node gains a deterministic anchor — and every other member of that workplace cluster is now context around a named account. That promotion path, including its consent gates, is its own essay: from anonymous visitor to CRM contact, the compliant path.
The Guardrail: Environmental Signals Never Merge People
Here is the part that makes the feature trustworthy rather than creepy. Sharing a household or a workplace is evidence about an environment, not about a person — and the graph enforces that distinction structurally. The merge logic that folds two person nodes into one accepts only deterministic keys: hashed emails and phone numbers, tenant-scoped customer and account IDs, and authenticated social-login subjects. A shared mobile ad ID can trigger a merge only with independent corroboration, because family members share tablets. Household membership, IP hashes, and geohashes are not on the list at all. They cannot merge people, no matter how strong the co-occurrence looks.
| Signal | Confidence Weight | Can It Merge Two People? |
|---|---|---|
Hashed email (hem / hmac_hem) |
0.30 | Yes — deterministic anchor |
| Social-login subject (Google, Facebook, Apple, LinkedIn) | 0.25 | Yes — deterministic anchor |
| Customer / account ID | 0.20 | Yes — tenant-scoped deterministic anchor |
| Mobile ad ID (MAID) | 0.10 | Only with independent corroboration |
| Device fingerprint | 0.08 | No — corroborating evidence only |
| Postal code | 0.06 | Never |
| Geohash | 0.05 | Never |
| Metro code | 0.04 | Never |
| Timezone | 0.03 | Never |
The weights tell the same story from another angle: a geohash contributes 0.05 to a person's resolution confidence where a hashed email contributes 0.30. Environmental signals season the profile; they never define it. This is the same philosophy behind the graph's confidence bands — the strength of a claim is pinned to the strength of its evidence.
There's one subtle case worth spelling out. When two nodes look like merge candidates because they're geographically close, the graph demands corroboration that is independent of geography — specifically a shared high-confidence device fingerprint. Shared postal codes, timezones, and metro codes are explicitly rejected as corroboration, because the reasoning would be circular: the candidate pair exists precisely because the two nodes are near each other. The source comment says it plainly — accepting shared geography as its own proof "merges strangers who happen to share a metro." Colleagues in one office stay separate people in the graph until real person-level evidence says otherwise.
Per-Tenant Isolation: Your Clusters Are Yours
Look back at the two unique constraints: UNIQUE(ip_hash, tenant_id) for households and UNIQUE(geohash, tenant_id, asn) for workplaces. The tenant ID is inside the key. The same office building visiting two different ClickStream customers produces two entirely unrelated workplace nodes; membership rows carry a tenant ID too. There is no pooled cross-customer household or workplace database, and your competitors' traffic teaches your graph nothing — in either direction.
That's a real trade-off, and it's the honest one. Pooled B2B intent networks get broader coverage by commingling everyone's visitors, and you inherit whatever data-quality and consent decisions the pool made. If you're weighing bought account data against first-party clustering, we wrote up how to evaluate audience data vendors without getting burned.
Clusters That Expire
Environmental facts go stale faster than identities. People change jobs, leases end, and that café that briefly looked workplace-ish on weekday afternoons stops mattering. So every probabilistic edge in the graph carries a TTL and gets pruned; only deterministic person signals — hashed emails and phones — persist without expiry:
| Edge Type | TTL |
|---|---|
| Session ID | 7 days |
| Visitor ID / device fingerprint / geohash | 14 days |
| Household / mobile ad ID | 30 days |
| Workplace | 60 days |
| Ad-platform click ID | 90 days |
| Hashed email / hashed phone (deterministic) | No expiry |
Workplaces get twice the household TTL because, as the source comment notes, workplaces are more stable — but both decay. A cluster that isn't refreshed by real visits disappears. An identity system that only ever adds edges eventually believes everything; this one is built to forget.
The Bottom Line
B2B visitor identification doesn't have to mean buying a lookup table of other people's guesses. ClickStream's household and workplace clustering builds account-level context from your own first-party traffic, under constraints you can read in the schema:
- Hashed IPs only — the household key is an HMAC/SHA-256 digest, with VPN, hosting, proxy, and Tor connections excluded
- Workplaces require all three: a ~153m precision-7 geohash cell, a matching ASN, and repeated weekday business-hours activity
- Environmental signals never merge people — only deterministic person-level keys do, and geo-based candidates need geography-independent corroboration
- Per-tenant isolation is in the unique constraints — no cross-customer cluster pooling
- Everything probabilistic expires — households in 30 days, workplaces in 60, unless real activity renews them
If you want to see what your own traffic clusters into, installation takes a script tag — and the plans page shows what each tier includes. The buying committee is already on your site. You don't need their form fill to notice them — and you don't need to violate anyone's privacy to serve them better.