Privacy-First Measurement: Server-Side Tagging, Consent Mode and Conversion APIsConversion APIs: Meta, Google, TikTok and LinkedIn · Lesson 9 of 14

TikTok Events API and LinkedIn Conversions API

Article · 8 min · 8 min lecture

Video lecture

TikTok Events API and LinkedIn Conversions API

13 chapters · about 8 min · full transcript

Coming soon

Chapter 1 of 13

TikTok Events API and LinkedIn CAPI

  • Same pattern
  • TikTok specifics
  • LinkedIn specifics
  • B2B example

The narrated lecture is in production

Every chapter is scripted and ready. Browse the chapters and read the full transcript now — the video will appear here when it’s published.

Chapters

Same pattern, different fields

TikTok and LinkedIn follow the same server-side pattern as Meta: send conversion events from your server, hash identifiers, include platform click IDs and browser identifiers, and deduplicate with the browser tag using a shared event ID.

TikTok Events APILinkedIn Conversions API
Browser tagTikTok PixelLinkedIn Insight Tag
Click IDttclid (URL), _ttp cookieli_fat_id (URL/first-party cookie)
DedupSame event + event_id in Pixel and Events APIeventId shared with Insight Tag conversion
IdentifiersHashed email, phone, external_id; IP; user agentHashed email (SHA256_EMAIL), LinkedIn first-party tracking UUID, name/company/country as user info
Typical useE-commerce, app, lead genB2B leads and CRM stages (online and offline)
Setup routesPartner integrations, server GTM templates, direct APIPartner integrations (e.g., CRM connectors), GTM, direct API

TikTok Events API

The Events API endpoint (v1.3 at the time of writing) accepts batches of events with an access token generated in TikTok Events Manager.

import os, time, hashlib, requests

PIXEL_CODE = os.environ["TIKTOK_PIXEL_CODE"]
TOKEN = os.environ["TIKTOK_EVENTS_TOKEN"]
URL = "https://business-api.tiktok.com/open_api/v1.3/event/track/"
sha = lambda v: hashlib.sha256(v.strip().lower().encode()).hexdigest()

def tiktok_purchase(order, req, consent_ads: bool, test_code: str | None = None):
    if not consent_ads:
        return None
    body = {
        "event_source": "web",
        "event_source_id": PIXEL_CODE,
        "data": [{
            "event": "CompletePayment",
            "event_time": int(time.time()),
            "event_id": f"order_{order['id']}",
            "user": {
                "email": sha(order["email"]),
                "phone": sha(order["phone_e164"]),
                "external_id": sha(str(order["customer_id"])),
                "ttclid": req["cookies"].get("ttclid") or req.get("ttclid"),
                "ttp": req["cookies"].get("_ttp"),
                "ip": req["ip"], "user_agent": req["user_agent"],
            },
            "page": {"url": order["thank_you_url"]},
            "properties": {"currency": order["currency"], "value": order["value"],
                           "contents": [{"content_id": i["sku"], "quantity": i["qty"], "price": i["price"]} for i in order["items"]],
                           "content_type": "product"},
        }],
    }
    if test_code:
        body["test_event_code"] = test_code
    r = requests.post(URL, headers={"Access-Token": TOKEN, "Content-Type": "application/json"}, json=body, timeout=10)
    r.raise_for_status()
    data = r.json()
    if data.get("code") != 0:
        raise RuntimeError(f"TikTok Events API error: {data}")
    return data

Check the TikTok Events API documentation for the current version, phone normalization rules and supported standard events. Capture ttclid from the landing URL and store it (first-party) so the server can send it.

LinkedIn Conversions API

LinkedIn's API uses versioned REST endpoints. You create a conversion rule in Campaign Manager (or via API), then stream events to /rest/conversionEvents with an OAuth access token that has the right permissions.

import os, time, hashlib, requests

TOKEN = os.environ["LINKEDIN_ACCESS_TOKEN"]
LI_VERSION = os.environ.get("LINKEDIN_API_VERSION", "202608")  # YYYYMM; use a currently supported version
RULE_URN = os.environ["LINKEDIN_CONVERSION_RULE_URN"]  # e.g. urn:lla:llaPartnerConversion:123456

