Skip to main content

Visitor Profiles

The Identity Graph stores visitors using two record types: a global Person (the human) and one or more per-tenant Person Profiles (what each company knows about that human).

Person

A Person is created the first time we resolve a visitor to an identifier — typically their email or phone number. It holds:

  • Name, email, phone as we've come to learn them.
  • Match keys — normalised, hashed forms of every identifier we've seen for that human (each email and phone gets normalised, lowercased / digits-only, and sha256-hashed; the matching is done against the hash, not the raw value).
  • First seen / last active timestamps.

Person records are global: a single human is one Person record, even if they show up on three different customers' websites. Importantly, only the basic identity fields (name / email / phone) are stored at this level. Anything richer — past conversations, CRM enrichment, bookings, captured form responses — lives on the per-tenant Person Profile, not on the Person itself.

Person Profile

A Person Profile is created the first time a Person is seen by a particular customer. There is exactly one profile per (Person, Company) pair, and it carries everything that customer knows about that human:

  • Self-reported company name when they shared it on your site.
  • CRM contact IDs — HubSpot contact id, GoHighLevel contact id.
  • CRM enrichment snapshot — cached lifecycle stage, deals/opportunities, tags, recent notes (refreshed in the background every few hours).
  • Form submissions — every form they've filled on your site, with the captured fields.
  • Bookings — every meeting they've booked through Google Calendar / Calendly / GHL / your widget's booking flow, deduplicated.
  • Extracted facts — short AI-generated takeaways from prior chats and calls ("interested in T-shirts", "budget under $5k", "decision-maker for procurement").
  • Resolved location — city plus a location_source flag that records which layer produced it: Snitcher (B2B company location), IP geolocation, or a direct value the visitor shared. So a profile might show "San Francisco (via Snitcher)" or "New York (via IP)". The label makes it clear whether the location is a confident B2B match or a best-guess IP lookup.
  • First seen / last active timestamps for this tenant.

Per-tenant isolation

When the AI agent on Company A's site builds a prompt for a visitor, it reads from Company A's Person Profile only. It never reaches into Company B's profile for the same Person. This means:

  • A visitor's chat history with Company A is invisible to Company B's AI even when both companies recognise it's the same human.
  • CRM enrichment, captured forms, bookings — all per tenant.
  • The only thing both tenants share is the Person record itself: name, email, phone — and even those are surfaced to the AI based on the tenant's own verification policy.

Looking up a visitor

The Person Profile detail page (super admin → Identity → Persons → click a person → click a profile) shows everything we've collected about a visitor for a given customer:

  • A summary header (who they are, first/last seen, lead score).
  • Form Submissions tab — every captured form, newest first.
  • Extracted Facts tab — every AI-distilled fact, with source (chat or call) and confidence weight.
  • Bookings tab — every meeting linked to this person.
  • CRM Enrichment tab — the cached HubSpot/GHL snapshot.
  • Identity Audit tab — every verification event we've recorded against this profile (claims, verifications, conflicting claims). Useful when investigating why a session was or wasn't trusted.