feat: Add meta pixel conversion events (#25638)

* feat(meta-pixel): add trackingEvent to zod schema

* fix: do not allow trackingEvent to be optional

* feat(meta-pixel): add trackingEvent selection dropdown to UI

* feat(meta-pixel): add trackingEvent to Event Type App Data

* fix(meta-pixel): implement history API hook for SPA conversion tracking

* fix(meta-pixel): check for cancel in URL and prevent Re-wrapping of pushState

* Update EventTypeAppSettingsInterface.tsx

* fix: make trackingEvent optional in zod schema to fix type-check

---------

Co-authored-by: Sahitya Chandra <sahityajb@gmail.com>
This commit is contained in:
Abir Roy
2026-02-20 00:17:42 +05:30
committed by GitHub
co-authored by Sahitya Chandra
parent 60b6086221
commit 12e95a1f47
4 changed files with 45 additions and 10 deletions
@@ -25,6 +25,7 @@ export const getEventTypeAppData = <T extends EventTypeAppsList>(
currency: eventType.currency || appMetadata.currency || null,
// trackingId is legacy way to store value for TRACKING_ID. So, we need to support both.
TRACKING_ID: appMetadata.TRACKING_ID || appMetadata.trackingId || null,
TRACKING_EVENT: appMetadata.trackingEvent || "Lead",
}
: null;
}
@@ -1,5 +1,7 @@
import { useEffect } from "react";
import type { EventTypeAppSettingsComponent } from "@calcom/app-store/types";
import { TextField } from "@calcom/ui/components/form";
import { Label, Select, TextField } from "@calcom/ui/components/form";
const EventTypeAppSettingsInterface: EventTypeAppSettingsComponent = ({
getAppData,
@@ -7,16 +9,47 @@ const EventTypeAppSettingsInterface: EventTypeAppSettingsComponent = ({
disabled,
}) => {
const trackingId = getAppData("trackingId");
const trackingEvent = getAppData("trackingEvent");
type EventOption = { label: string; value: string };
const eventOptions: EventOption[] = [
{ label: "Lead", value: "Lead" },
{ label: "Complete Registration", value: "CompleteRegistration" },
{ label: "Schedule", value: "Schedule" },
{ label: "Page View (use for custom tracking)", value: "PageView" },
];
const currentOption = eventOptions.find((e) => e.value === trackingEvent) || eventOptions[0];
useEffect(() => {
if (!trackingEvent) {
setAppData("trackingEvent", "Lead");
}
}, [trackingEvent, setAppData]);
return (
<TextField
name="Pixel ID"
value={trackingId}
disabled={disabled}
onChange={(e) => {
setAppData("trackingId", e.target.value);
}}
/>
<div className="flex flex-col gap-2">
<TextField
name="Pixel ID"
value={trackingId}
disabled={disabled}
onChange={(e) => {
setAppData("trackingId", e.target.value);
}}
/>
<div className="flex flex-col gap-1">
<Label>Select Conversion Event to Fire</Label>
<Select
options={eventOptions}
value={currentOption}
isDisabled={disabled}
isSearchable={false}
onChange={(e) => {
setAppData("trackingEvent", e?.value ?? "Lead");
}}
/>
</div>
</div>
);
};
+1 -1
View File
@@ -17,7 +17,7 @@
"tag": {
"scripts": [
{
"content": "!function(f,b,e,v,n,t,s){if(f.fbq)return;n=f.fbq=function(){n.callMethod?n.callMethod.apply(n,arguments):n.queue.push(arguments)};if(!f._fbq)f._fbq=n;n.push=n;n.loaded=!0;n.version='2.0';n.queue=[];t=b.createElement(e);t.async=!0;t.src=v;s=b.getElementsByTagName(e)[0];s.parentNode.insertBefore(t,s)}(window,document,'script','https://connect.facebook.net/en_US/fbevents.js');fbq('init','{TRACKING_ID}');fbq('trackCustom','CalcomView');"
"content": "!function(f,b,e,v,n,t,s){if(f.fbq)return;n=f.fbq=function(){n.callMethod?n.callMethod.apply(n,arguments):n.queue.push(arguments)};if(!f._fbq)f._fbq=n;n.push=n;n.loaded=!0;n.version='2.0';n.queue=new Array();t=b.createElement(e);t.async=!0;t.src=v;s=b.getElementsByTagName(e).item(0);s.parentNode.insertBefore(t,s)}(window,document,'script','https://connect.facebook.net/en_US/fbevents.js');fbq('init','{TRACKING_ID}');(function(){window.calMetaCheck=function(u){var url=(typeof u==='string')?u:window.location.href;if(url.indexOf('/booking/')>-1&&url.indexOf('cancel=true')===-1){if(!window.meta_fired){fbq('track','{TRACKING_EVENT}');window.meta_fired=true;}}else{window.meta_fired=false;fbq('track','PageView');fbq('trackCustom','CalcomView');}};if(!history.__cal_meta_pixel_original_push){history.__cal_meta_pixel_original_push=history.pushState;history.pushState=function(s,t,u){history.__cal_meta_pixel_original_push.apply(history,arguments);window.calMetaCheck(u);};}if(!history.__cal_meta_pixel_original_replace){history.__cal_meta_pixel_original_replace=history.replaceState;history.replaceState=function(s,t,u){history.__cal_meta_pixel_original_replace.apply(history,arguments);window.calMetaCheck(u);};}if(!window.__cal_meta_pixel_popstate_added){window.__cal_meta_pixel_popstate_added=true;window.addEventListener('popstate',function(){window.calMetaCheck();});}window.calMetaCheck();})();"
}
]
}
+1
View File
@@ -5,6 +5,7 @@ import { eventTypeAppCardZod } from "@calcom/app-store/eventTypeAppCardZod";
export const appDataSchema = eventTypeAppCardZod.merge(
z.object({
trackingId: z.string().default("").optional(),
trackingEvent: z.enum(["Lead", "CompleteRegistration", "Schedule", "PageView"]).optional(),
})
);
export const appKeysSchema = z.object({});