Documentation
One person, however they arrive
How a visitor, an email address and a customer become one record.
A person meets your business several times before you know their name: on a phone, then a laptop, then in your app, then as a billing id that looks like nothing at all. In most stacks that's four rows in four tools. In Kicklace it's one record with one timeline, and this page is how it stays one.
The record, and the keys that find it
Everything Kicklace knows about somebody hangs off one record. Beside it sit its identities, the keys other systems know that person by:
| Kind | What it is | Who writes it |
|---|---|---|
email |
an address, lowercased | a form, an import, your own server, a connection |
anon |
the random id the site tag keeps in localStorage |
the tag |
account |
your own id for their account in your product | your server, as account_id |
clerk_user, kinde_user |
their user id at your sign-in provider | Clerk or Kinde |
github_user |
a GitHub handle | GitHub |
One more kind exists that no other system writes for a person: install, an id for one installation
of a downloadable app.
Any of them finds the person. Post an event with an email, an anon_id, an account_id or all
three, and it lands on the same record.
An identity on a record stays on it. Kicklace never guesses a person from a browser fingerprint, an IP address or a name, and has none of the machinery that would let it.
The four rules
1. The address is the key that crosses devices. Two browsers, a laptop and a phone, with the same address typed into both, are one person, because the address is the same and nothing else has to be.
2. A known address on a new browser attaches that browser. Somebody who already exists fills in a
form on a machine Kicklace has never seen, and the new anon id is added to the record they have.
Their history isn't split.
3. A known address on a browser that belongs to an anonymous person merges the two. That browser had been reading pages for two weeks with no name. Now it has one. The anonymous record is folded into the named one (its identities, its timeline, its sign-ups, its links), and the earliest first touch wins. What that visitor was first recorded arriving from is what the person is still credited to a year later.
4. Two people who both have an address are never merged by themselves. A shared laptop is a real thing. If the browser id already belongs to somebody with a different address, the new address starts its own record and the browser id stays where it was. Merging two named people is a decision, and a person makes it (below).
These rules are what let a Stripe payment and a Clerk sign-up land on one record without either provider ever meeting the other.
A hosted sign-in, joined by the tag
Rule 3 joins a visitor to the person they sign up as. But a hosted sign-in, like Clerk's own pages,
leaves no form on your site for the tag to hear, so without one more thing the visitor and the
signed-in user stay two records. <KicklaceTag user={…} /> closes that gap: it puts the
signed-in visitor's address, id and name on the tag's own script element, and the tag reads them back
and identifies that browser once a session. Rule 3, from code rather than a form.
The address is the signed-in user's own, rendered only into their own page, and sent only to your workspace's own public ingest route. Nothing is identified for a visitor who isn't signed in.
Organizations, and whoever pays
A person is usually the one who pays: they signed up, they put a card in, and the money is theirs. A company with four people on one plan is different. There the money is the company's, and the four are its people.
So a second level of identity hangs off the organization, the company or team your people belong to:
| Kind | What it is | Who writes it |
|---|---|---|
clerk_org, kinde_org |
an organization id at your sign-in provider | Clerk or Kinde |
github_sponsor_org |
a sponsoring organization's handle | GitHub |
stripe_customer (cus_…) is a person's identity, because a Stripe customer is usually the
human who signed up. It sits on an organization only where you've said so (update_organization
with a stripeCustomer, or a Clerk organization whose own metadata names one), and then the
subscriptions the person was carrying move with it.
A payment carrying no address still lands somewhere useful: the first event under a customer id
nobody has seen writes the person down under it, named the way Stripe names them, and every later
event finds them. A purchase belongs to the record whose stripe_customer matches the customer id
on it, and one with no customer id belongs to the person it's on, so nothing is counted twice.
A customer's state follows from their subscriptions and payments: Paying is a live subscription, or a purchase in the last ninety days. Trial is trialing with no money yet. Churned paid once and is neither. Free never paid. Nobody sets it. A person who pays nothing themselves reads the state of the organization they're in.
A person is linked to their organization as a member of it. Moving somebody to another organization is one edit, and two records of one company are folded together the way two people are, with the same rule: the earliest first touch wins.
First touch is kept for good
Every record carries a first touch and a last touch: the source, medium, campaign, ad click id and path of an arrival. First touch only ever moves earlier. A later visit can never overwrite it, and neither can a merge.
That's what makes "which campaign brought us the people who paid this quarter" answerable: first touch is still the ad they clicked in March.
Merging by hand
Sometimes there really are two records for one person (two addresses, a typo, a spreadsheet import) and no rule should join them on its own. Merge… on a person (owners and admins) finds another record of the same kind, shows what will happen, and asks which one stays.
When it runs:
- the one that stays keeps its own values, and its blanks are filled from the other;
- identities, timeline rows, links, sign-ups, tasks and sent emails move across;
- the earliest first touch and the latest last touch win;
- the further stage on the Lifecycle wins, so a merge never moves anybody backwards;
- the folded record is marked, and its page sends you to the one that stayed, so no saved link breaks;
- a note on the timeline says what moved and who did it.
Two records of different kinds can't be merged. Every step is safe to run twice, so a merge that was interrupted is finished by running it again.
What a person can ask you for
Everything you hold. A record's export is a JSON file with all of it: the fields, every identity, every sign-up with the words that person agreed to and when, the whole timeline, every email sent to them, their links, and the records merged into them. Any member can take it, from the record's own menu.
Deletion. Deleting a record deletes it, every record merged into it, and everything hanging off them: identities, timeline, sign-ups and their consent records, tasks, sends and links. You're told a record was deleted, and the note never names the person.
Visitors who never came back
A visitor is one browser, until they give an address. The Lifecycle map, its Table and its chart show one for 30 days after their last visit, and then they step off. Nothing is deleted for that: a visitor who comes back, or gives an address, is on the map again with everything they did.
Most anonymous visitors never leave an address, and keeping them forever is a cost with no purpose. Set a retention period under Settings → General → Privacy, and every hour anonymous people not seen since then are deleted.
"Anonymous" is narrow on purpose. Somebody is only swept if they have no email, no account, no Stripe customer, no Clerk or Kinde user and no GitHub handle, and weren't merged into anybody. Anybody another system has named is a person, and stays. Setting the period to keep them all keeps everything.
Your own servers can go further: an event posted to POST /api/v1/events may carry an expires_at,
your promise about how long that one row may be kept. Kicklace deletes the row on that day, and the
person, their stage, their first touch and their sign-ups all stay. Events has the rule.