Skip to content

Contacts

Signals sessions are anonymous by design. A contact is the bridge: when a visitor gives you an email or logs into an account you already know, you identify them, and from then on their sessions link to one record you can look up, export, or delete.

Personal data lives on the contact only. A session carries nothing but a contact_id.

A contact is created the first time you identify a person on a property. Four paths lead there:

signals.identify('[email protected]', { first_name: 'Jane', plan: 'pro' });

Links the current browser session. See Identify.

From a Laravel backend the PHP SDK can identify on login with one middleware.

Identify is idempotent. Each call resolves to exactly one contact:

  1. If the payload has an external_id, match on it. A new email on a known external_id updates the email.
  2. Otherwise match on email, most recently seen first. An external_id supplied later is backfilled onto the matched contact.
  3. Otherwise create a new contact.

Traits in the payload overwrite the stored value when present and are left alone when absent. meta entries merge by key. If the call came with a session and the contact has no country or city yet, they default from the session’s geo.

At least one of external_id or email is required.

A session is linked to the first contact that identifies it, and never re-linked. A second identify on the same session with a different person is recorded against that person’s contact, but the session keeps its original contact_id. This keeps a shared device from rewriting history, and it means a session’s contact is something you can rely on.

Each successful link increments the contact’s session_count and writes an identify event onto the session, so identification is visible in the session timeline and queryable.

FieldNotes
external_idYour own id for the person (user id, CRM id). Preferred match key.
email
first_name, last_name
phone, company, job_title, website
country, cityDefaults from the session’s geo on first identify
lifecycle_stageFree text. SnipForm offers lead, subscriber, customer, user anywhere it gives you a picker; the API accepts whatever your CRM uses. New contacts default to user.
stateactive, unsubscribed, or deleted (see below)
metaA list of {key, value} pairs for anything else
first_seen_tsEntry time of the first linked session, or the identify time
identified_tsWhen the contact was created
last_seen_tsLast activity of any linked session
session_countLinked sessions

Timestamps are unix seconds.

StateSet byMeaning
activedefaultNormal
unsubscribedyou, via the dashboard or APIA flag for your own outbound tools. SnipForm does not send anything to contacts, so it changes nothing here.
deletedthe delete action onlyThe contact has been redacted. It cannot be set directly.

Deleting a contact is erasure by redaction. Sessions and events keep the contact’s id as their relational spine, so removing the row would break them. Instead, every identifying value is destroyed in place:

  • external_id, names, phone, company, job title, website, country, city and meta are cleared
  • email becomes deleted_<random>@redacted.invalid
  • state becomes deleted
  • Identify events on the linked sessions are scrubbed of the email and external id

What remains says nothing about anyone. A deleted contact returns 410 Gone on update over the API, and its sessions stay in your analytics as anonymous sessions, which is what they were before identification.

A browser that sends Sec-GPC: 1 is never identified by the tracker. signals.identify() returns quietly and no contact is created or linked. Server-side identification through the API is under your control and is not affected; honour the signal yourself if you have it.

The Contacts page on a property lists contacts with search, state and lifecycle filters. Each contact page shows the traits, the linked sessions newest first, and the edit and delete actions. The same data is available at /v2/property/contacts.

Contacts also power the A visitor is identified and A contact is created or updated automation triggers, which is the hook for pushing identified people into a CRM.