Guide · Tracking & analytics
LinkedIn conversion tracking for Microsoft Bookings
Last updated 10 min read10 sources
As of October 2026, you can't put the LinkedIn Insight Tag on a Microsoft Bookings page. Microsoft hosts the page, gives you no field for tags or scripts, and doesn't redirect to your site after someone books. What you can do is fire a LinkedIn conversion when someone clicks through to book from your own site, keep the visitor's LinkedIn click ID (li_fat_id), and send each completed booking to LinkedIn's Conversions API from a Power Automate flow. This guide covers all three. It's for B2B marketers running LinkedIn campaigns to a "book a demo" or "book a call" page, and for the developer helping them.
The Meta Pixel and Conversions API guide has a short LinkedIn section. This page goes further, with LinkedIn's own access, payload and matching rules.
Why the Insight Tag can't see a booking#
The Insight Tag is JavaScript that runs on pages you control. A Microsoft Bookings page lives at outlook.office.com/book/..., with no script field, no custom confirmation page and no redirect. People asking on Microsoft Q&A about adding a conversion pixel were sent to other forums. See Can I add a Meta pixel to Microsoft Bookings? for those threads. The same answer applies to LinkedIn.
Embedding the page doesn't help either. If you put Bookings in an iframe, the tag on your page can't read anything inside it, because the frame is on another origin. It can't even see the click on the final "Book" button. GTM and the Bookings iframe explains why. With an iframe, the most your page can record is that the frame came into view.
That leaves three signals:
| Signal | Where it comes from | Good for bidding? |
|---|---|---|
| Book-link click (or iframe view) | Insight Tag on your page | No. Intent only |
li_fat_id kept on your side | Your page, before the visitor leaves | Not a conversion on its own. It improves matching |
| Completed booking | Conversions API, sent from a Power Automate flow | Yes |
Before you start#
- The Insight Tag on every page of your site, installed directly or through GTM, with enhanced conversion tracking turned on. LinkedIn says this adds
li_fat_idto ad landing page URLs and is on by default for newly created tags. - A role on the LinkedIn ad account that can create conversions. For the API, LinkedIn requires a role other than Viewer.
- For level 3: the Administrator role on the Bookings calendar, Power Automate, and somewhere to run a small HTTPS endpoint (Azure Functions, a serverless worker or your web backend).
Level 1: an event-specific conversion on the Book click#
- In Campaign Manager, go to Measure → Conversion tracking → Create conversion and choose Insight Tag conversion.
- Name it so nobody mistakes it for a booking, for example "Bookings link click". Pick a category, set the value and attribution model, and choose the ad sets it applies to.
- Under the tracking method, choose Manual conversions setup → Event-specific, and copy the code. It contains a numeric
conversion_id. - In GTM, create a Custom HTML tag that fires on the "Bookings link click" trigger from the GA4 and GTM guide. That trigger matches
outlook.office.com/book/links, older/owa/calendar/links andbook.msshort links.
<script>
if (window.lintrk) {
window.lintrk("track", { conversion_id: 1234567 });
}
</script>The menu names are LinkedIn's as of October 2026. If they move, the conversion ID is what matters.
Two points about counting. LinkedIn counts most conversion types once per member within the lookback window, so someone who clicks Book three times counts once. And a click doesn't mean a booking. If campaigns optimise on this conversion, LinkedIn finds people who click and leave. Use it for reporting until level 3 is live.
Level 2: keep li_fat_id and pass a key through RefID#
LinkedIn's Conversions API matches a server event to a member through identifiers such as a SHA-256 hashed email or the li_fat_id click ID. A hashed email only matches if the person booked with the email on their LinkedIn account. B2B visitors often book with a work address that isn't on their profile, so li_fat_id is worth keeping.
According to LinkedIn, you can read li_fat_id from the landing page URL, or from the li_fat_id cookie that the Insight Tag sets. The cookie lasts 30 days from the last ad click. LinkedIn keeps the mapping from click ID to member for 365 days, so an ID captured today can still match a booking made weeks later.
The only thing Microsoft Bookings carries from your link into the appointment is RefID. Microsoft allows letters, digits, underscores and hyphens in it, and it shows up in the connector's Tracking data field. Give each visitor a short random key, store their click ID under that key on your server, and put only the key in the link:
(function () {
var params = new URLSearchParams(location.search);
var m = document.cookie.match(/(?:^|;\s*)li_fat_id=([^;]+)/);
var liFatId = params.get("li_fat_id") || (m ? decodeURIComponent(m[1]) : null);
var key = sessionStorage.getItem("bk_key");
if (!key) {
key = "k" + crypto.randomUUID().replace(/-/g, "").slice(0, 15);
sessionStorage.setItem("bk_key", key);
}
document.querySelectorAll('a[href*="outlook.office"]').forEach(function (a) {
var url = new URL(a.href);
if (!/\/(book|owa\/calendar)\//.test(url.pathname)) return;
url.search = "";
url.searchParams.set("RefID", key);
a.href = url.toString();
a.addEventListener("click", function () {
navigator.sendBeacon("/api/booking-intent",
JSON.stringify({ key: key, liFatId: liFatId, pageUrl: location.href }));
});
});
})();Run it only when the visitor has consented to advertising cookies, under the same rule your consent tool uses for the Insight Tag. The storage endpoint is the same as the one in the Meta guide. If you run both, store li_fat_id next to the Meta cookies under one key. If you also need a gclid or campaign code, the lookup-key approach in passing UTM parameters into Bookings carries all of them through one RefID.
RefID has known problems. Users have reported Bad Request pages and blank Tracking data, so make a test booking through a tagged link before you rely on it. See RefID not working.
Level 3: send completed bookings with the Conversions API#
Step 1: Get a token and create the conversion#
You don't need a developer app for your own ad account. LinkedIn lets advertisers generate a token in Campaign Manager: Measure → Signals manager → Direct API → Generate access token. LinkedIn doesn't store the token, so save it in a secrets store as soon as you copy it. LinkedIn's API docs say these tokens don't expire, so treat it like a password. Developer Portal access, where an app has to be approved for the Conversions API, is for partners building integrations for other advertisers.
Then create the conversion:
- Measure → Conversion tracking → Create conversion → Conversions API.
- Name it "Booked meeting - Bookings", choose a booking category, set the value, windows and attribution model, and click Next step.
- Choose Direct API, review the ad sets it applies to, and create it.
- Open the conversion and copy the number after
/conversions/in the Campaign Manager URL. You'll send it asurn:lla:llaPartnerConversion:<number>.
Step 2: The flow#
- Trigger: When a appointment is Created (Microsoft Bookings), with your booking page's SMTP address.
- Condition: Tracking data starts with
k. - HTTP action: POST to
https://your-domain.example/api/booking-createdwith a shared-secret header and this body, mapped from Dynamic content:
{
"refId": "TrackingData value",
"email": "Customer email value",
"appointmentId": "SelfServiceAppointmentId value"
}Microsoft marks the connector's Id field as deprecated, so use SelfServiceAppointmentId. The limits from the other guides apply here too. The connector is in Preview. Only Bookings admins can create these flows, and each Bookings mailbox allows five. The HTTP action is a Premium connector in Power Automate. In a group booking, only the first attendee fires Created.
Step 3: The endpoint call to LinkedIn#
The endpoint looks up the key, normalises and hashes the email, and holds the LinkedIn token, so the token stays out of the flow's run history:
const user = { userIds: [
{ idType: "SHA256_EMAIL", idValue: sha256(email.replace(/\s/g, "").toLowerCase()) }
] };
if (intent?.liFatId) {
user.userIds.push({ idType: "LINKEDIN_FIRST_PARTY_ADS_TRACKING_UUID", idValue: intent.liFatId });
}
await fetch("https://api.linkedin.com/rest/conversionEvents", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.LI_CAPI_TOKEN}`,
"Content-Type": "application/json",
"LinkedIn-Version": "202609",
"X-Restli-Protocol-Version": "2.0.0"
},
body: JSON.stringify({
conversion: `urn:lla:llaPartnerConversion:${process.env.LI_CONVERSION_ID}`,
conversionHappenedAt: Date.now(),
eventId: appointmentId,
user
})
});LinkedIn returns 201 Created when it accepts the event. The flow runs within moments of the booking, so the current time is the booking time. LinkedIn rejects any conversionHappenedAt older than 90 days. Use a current LinkedIn-Version: LinkedIn retires old versions on a schedule, and the October 2025 version is sunset on 15 October 2026.
A booking without a key can still be sent with only the hashed email. It just matches less often.
De-duplication#
The browser conversion from level 1 is a click and the server conversion is a booking, so they never describe the same event. Nothing needs de-duplicating. LinkedIn only de-duplicates when the same event arrives through both the Insight Tag and the API with the same eventId, and it needs a separate conversion rule for each source. Then it keeps the Insight Tag event. That matters only if the booking itself happens on your page, as in the last section.
Testing#
- The click. With GTM Preview open, click a Book link and confirm the Custom HTML tag fires once. In the browser's network tab, a request goes to
px.ads.linkedin.com. - The link. Visit your site with
?li_fat_id=test-123, click Book, and check that the Bookings URL ends in?RefID=k...and that your endpoint stored the click ID under that key. - The flow. Make a test booking through that link. In the flow's run history, Tracking data should hold the key and the HTTP action should get a 2xx.
- LinkedIn. Check the endpoint logged a
201from LinkedIn. On Conversion tracking in Campaign Manager, the status moves from Unverified to Active once events arrive. A "Low Match Rate" note means the events reached LinkedIn but few matched a member. - Cancel the test appointment in Bookings as usual.
Common problems#
The conversion stays Unverified. For level 1, the Insight Tag didn't load (often blocked by the cookie banner), or the tag fired before lintrk existed. For level 3, events aren't reaching LinkedIn. Check the endpoint's logs for 4xx responses.
401 or 403 from LinkedIn. The token is missing or wrong, or the person who generated it has only the Viewer role on the ad account.
400 about conversion time. The event is more than 90 days old, usually because failed runs were replayed late. Let those go.
Low match rate. Enhanced conversion tracking is off, so there's no li_fat_id. Or visitors book with work emails that aren't on their LinkedIn profiles, or the email wasn't lowercased and stripped of spaces before hashing.
Bookings with no key. People book from links you didn't tag, such as Microsoft's confirmation email, a bookmark or a forwarded link. Staff-made bookings never have one.
The Book click doesn't fire on an embedded page. The click happens inside Microsoft's iframe. Use a link to the Bookings page, or count iframe views instead.
Privacy. You're sending hashed customer emails and click IDs to LinkedIn. Update your privacy notice and respect consent choices before you turn this on.
Doing this with BookingsXP#
BookingsXP runs the booking in a widget on your own page, in front of your existing Bookings page, so the Insight Tag on that page sees the confirmed booking itself rather than a click. On Pro, add your LinkedIn conversion ID in the widget's Tracking tab. When Microsoft Bookings confirms the appointment, the loader calls window.lintrk("track", { conversion_id: ... }), but only if your Insight Tag is already on the page. It never loads a second copy of the tag. The exception is the hosted booking page, which has no site tag of its own and loads the Insight Tag from the partner ID you set. On Free, a GTM Custom HTML tag on the bookingsxp.booking_completed Custom Event trigger can make the same call. If you also plan to send server events, the GTM route lets you add event_id set to the booking reference. The built-in call doesn't send one.
The widget captures li_fat_id from the landing page URL along with UTMs and other click IDs, and keeps the first touch for 90 days. The booking notes in Microsoft Bookings record that a LinkedIn ad click was present. The li_fat_id value itself is in the booking.created webhook payload (Pro, with Store bookings switched on). BookingsXP doesn't send LinkedIn Conversions API events. If you want them, send the webhook to your own endpoint and post to LinkedIn as in step 3, with no RefID or Power Automate needed. It only covers bookings made through the widget or hosted page, not bookings made on Microsoft's page or by staff. See the LinkedIn integration, tracking docs, plans, or try it with your booking page. BookingsXP is independent and not affiliated with or endorsed by Microsoft.
Questions people also ask
Sources
- Microsoft Learn: Customize booking page (opens in a new tab) · learn.microsoft.com
- Microsoft Learn (opens in a new tab) · learn.microsoft.com
- linkedin.com (opens in a new tab) · linkedin.com
- linkedin.com (opens in a new tab) · linkedin.com
- Microsoft Learn: Conversions overview (opens in a new tab) · learn.microsoft.com
- Microsoft Learn: Conversions api (opens in a new tab) · learn.microsoft.com
- Microsoft Learn: Conversions api schema (opens in a new tab) · learn.microsoft.com
- Microsoft Learn: Enabling first party cookies (opens in a new tab) · learn.microsoft.com
- Microsoft Learn (opens in a new tab) · learn.microsoft.com
- Microsoft Learn: Conversions usecase (opens in a new tab) · learn.microsoft.com
Related
- Meta Pixel and Conversions API for Microsoft Bookings
- Google Ads conversion tracking for Microsoft Bookings
- Microsoft Ads (Bing) UET conversions for Microsoft Bookings
- Pass UTM parameters and gclid into Microsoft Bookings
- Why is RefID tracking blank or Bad Request in Bookings?
- Can GTM track bookings inside the Microsoft Bookings iframe?