Identified Visitors Webhook¶
Send every person Rose identifies visiting your site to your own endpoint, within a few minutes of them being identified. Wire those contacts straight into your CRM, n8n, Zapier, or any HTTPS endpoint and build your own follow-up: assign an owner, alert the rep who covers that account, or start a sequence.
This is the person-level counterpart of the Identified accounts webhook. That one tells you a company visited; this one tells you who.
This is self-serve — you set it up yourself on the Integrations page, no account manager needed.
How it works¶
Rose resolves person-level identity from providers that can name an individual
behind a visit. When one of them names someone, Rose sends a single POST to your
webhook URL with that person's details, their company, and how they reached your
site.
Two things are worth knowing up front:
- Only named people are sent. A visit where Rose recognises the company but not the person goes to the identified accounts webhook instead, never here. You will always get at least a name, a work email, or a LinkedIn profile.
- Identification can be much later than the visit. Some providers answer
within seconds; others resolve a visit hours afterwards. The payload carries
both
timestamp(when Rose sent it) andidentification.identified_at(when the provider actually resolved it), so your CRM can tell the difference.
One request per identified person. Delivery is best-effort and fully in the background: if your endpoint is slow or down, your visitors' experience is never affected. Rose retries a few times with backoff, then gives up for that person.
De-duplication is best-effort, so on rare occasions the same person can arrive
twice. Every payload carries a stable event_id — de-duplicate on it and ignore
any repeat you've already processed.
What you need¶
- An HTTPS endpoint that accepts a
POSTwith a JSON body (a Zapier "Catch Hook", an n8n Webhook node, or your own API route). - Access to the Rose backoffice Integrations page for your site.
- Person-level identification enabled for your site. If you are not sure whether it is, ask in your shared Slack channel or at support@userose.ai.
Set it up¶
- In the Rose backoffice, open Integrations and find the Identified visitors webhook card (under Webhooks).
- Turn Enable webhook on, then click Configure and fill in:
| Setting | What to enter |
|---|---|
| Webhook URL | The HTTPS address that receives each identified person. Example: https://hooks.zapier.com/hooks/catch/123/abc. |
| Secret key (optional) | A secret you choose so your endpoint can confirm the request really came from Rose. Leave empty to skip. Stored encrypted — after saving, the field shows Saved rather than the secret; paste a new one to replace it. See Verifying the signature. |
- Click Save. The next person identified on your site is posted to your endpoint.
The payload¶
Rose sends a JSON body like this:
{
"event_type": "visitor_identified",
"event_id": "3ab41c...9d02",
"timestamp": "2026-09-02T14:32:10.123456+00:00",
"site_name": "yourdomain.com",
"person_id": "0191f2a4-...",
"person": {
"email": "jane@acme.com",
"name": "Jane Doe",
"job_title": "VP Sales",
"linkedin_url": "https://www.linkedin.com/in/jane-doe"
},
"account": {
"company_name": "Acme Inc",
"domain": "acme.com",
"sector": "Software",
"sub_sector": "Supply chain",
"employee_count": "51-200",
"country": "US"
},
"identification": {
"provider": "vector",
"confidence_score": 1.0,
"identified_at": "2026-09-02T09:15:00+00:00"
},
"first_touch": {
"channel": "organic_search",
"referrer_domain": "google.com",
"utm_source": null,
"at": "2026-09-02T08:58:41+00:00"
},
"activity": {
"session_count": 3,
"first_seen_at": "2026-09-02T08:58:41+00:00",
"last_seen_at": "2026-09-02T09:14:02+00:00"
}
}
| Field | Description |
|---|---|
event_type |
Always visitor_identified. |
event_id |
Stable id for one identified person. Use it to de-duplicate: two requests with the same event_id are the same person, so ignore the repeat. |
timestamp |
When Rose sent the webhook (ISO 8601, UTC). |
site_name |
Your site domain. |
person_id |
Rose's anonymous visitor id, when known (may be null). |
person |
The identified individual. At least one of email, name or linkedin_url is always present. |
account |
Their company, when Rose knows it. |
identification |
Which provider named them, how confident it was, and when it resolved — often well before timestamp. |
first_touch |
How this visitor first arrived on your site: channel, referring domain, UTM source. |
activity |
How much they have browsed: number of sessions, first and last seen. |
Any field Rose couldn't determine is
null. Always code your endpoint to tolerate missing fields.
A note on email¶
person.email is a work email address. Rose does not send personal-mailbox
addresses resolved by an enrichment provider, and depending on your site's
settings the field may be null even though the person is identified by name.
Verifying the signature¶
If you set a Secret key, Rose adds an X-Webhook-Signature header to every
request: a hex-encoded HMAC-SHA256 of the raw request body, keyed with your
secret. Recompute it on your side and compare to confirm the request is genuine.
Node.js example:
const crypto = require('crypto');
function isFromRose(rawBody, signatureHeader, secret) {
const expected = crypto
.createHmac('sha256', secret)
.update(rawBody) // the exact raw bytes, before JSON parsing
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(expected),
Buffer.from(signatureHeader)
);
}
Sign over the raw body bytes exactly as received — parsing and re-serializing the JSON can change the bytes and break the check.
Troubleshooting¶
| Symptom | Likely cause / fix |
|---|---|
| No requests at all | Check Enable webhook is on and Save was clicked, and that the Webhook URL starts with https://. If it is all correct, person-level identification may not be enabled for your site — ask us. |
| Far fewer people than companies | Expected. Naming an individual is much harder than recognising a company, so only a fraction of identified visits produce a person. |
identified_at is hours before timestamp |
Expected for providers that resolve a visit after the fact. The person is real; the visit simply happened earlier. |
person.email is null but there is a name |
The provider returned no work email, or returned a personal-mailbox address that Rose does not forward. |
| Signature never matches | Recompute HMAC over the raw body, not the re-serialized JSON, and confirm the secret matches exactly. |
| A known visitor didn't fire again | Rose sends each identified person once. A returning visitor already sent won't re-fire. |