Track what creators drive on a brand's own site. A pixel records visitors' events, a conversion decides which events count, and a link from a creator's video credits them. The tracking guide covers installing the pixel in the browser.
Start with POST /v1/pixels, then add a conversion for the event you care about, like a purchase.
Pixels
POST /v1/pixels creates one for the domains it may send from:
{
"name": "Shop",
"domains": ["https://shop.example.com"],
"excludedCountries": ["DE"]
}
{
"id": "pxl_0Q2m8VxR4sTnYb7KcLd3Ew",
"name": "Shop",
"domains": ["https://shop.example.com"],
"excludedCountries": ["DE"],
"status": "verified",
"lastSeenAt": "2026-10-07T15:04:05.000Z",
"snippet": "<script>window.lucra=window.lucra||[];lucra.push([\"init\",{siteId:\"pxl_0Q2m8VxR4sTnYb7KcLd3Ew\"}]);</script><script async src=\"https://a.onlucra.com/p.js\"></script>",
"firstParty": {
"path": "/lucra",
"target": "https://a.onlucra.com",
"snippet": "<script>…</script><script async src=\"/lucra/p.js\"></script>"
},
"quality": {
"events": 1840,
"consented": 1622,
"fromServer": 212,
"withUserData": 240,
"withClickIds": 610,
"credited": 388,
"located": 1835
},
"version": 2,
"createdAt": "2026-10-01T15:04:05.000Z",
"updatedAt": "2026-10-02T09:12:44.000Z"
}
domainsare origins with no path, likehttps://shop.example.com.excludedCountriesare two-letter codes; visitors there aren't recorded.statusiswaitinguntil the first event arrives, thenverified;archivedpixels accept no events.firstPartyis the recommended install: proxypathon your site totargetand use itssnippet.qualitycounts the last 7 days' events.
PATCH /v1/pixels/:id renames it, changes domains or excludedCountries, or archives it with status: "archived". The pixel.verified webhook fires on its first event.
A connected Shopify store can install the pixel without code from Settings → Lucra Pixel in the app.
Server events
POST /v1/pixels/:id/events (lucra.pixels.events.create in the SDK) records an event from the brand's server, so ad blockers and closed tabs can't lose it. It returns 202:
{
"name": "purchase",
"eventId": "order-1042",
"orderId": "1042",
"value": 4999,
"currency": "USD",
"pageUrl": "https://shop.example.com/thanks",
"lucraId": "sub_14XA4WGiSOmaVI3B4QLm4Fs",
"landedAt": "2026-10-05T18:20:00.000Z",
"user": { "email": "jo@example.com", "phone": "+1 555 010 4477" },
"clickIds": { "fbc": "fb.1.1759685000000.IwAR2x", "fbp": "fb.1.1759600000000.1234567890" },
"ipAddress": "203.0.113.7",
"userAgent": "Mozilla/5.0 (iPhone; CPU iPhone OS 26_0 like Mac OS X) …"
}
{ "eventId": "order-1042", "duplicate": false }
| Field | What |
|---|---|
name | A standard event (page_view, view_content, search, add_to_cart, begin_checkout, purchase, lead, sign_up, start_trial, subscribe, contact) or your own, in snake_case. |
eventId | Send the browser event's ID to count it once. A repeat returns duplicate: true and confirms the browser event. |
occurredAt | Defaults to now; within the last 7 days. |
value, currency | In cents, with an ISO 4217 code. Send both or neither. |
orderId | Your order's ID. |
pageUrl | A page on the pixel's domains. Defaults to its first domain. |
consent | granted (default), denied or unknown. Without granted, leave out lucraId, landedAt, user, clickIds, ipAddress and userAgent. |
lucraId | lucra_id from the landing URL: the video the visitor came from. |
discountCode | The order's discount code, recorded with the event. |
landedAt | When the visitor arrived from the video or code, for attribution windows. |
user | email, phone, firstName, lastName, city, state, zip, country, externalId. Hashed (SHA-256) on arrival; hashes are kept as sent. |
clickIds | fbc, fbp, gclid, gbraid, wbraid, ttclid, ttp, sccid, scid. |
ipAddress, userAgent | The visitor's. The IP is kept 13 months. |
location | country, region, city, postalCode, like the shipping address. |
actionSource | website (default), app, physical_store, phone_call, chat, email, system_generated or other. |
properties | productId, variantId, quantity, contents ({ id, quantity, price }, up to 100) and custom (up to 25 fields). |
A pixel takes up to 1,200 events a minute; past that you get 429.
Pixel events
GET /v1/pixel-events lists what the pixels received, newest first. Filter by pixel, conversion, or attributed=true for events from a creator's video. GET /v1/pixel-events/:id returns one, with what ad platforms' conversion APIs take:
{
"id": "pxev_3Hd8kQm1ZrT6yWv2NbLx0Pa",
"pixel": "pxl_0Q2m8VxR4sTnYb7KcLd3Ew",
"name": "purchase",
"occurredAt": "2026-10-07T15:04:05.000Z",
"receivedAt": "2026-10-07T15:04:05.412Z",
"sentFrom": "server",
"actionSource": "website",
"consent": "granted",
"value": 4999,
"currency": "usd",
"orderId": "1042",
"pageUrl": "https://shop.example.com/thanks",
"referrerUrl": null,
"submission": "sub_14XA4WGiSOmaVI3B4QLm4Fs",
"landedAt": "2026-10-05T18:20:00.000Z",
"clickIds": { "fbc": "fb.1.1759685000000.IwAR2x" },
"user": { "email": "5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8" },
"ipAddress": "203.0.113.7",
"userAgent": "Mozilla/5.0 (iPhone; CPU iPhone OS 26_0 like Mac OS X) …",
"properties": {},
"conversions": ["conv_1fK7pQ2wXy9LmN4bVc8RtZa"],
"source": "paid_ad",
"creator": "crtr_026UYfiw1Y6OvUpuKWiOpeL",
"discountCode": null,
"location": { "country": "US", "region": "California", "city": "Oakland", "postalCode": "94612", "timezone": "America/Los_Angeles", "latitude": 37.8, "longitude": -122.27 },
"network": { "asn": 7922, "organization": "Comcast" },
"device": { "type": "mobile", "os": "iOS", "browser": "Safari", "inApp": "tiktok", "language": "en-US" }
}
sentFromisserverfor server events and browser events a server copy confirmed.sourceispaid_ad(an ad's link) ordirect;creatoris who's credited.userholds SHA-256 hashes, normalized for Meta, TikTok and Google.
Conversions
A conversion counts the events that matter, like purchases over $20:
{
"name": "Purchase",
"eventName": "purchase",
"pageUrlContains": "/thanks",
"minValue": { "amount": 2000, "currency": "USD" },
"attributionWindowDays": 30,
"payBrowserEvents": false
}
{
"id": "conv_1fK7pQ2wXy9LmN4bVc8RtZa",
"name": "Purchase",
"eventName": "purchase",
"pageUrlContains": "/thanks",
"minValue": { "amount": 2000, "currency": "usd" },
"attributionWindowDays": 30,
"payBrowserEvents": false,
"status": "active",
"recorded": 412,
"attributed": 96,
"version": 1,
"createdAt": "2026-10-01T15:04:05.000Z",
"updatedAt": "2026-10-01T15:04:05.000Z"
}
eventNameis a standard event or your own.pageUrlContainsandminValuenarrow it; a minimum value matches only events in its currency.attributionWindowDays(1–90, default 30) credits the creator when the visitor converts within that many days of landing from their video. Events without a landing time, like server events, are credited too.payBrowserEventslets browser-only events pay creators. Off by default, since anyone with the pixel ID can send browser events.recordedcounts matching events;attributed, those credited to a creator.
PATCH /v1/conversions/:id changes it or archives it; events already recorded keep counting as they did. Each matching event sends conversion.recorded with conversion, pixel_event and, when credited to a video, submission.
Pay per conversion
Add a conversion rule to a program's or a retainer's pay:
{
"rules": [
{ "conversion": "conv_1fK7pQ2wXy9LmN4bVc8RtZa", "amount": 500 },
{ "conversion": "conv_7Rt2LmQ9xWb4NcV1kZp8YsD", "percent": 10 }
],
"cap": 100000,
"schedule": { "every": "week" }
}
amountpays a flat amount in cents per conversion;percentpays a share of its value, like an affiliate commission. Apercentcounts only events valued in USD for now.- Only conversions credited to the creator count: through their video's
lucra_idlink, within the conversion's window. One counts toward every program and retainer of that creator that pays on it. - Only server-confirmed events pay, unless the conversion has
payBrowserEvents: true. - A retainer can pay only on conversions. A program pays them alongside its usual rule.
Report
GET /v1/conversions/:id/report?groupBy=creator,country breaks a conversion down by up to 3 of creator, country, region, city, inApp, deviceType, source and day. Narrow it with from, to, and credited=true for creators' only.
{
"data": [
{ "creator": "crtr_026UYfiw1Y6OvUpuKWiOpeL", "country": "US", "conversions": 58, "value": 289942, "currency": "usd" },
{ "creator": null, "country": "CA", "conversions": 21, "value": 104979, "currency": "usd" }
]
}
/v1/pixelsCreate a pixel
const { data } = await lucra.pixels.create({
body: { name: "…", domains: ["…"] },
})Body
namestring· requireddomainsstring[]· requiredOrigins the pixel may send from, like
https://shop.example.com.excludedCountriesstring[]Countries (ISO 3166-1 alpha-2) whose visitors the pixel doesn't record, decided by the visitor's IP country.
Response20112 fieldsShow
idpxl_…namestringdomainsstring[]excludedCountriesstring[]statusenumverified once the first event arrives from an allowed domain; archived pixels accept no events.
waitingverifiedarchivedlastSeenAtstringnullablesnippetstringPaste before </head> on every page of the allowed domains.
firstPartyobjectRecommended: proxy
pathon your site totarget(a rewrite in Next.js, Vercel, Cloudflare or nginx) and use this snippet instead. The pixel then keeps visitors' attribution in a first-party cookie, so Safari doesn't forget them after 7 days.Show 3 child fieldsHide child fields
pathstringtargetstringsnippetstring
qualityobjectOf the last 7 days' events: how many had consent, came from your server, carried user data or ad click IDs, were credited to a creator, and have a location.
Show 7 child fieldsHide child fields
eventsintegerconsentedintegerfromServerintegerwithUserDataintegerwithClickIdsintegercreditedintegerlocatedinteger
versionintegerSend it back on PATCH to reject edits based on a stale read.
createdAtstringupdatedAtstring
/v1/pixels/:id/eventsSend a conversion from the brand's server; 202 once it's recorded for attribution
const { data } = await lucra.pixels.events.create({
path: { id: "pxl_…" },
body: { name: "…" },
})Path parameters
idpxl_…· required
Body
namestring· requiredA standard event (page_view, view_content, search, add_to_cart, begin_checkout, purchase, lead, sign_up, start_trial, subscribe, contact) or your own, in snake_case.
occurredAtstringDefaults to now; must be within the last 7 days.
orderIdstringvalueintegerIn cents, with its currency.
currencystringISO 4217, in either case (
usdorUSD).consentenumRecorded by default, like the browser pixel; send
deniedorunknownwhen the visitor declined, and leave out lucraId, campaign, attributionId and clickId.granteddeniedunknownlucraIdstringlucra_idfrom the landing URL: the video (submission) the visitor came from.campaignstringlucra_campaignfrom the landing URL: the paid campaign (camp_…) whose ad the visitor came from.attributionIdstringlucra_attribution_idfrom older landing URLs; sendlucraIdfor new ones.clickIdstringeventIdstringSend the browser event's ID to count a conversion once when both fire.
pageUrlstringThe page the conversion happened on; defaults to the pixel's first domain.
propertiesobjectShow 5 child fieldsHide child fields
productIdstringquantityintegervariantIdstringcontentsobject[]Show 3 child fieldsHide child fields
idstring· requiredquantityintegerpriceintegerPer item, in cents, in the event's currency.
customobject
actionSourceenumWhere the conversion happened.
websiteappphysical_storephone_callchatemailsystem_generatedotherlandedAtstringWhen the visitor arrived from the video (
lucra_id), for conversion attribution windows.userobjectFor matching on ad platforms: hashed (SHA-256) on arrival, never stored raw; already-hashed values are kept.
Show 9 child fieldsHide child fields
emailstringphonestringfirstNamestringlastNamestringcitystringstatestringzipstringcountrystringexternalIdstring
clickIdsobjectAd click IDs and platform cookies from the visitor's browser.
Show 9 child fieldsHide child fields
fbcstringfbpstringgclidstringgbraidstringwbraidstringttclidstringttpstringsccidstringscidstring
ipAddressstringThe visitor's IP address; kept 13 months.
userAgentstringThe visitor's browser user agent, for their device and in-app browser.
creatorCodestringThe creator's code from the landing URL (
?lucra=CODE).discountCodestringThe order's discount code, recorded with the event.
locationobjectWhere the customer is, like the order's shipping address.
Show 4 child fieldsHide child fields
countrystringregionstringcitystringpostalCodestring
/v1/pixelsList pixels
const { data } = await lucra.pixels.list()Query parameters
Plus paging: limit, cursor, createdAfter and createdBefore.
Response200A page of items, 12 fields each, and nextCursorShow
idpxl_…namestringdomainsstring[]excludedCountriesstring[]statusenumverified once the first event arrives from an allowed domain; archived pixels accept no events.
waitingverifiedarchivedlastSeenAtstringnullablesnippetstringPaste before </head> on every page of the allowed domains.
firstPartyobjectRecommended: proxy
pathon your site totarget(a rewrite in Next.js, Vercel, Cloudflare or nginx) and use this snippet instead. The pixel then keeps visitors' attribution in a first-party cookie, so Safari doesn't forget them after 7 days.Show 3 child fieldsHide child fields
pathstringtargetstringsnippetstring
qualityobjectOf the last 7 days' events: how many had consent, came from your server, carried user data or ad click IDs, were credited to a creator, and have a location.
Show 7 child fieldsHide child fields
eventsintegerconsentedintegerfromServerintegerwithUserDataintegerwithClickIdsintegercreditedintegerlocatedinteger
versionintegerSend it back on PATCH to reject edits based on a stale read.
createdAtstringupdatedAtstring
/v1/pixels/:idGet a pixel and whether it's verified
const { data } = await lucra.pixels.retrieve({
path: { id: "pxl_…" },
})Path parameters
idpxl_…· required
Response20012 fieldsShow
idpxl_…namestringdomainsstring[]excludedCountriesstring[]statusenumverified once the first event arrives from an allowed domain; archived pixels accept no events.
waitingverifiedarchivedlastSeenAtstringnullablesnippetstringPaste before </head> on every page of the allowed domains.
firstPartyobjectRecommended: proxy
pathon your site totarget(a rewrite in Next.js, Vercel, Cloudflare or nginx) and use this snippet instead. The pixel then keeps visitors' attribution in a first-party cookie, so Safari doesn't forget them after 7 days.Show 3 child fieldsHide child fields
pathstringtargetstringsnippetstring
qualityobjectOf the last 7 days' events: how many had consent, came from your server, carried user data or ad click IDs, were credited to a creator, and have a location.
Show 7 child fieldsHide child fields
eventsintegerconsentedintegerfromServerintegerwithUserDataintegerwithClickIdsintegercreditedintegerlocatedinteger
versionintegerSend it back on PATCH to reject edits based on a stale read.
createdAtstringupdatedAtstring
/v1/pixels/:idRename a pixel, change its domains or excluded countries, or archive it
const { data } = await lucra.pixels.update({
path: { id: "pxl_…" },
body: { name: "…" },
})Path parameters
idpxl_…· required
Body
namestringdomainsstring[]Origins the pixel may send from, like
https://shop.example.com.excludedCountriesstring[]Countries (ISO 3166-1 alpha-2) whose visitors the pixel doesn't record, decided by the visitor's IP country.
statusstringStops the pixel accepting events; its history stays.
archivedversioninteger
Response20012 fieldsShow
idpxl_…namestringdomainsstring[]excludedCountriesstring[]statusenumverified once the first event arrives from an allowed domain; archived pixels accept no events.
waitingverifiedarchivedlastSeenAtstringnullablesnippetstringPaste before </head> on every page of the allowed domains.
firstPartyobjectRecommended: proxy
pathon your site totarget(a rewrite in Next.js, Vercel, Cloudflare or nginx) and use this snippet instead. The pixel then keeps visitors' attribution in a first-party cookie, so Safari doesn't forget them after 7 days.Show 3 child fieldsHide child fields
pathstringtargetstringsnippetstring
qualityobjectOf the last 7 days' events: how many had consent, came from your server, carried user data or ad click IDs, were credited to a creator, and have a location.
Show 7 child fieldsHide child fields
eventsintegerconsentedintegerfromServerintegerwithUserDataintegerwithClickIdsintegercreditedintegerlocatedinteger
versionintegerSend it back on PATCH to reject edits based on a stale read.
createdAtstringupdatedAtstring
/v1/conversionsCreate a conversion: the events that count as a sign-up, a purchase or your own goal
const { data } = await lucra.conversions.create({
body: { name: "…", eventName: "…" },
})Body
namestring· requiredeventNamestring· requiredThe event that counts: a standard one (purchase, sign_up, lead…) or your own.
pageUrlContainsstringnullableOnly events on pages whose URL contains this (case-insensitive).
minValueobjectOnly events in this currency with at least this value count.
Show 2 child fieldsHide child fields
amountinteger· requiredIn cents.
currencystring· requiredISO 4217, in either case.
attributionWindowDaysintegerCredits the video when the visitor converts within this many days of landing from it.
payBrowserEventsbooleanPay creators on events only the browser sent. Anyone with your pixel ID can forge those, so by default only events your server or Shopify confirmed pay.
/v1/conversionsList conversions, newest first
const { data } = await lucra.conversions.list()Query parameters
Plus paging: limit, cursor, createdAfter and createdBefore.
/v1/conversions/:idGet a conversion and how many events counted as it
const { data } = await lucra.conversions.retrieve({
path: { id: "…" },
})Path parameters
idstring· required
/v1/conversions/:idChange a conversion or archive it; events already recorded keep counting as they did
const { data } = await lucra.conversions.update({
path: { id: "…" },
body: { name: "…" },
})Path parameters
idstring· required
Body
namestringeventNamestringThe event that counts: a standard one (purchase, sign_up, lead…) or your own.
pageUrlContainsstringnullableOnly events on pages whose URL contains this (case-insensitive).
minValueobjectnullableShow 2 child fieldsHide child fields
amountinteger· requiredIn cents.
currencystring· requiredISO 4217, in either case.
attributionWindowDaysintegerCredits the video when the visitor converts within this many days of landing from it.
payBrowserEventsbooleanPay creators on events only the browser sent. Anyone with your pixel ID can forge those, so by default only events your server or Shopify confirmed pay.
statusenumactivearchivedversioninteger
/v1/conversions/:id/reportBreak a conversion down by creator, place, in-app browser, source or day, with counts and value
const { data } = await lucra.conversions.report.retrieve({
path: { id: "…" },
query: { groupBy: "…" },
})Path parameters
idstring· required
Query parameters
groupBystring· requiredUp to 3, comma-separated: creator, country, region, city, inApp, deviceType, source, day.
fromstringOnly conversions at or after this time.
tostringOnly conversions before this time.
creditedenumtrue: only conversions credited to a creator.
truefalse
Response2001 fieldsShow
dataany[]
/v1/pixel-eventsList the events your pixels received, newest first
const { data } = await lucra.pixelEvents.list({
query: { pixel: "pxl_…" },
})Query parameters
pixelpxl_…conversionconv_…attributedenumtrue: only events credited to a creator (their video or their code).
truefalse
Plus paging: limit, cursor, createdAfter and createdBefore.
/v1/pixel-events/:idGet one pixel event, with what ad platforms' conversion APIs take
const { data } = await lucra.pixelEvents.retrieve({
path: { id: "…" },
})Path parameters
idstring· required