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_sourceflag 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.