Measurement / Send Events
Send Events
Tell Revnu from your server when a visitor signs up, books a call or pays, so the result is tied back to where they came from.
Last updated
The Revnu Tag sees visits. The Event API is how your server tells Revnu something real happened: a signup, a booked call, a payment. Revnu joins the event to the visit that led to it, so you can see which source (an AI assistant, search, an ad) brought the customers who converted.
curl https://revnu.com/api/measurement/events \
-H "Authorization: Bearer $REVNU_EVENT_KEY" \
-H "Content-Type: application/json" \
-d '{
"event_id": "signup_8412",
"event_name": "signup",
"anonymous_id": "ra_3f9c0a1b2c3d4e5f60718293a4b5c6d7",
"consent_state": "granted",
"email": "ana@example.com"
}'Your event key
The event key starts with rsk_live_ and comes with your site key. Keep it in a server-side environment variable: anyone who has it can send events for your site. It is not the rvp_ personal API token.
Connect the visit to the event
The tag gives every visitor an id. Read it in the browser and send it to your backend with the signup, booking or checkout:
const anonymousId = window.revnu?.anonymousId; // "ra_..."Then pass it as anonymous_id when your server sends the event. That id is what ties the event to the visit.
Save the visitor's consent choice at the same moment, and send it as consent_state:
const consentState = window.revnu?.getContext().consentState; // "granted", "pending" or "denied"Revnu sends every event to your ad platforms unless consent_state is denied, so an event without it still counts for your ads. Sending the saved choice is what keeps a visitor who declined out of them.
Request
| Field | Required | Notes |
|---|---|---|
event_id |
yes | Your stable id for this event. 1-128 letters, digits, ., _, : or -. Sending the same id again is safe: it is reported as a duplicate, not counted twice. |
event_name |
yes | Lowercase snake_case, for example signup, demo_booked, purchase. |
occurred_at |
no | ISO 8601 date or milliseconds. Defaults to when Revnu receives it. |
anonymous_id |
no | window.revnu.anonymousId from the visit. |
consent_state |
no | granted, denied or pending: the visitor's choice saved with the signup, booking or checkout. Every event except denied is sent to your ad platforms. |
google_ad_user_data, google_ad_personalization |
no | granted, denied or unknown. Google Ads receives every event except one where google_ad_user_data is denied. |
gclid, gbraid, wbraid, fbclid, ttclid, _ttp, twclid, li_fat_id, msclkid, rdt_cid |
no | Ad click ids or Pixel cookies you stored yourself. Only needed when the visit cannot be joined by anonymous_id, for example when the tag was blocked. |
email, phone, external_user_id |
no | Normalized and hashed for matching. |
amount, currency |
no | Send both, for example 49 and "USD". |
properties |
no | An object of extra facts, for example { "plan": "pro" }. |
reversal_of |
no | The event_id of an earlier event this one cancels, such as a refund. Repeat the original amount and currency. |
Node.js
await fetch("https://revnu.com/api/measurement/events", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.REVNU_EVENT_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
event_id: `signup_${user.id}`,
event_name: "signup",
occurred_at: user.createdAt.toISOString(),
anonymous_id: revnuAnonymousId, // sent up from the browser
consent_state: savedConsentState, // getContext().consentState, saved at signup
email: user.email,
}),
});Response
{
"accepted": true,
"matched": false,
"counted": false,
"not_counted_reason": "\"signup\" is not in this site's win definition, which counts \"trial_started\". It was recorded, but it will not count as a win until the definition in Revnu includes it.",
"duplicate": false,
"enriched": false,
"event_id": "signup_8412",
"event_name": "signup",
"roles": [],
"attribution_status": "pending"
}countedsays whether the event counts as a win under your site's win definition.not_counted_reasonappears when an event can never count because the definition does not include itsevent_name. Change the definition in Revnu, or send the event it names.matchedsays whether the event was credited to one of your Revnu ad campaigns. It staysfalseuntil you run campaigns through Revnu, and that is expected.
| Code | Meaning |
|---|---|
| 200 | Recorded and credited to one of your Revnu ad campaigns, or a duplicate of an event already recorded |
| 202 | Recorded, not credited to a campaign. Check counted to see whether it counts as a win |
| 401 | Missing or invalid event key |
| 409 | The same event_id was sent before with different values |
| 413 | Body over 64 KB |
| 422 | A field failed validation; error says which |
| 429 | Rate limited; retry later with the same event_id |
Agents: this page is also markdown at /docs/event-api.md, answers Accept: text/markdown, and is listed in /docs/llms.txt.
Frequently Asked Questions
No. The event key would be public. Send events from your backend, a serverless function or a webhook handler, and let the browser pass along only the `anonymous_id`.