def linkedin_sql(lead, stage_value: float, currency="USD", consent_ads=True):
    if not consent_ads:
        return None
    ids = [{"idType": "SHA256_EMAIL", "idValue": hashlib.sha256(lead["email"].strip().lower().encode()).hexdigest()}]
    if lead.get("li_fat_id"):
        ids.append({"idType": "LINKEDIN_FIRST_PARTY_ADS_TRACKING_UUID", "idValue": lead["li_fat_id"]})
    event = {
        "conversion": RULE_URN,
        "conversionHappenedAt": int(time.time() * 1000),  # milliseconds
        "conversionValue": {"currencyCode": currency, "amount": f"{stage_value:.2f}"},
        "user": {"userIds": ids,
                 "userInfo": {"firstName": lead["first_name"], "lastName": lead["last_name"],
                              "companyName": lead.get("company", ""), "countryCode": lead.get("country", "")}},
        "eventId": f"lead_{lead['id']}_sql",
    }
    r = requests.post("https://api.linkedin.com/rest/conversionEvents", json=event, timeout=10,
                      headers={"Authorization": f"Bearer {TOKEN}", "LinkedIn-Version": LI_VERSION,
                               "X-Restli-Protocol-Version": "2.0.0", "Content-Type": "application/json"})
    if r.status_code >= 400:
        raise RuntimeError(f"LinkedIn CAPI error {r.status_code}: {r.text}")
    return r.status_code

LinkedIn documents rate limits and batch endpoints; check the Microsoft Learn LinkedIn Marketing API docs for current versions and limits.

Both APIs accept batched events; batch when you process conversions in bulk (for example a nightly CRM sync), and send individually in near real time for web purchases. Build a small outbox table: write each event to the table when the conversion happens, have a worker send it, record the response, and retry with backoff on network errors or rate limiting (HTTP 429). Store the consent state that applied at the time of the conversion and check it before sending. This pattern makes server-side feeds auditable: for any conversion you can show what was sent, when, with what consent, and what the platform replied.

Worked example: a UK cybersecurity SaaS

The company runs LinkedIn and TikTok (for employer brand and SMB awareness). LinkedIn: Insight Tag for demo requests with eventId; CRM (HubSpot) sends "SQL" and "Opportunity" stages via the Conversions API, stage values from historical close rates. TikTok: Events API for free-trial sign-ups deduplicated with the Pixel. Both honor the CMP's advertising consent. Within a quarter, LinkedIn campaigns optimized toward SQLs instead of raw form fills.

Pitfalls

  • LinkedIn timestamps in seconds instead of milliseconds.
  • Unversioned or deprecated LinkedIn API versions.
  • Forgetting to capture ttclid/li_fat_id at landing.
  • Different event IDs in browser and server events.

How to measure success

Events visible in each platform's event diagnostics or conversion tracking pages, dedup working, match rates improving, and qualified-stage conversions steering bidding.

Key takeaways

  • TikTok and LinkedIn follow the same server-side pattern: hashed IDs, click IDs, browser IDs and shared event IDs for dedup.
  • TikTok Events API: event_source_id = Pixel code, Access-Token header, events with event_id and hashed user data.
  • LinkedIn Conversions API: versioned REST, conversion rule URN, millisecond timestamps, SHA256_EMAIL and li_fat_id.
  • Capture ttclid and li_fat_id at landing and store them first-party.
  • Respect advertising consent and check current API versions and limits.

Check your understanding

Quick questions to lock in the lesson. They don’t count towards your certificate.

  1. What unit does LinkedIn's conversionHappenedAt use?
  2. Which identifier helps TikTok match a server event to an ad click?
  3. How is dedup achieved between the TikTok Pixel and Events API?

Put it into practice

Pick TikTok or LinkedIn. Write the event mapping for your top two conversions: event name, event ID source, identifiers, value, and where click IDs are captured and stored.

Enrol for free to save your progress

Reading is always free. Enrol to keep your place, take the final assessment and earn a verifiable certificate.