LinkedIn Conversions API
Send conversions to LinkedIn server-to-server through the LinkedIn Conversions API (Linkedin-Version 202609).
Why route LinkedIn Conversions API through Datafly Signal
- Conversions survive ad blockers and tracking prevention. Signal sends the event from your own infrastructure, so the conversions LinkedIn optimises against are not filtered by the browser.
- Identifiers are hashed before they leave your infrastructure. Signal normalises and applies SHA-256 inside your own deployment, so LinkedIn receives match keys, not raw personal data.
- Click and cookie identifiers are captured first-party and replayed on later conversions, so attribution survives when the landing-page cookie has expired.
- One consent decision governs every destination. LinkedIn is gated by the same consent state as the rest of your stack, so a withdrawal applies everywhere at once.
- Presets for B2B / SaaS, Retail and Insurance. The mapping starts from a working configuration for your vertical, and every field can be changed afterwards.
Prerequisites
- A LinkedIn Campaign Manager ad account. Create one conversion rule per conversion type (Lead, Sign Up, Purchase, Request Quote and so on) with Conversions API as the data source, and note each rule ID (the number after
/conversions/in the rule’s URL). - A LinkedIn developer application with Advertising API access. Copy its Client ID and Client Secret.
- Authorise the application for a member with access to the ad account, with the
rw_conversionsscope, and keep the refresh token (valid for a year). Signal uses it to mint access tokens.
Configuration
| Field | Type | Required | Description |
|---|---|---|---|
client_id | string | Yes | The Client ID of your LinkedIn developer application with Advertising API access (LinkedIn Developer Portal > My apps > Auth). |
client_secret | secret | Yes | The Primary Client Secret of the same application. Sent only to LinkedIn’s token endpoint when the access token is refreshed. |
refresh_token | secret | Yes | A LinkedIn OAuth 2.0 refresh token (valid for a year) for a member with access to the ad account, issued with the rw_conversions scope. Delivery exchanges it for short-lived access tokens. |
conversion_rule_id | string | Yes | The conversion rule events are streamed to when their type has no rule of its own below. Find it in Campaign Manager: the number after /conversions/ in the rule’s URL. |
conversion_rule_id_lead | string | No | Optional. The conversion rule for Lead events. A conversion rule has one conversion type, so give each type its own rule to report them separately. |
conversion_rule_id_sign_up | string | No | Optional. The conversion rule for Sign Up events. A conversion rule has one conversion type, so give each type its own rule to report them separately. |
conversion_rule_id_request_quote | string | No | Optional. The conversion rule for Request Quote events. A conversion rule has one conversion type, so give each type its own rule to report them separately. |
conversion_rule_id_submit_application | string | No | Optional. The conversion rule for Submit Application events. A conversion rule has one conversion type, so give each type its own rule to report them separately. |
conversion_rule_id_add_to_cart | string | No | Optional. The conversion rule for Add to Cart events. A conversion rule has one conversion type, so give each type its own rule to report them separately. |
conversion_rule_id_start_checkout | string | No | Optional. The conversion rule for Start Checkout events. A conversion rule has one conversion type, so give each type its own rule to report them separately. |
conversion_rule_id_purchase | string | No | Optional. The conversion rule for Purchase events. A conversion rule has one conversion type, so give each type its own rule to report them separately. |
conversion_rule_id_subscribe | string | No | Optional. The conversion rule for Subscribe events. A conversion rule has one conversion type, so give each type its own rule to report them separately. |
conversion_rule_id_download | string | No | Optional. The conversion rule for Download events. A conversion rule has one conversion type, so give each type its own rule to report them separately. |
conversion_rule_id_book_appointment | string | No | Optional. The conversion rule for Book Appointment events. A conversion rule has one conversion type, so give each type its own rule to report them separately. |
access_token | secret | No | Not read: delivery mints access tokens from the refresh token above, so the integration does not stop when a 60-day access token expires. Retained for existing integrations. |
account_id | string | No | Your LinkedIn Ads account ID. Not sent on conversion events (the rule belongs to the account); kept for reference. |
api_version | string | No | Not read: the delivery spec sends Linkedin-Version 202609. Retained for existing integrations. |
linkedin_version | string | No | Not read: the delivery spec sends Linkedin-Version 202609. Retained for existing integrations. |
Configure in Signal
- In the Management UI, go to Integrations > Integration Library and select LinkedIn Ads.
- Choose a preset, fill in the fields above and choose the pipelines and consent categories (advertising destinations default to marketing).
- Click Install Integration.
Or with the Management API:
curl -X POST http://localhost:8084/v1/admin/integration-catalog/linkedin/install \
-H "Authorization: Bearer YOUR_TOKEN" -H "Content-Type: application/json" \
-d '{"name": "LinkedIn Ads", "variant": "default", "config": {"client_id": "86abc123def456", "client_secret": "...", "refresh_token": "AQX...", "conversion_rule_id": "12345678"}, "delivery_mode": "server_side"}'API endpoint
POST https://api.linkedin.com/rest/conversionEventsAuthentication: OAuth 2.0 Bearer token, refreshed from the refresh token. Allow egress to api.linkedin.com from the network your delivery workers run on.
Presets and event mapping
Every preset sends only the fields it maps (the strict output contract is on). Events not listed are not sent.
B2B / SaaS (saas)
B2B lead and subscription conversions: leads, demo requests, content downloads, sign-ups, trials and paid subscriptions, each streamed to the conversion rule configured for its type.
| Signal event | LinkedIn event |
|---|---|
generate_lead | rule for lead |
demo_requested | rule for book_appointment |
content_downloaded | rule for download |
sign_up | rule for sign_up |
trial_started | rule for sign_up |
subscription_started | rule for subscribe |
Retail (ecommerce)
Retail conversions: add to cart, checkout start, purchases with value and the order ID as event ID for Insight Tag deduplication, sign-ups and leads.
| Signal event | LinkedIn event |
|---|---|
add_to_cart | rule for add_to_cart |
begin_checkout | rule for start_checkout |
purchase | rule for purchase |
sign_up | rule for sign_up |
generate_lead | rule for lead |
Default (default)
LinkedIn Conversions API core conversions: leads, sign-ups and purchases, matched on the hashed email, the li_fat_id click ID and (when both are known) hashed first and last name.
| Signal event | LinkedIn event |
|---|---|
generate_lead | rule for lead |
sign_up | rule for sign_up |
purchase | rule for purchase |
Insurance (insurance)
Insurance conversions: quote requests (Request Quote), leads, applications (Submit Application) and policy purchases with premium value and the policy number as event ID.
| Signal event | LinkedIn event |
|---|---|
get_quote | rule for request_quote |
quote_requested | rule for request_quote |
generate_lead | rule for lead |
lead_submitted | rule for lead |
begin_checkout | rule for submit_application |
purchase | rule for purchase |
policy_purchased | rule for purchase |
Identity and hashing
| LinkedIn field | Signal source | Treatment |
|---|---|---|
user.userIds[] SHA256_EMAIL | $traits.email | trim, lowercase, SHA-256 |
user.userIds[] LINKEDIN_FIRST_PARTY_ADS_TRACKING_UUID | li_fat_id click ID | sent as captured |
user.userInfo.hashedFirstName, hashedLastName | $traits.first_name, last_name (only as a pair) | trim, lowercase, SHA-256 |
user.externalIds[] | user_id | SHA-256 |
Email, phone and names come from datafly.identify() traits (a legacy properties.email / properties.phone is read when no trait is set). Raw personal data is never sent.
Deduplication and consent
eventId carries the Signal event ID, or the order ID on purchases, for deduplication against the Insight Tag. Each event is sent to the conversion rule configured for its type, else to the default rule. An event with neither an email nor an li_fat_id is not sent, because LinkedIn rejects it and one rejected conversion fails its whole batch. Conversions must be less than 90 days old.
Example: purchase (Default preset)
datafly.identify('crm-user-7', { email: 'jane.doe@example.com', phone: '07700 900123', first_name: 'Jane', last_name: 'Doe' });
datafly.track('purchase', {
transaction_id: 'T_1001', value: 139.99, currency: 'GBP',
items: [
{ item_id: 'SKU_1', item_name: 'Helmet', item_category: 'Motorbike', item_brand: 'Shoei', price: 120.00, quantity: 2 },
{ item_id: 'SKU_2', item_name: 'Gloves', price: 19.99, quantity: 1 }
]
});Request Signal sends (rendered from the preset):
{
"elements": [
{
"conversion": "urn:lla:llaPartnerConversion:999",
"conversionHappenedAt": 1758500000123,
"conversionValue": {
"amount": "139.99",
"currencyCode": "GBP"
},
"eventId": "T_1001",
"user": {
"externalIds": [
"a1a37b21e9d35da94d0ae0b42483e449206f1e24c3790d28c113fb5fb9045f93"
],
"userIds": [
{
"idType": "SHA256_EMAIL",
"idValue": "86e0b9e56c17cc4d12387e1949b85053fbe73bc3ce5a1188713a9d300cc6133d"
},
{
"idType": "LINKEDIN_FIRST_PARTY_ADS_TRACKING_UUID",
"idValue": "lifat1"
}
],
"userInfo": {
"hashedFirstName": "81f8f6dde88365f3928796ec7aa53f72820b06db8664f5fe76a7eb13e24546a2",
"hashedLastName": "799ef92a11af918e3fb741df42934f3b568ed2d93ac1df74f1b8d41a27932a6f"
}
}
}
]
}Known limitations
- Name hashing trims and lowercases but does not remove spaces and punctuation as LinkedIn documents (#1390).
Troubleshooting
| Symptom | Cause | Resolution |
|---|---|---|
401 / 403 | Invalid, expired or under-privileged credential | Re-issue the credential described under Prerequisites and update the integration. |
400 | A field the vendor rejects | Open the event in the Delivery Log; the vendor’s message names the field. |
| Event dead-lettered with a required-field error | A value the vendor requires is missing (for example currency and value on a purchase) | Send the property in the track() call, or map it in the integration. |
| Low match rate | Few identifiers | Call datafly.identify() with email and phone when you know them, and keep click-ID capture enabled. |