diff --git a/packages/browser-destinations/destinations/tiktok-pixel/src/identify/generated-types.ts b/packages/browser-destinations/destinations/tiktok-pixel/src/identify/generated-types.ts index ac49bf05424..5cef7f60c71 100644 --- a/packages/browser-destinations/destinations/tiktok-pixel/src/identify/generated-types.ts +++ b/packages/browser-destinations/destinations/tiktok-pixel/src/identify/generated-types.ts @@ -1,6 +1,10 @@ // Generated file. DO NOT MODIFY IT BY HAND. export interface Payload { + /** + * Include fields for travel or vehicle events. + */ + event_spec_type?: string /** * Conversion event name. Please refer to the "Supported Web Events" section on in TikTok’s [Pixel SDK documentation](https://business-api.tiktok.com/portal/docs?id=1739585696931842) for accepted event names. */ @@ -87,6 +91,14 @@ export interface Payload { */ brand?: string }[] + /** + * Product IDs associated with the event, such as SKUs. Do not populate this field if the 'Contents' field is populated. This field accepts a single string value or an array of string values. + */ + content_ids?: string[] + /** + * Number of items when checkout was initiated. Used with the InitiateCheckout event. + */ + num_items?: number /** * Type of the product item. When the `content_id` in the `Contents` field is specified as a `sku_id`, set this field to `product`. When the `content_id` in the `Contents` field is specified as an `item_group_id`, set this field to `product_group`. */ @@ -107,4 +119,8 @@ export interface Payload { * The text string that was searched for. */ query?: string + /** + * The text string entered by the user for the search. Optionally used with the Search event. + */ + search_string?: string } diff --git a/packages/browser-destinations/destinations/tiktok-pixel/src/identify/index.ts b/packages/browser-destinations/destinations/tiktok-pixel/src/identify/index.ts index e73bae13630..2767a001a36 100644 --- a/packages/browser-destinations/destinations/tiktok-pixel/src/identify/index.ts +++ b/packages/browser-destinations/destinations/tiktok-pixel/src/identify/index.ts @@ -1,9 +1,9 @@ import type { BrowserActionDefinition } from '@segment/browser-destination-runtime/types' import type { Settings } from '../generated-types' import type { Payload } from './generated-types' -import { formatPhone, handleArrayInput, formatString, formatAddress } from '../formatter' +import { getUser } from '../utils' import { TikTokPixel } from '../types' -import { commonFields } from '../common_fields' +import { commonFields } from '../reportWebEvent/fields/common_fields' // Change from unknown to the partner SDK types const action: BrowserActionDefinition = { @@ -40,19 +40,9 @@ const action: BrowserActionDefinition = { } } }, - perform: (ttq, { payload }) => { + perform: (ttq, { payload, settings }) => { if (payload.email || payload.phone_number || payload.external_id) { - ttq.identify({ - email: handleArrayInput(payload.email), - phone_number: formatPhone(handleArrayInput(payload.phone_number)), - external_id: handleArrayInput(payload.external_id), - first_name: formatString(payload.first_name), - last_name: formatString(payload.last_name), - city: formatAddress(payload.address?.city), - state: formatAddress(payload.address?.state), - country: formatAddress(payload.address?.country), - zip_code: formatString(payload.address?.zip_code) - }) + ttq.instance(settings.pixelCode).identify(getUser(payload)) } } } diff --git a/packages/browser-destinations/destinations/tiktok-pixel/src/reportWebEvent/constants.ts b/packages/browser-destinations/destinations/tiktok-pixel/src/reportWebEvent/constants.ts new file mode 100644 index 00000000000..9c10e826fa0 --- /dev/null +++ b/packages/browser-destinations/destinations/tiktok-pixel/src/reportWebEvent/constants.ts @@ -0,0 +1,2 @@ +export const VEHICLE_FIELDS = 'vehicle_fields' +export const TRAVEL_FIELDS = 'travel_fields' diff --git a/packages/browser-destinations/destinations/tiktok-pixel/src/common_fields.ts b/packages/browser-destinations/destinations/tiktok-pixel/src/reportWebEvent/fields/common_fields.ts similarity index 83% rename from packages/browser-destinations/destinations/tiktok-pixel/src/common_fields.ts rename to packages/browser-destinations/destinations/tiktok-pixel/src/reportWebEvent/fields/common_fields.ts index e4111ed6ef5..772e9c37743 100644 --- a/packages/browser-destinations/destinations/tiktok-pixel/src/common_fields.ts +++ b/packages/browser-destinations/destinations/tiktok-pixel/src/reportWebEvent/fields/common_fields.ts @@ -1,6 +1,16 @@ import { InputField } from '@segment/actions-core' +import { VEHICLE_FIELDS, TRAVEL_FIELDS } from '../constants' export const commonFields: Record = { + event_spec_type: { + label: 'Additional Fields', + type: 'string', + description: 'Include fields for travel or vehicle events.', + choices: [ + { value: TRAVEL_FIELDS, label: 'Travel Fields' }, + { value: VEHICLE_FIELDS, label: 'Vehicle Fields' } + ] + }, event: { label: 'Event Name', type: 'string', @@ -195,6 +205,24 @@ export const commonFields: Record = { } } }, + content_ids: { + label: 'Content IDs', + description: + "Product IDs associated with the event, such as SKUs. Do not populate this field if the 'Contents' field is populated. This field accepts a single string value or an array of string values.", + type: 'string', + multiple: true, + default: { + '@path': '$.properties.content_ids' + } + }, + num_items: { + label: 'Number of Items', + type: 'number', + description: 'Number of items when checkout was initiated. Used with the InitiateCheckout event.', + default: { + '@path': '$.properties.num_items' + } + }, content_type: { label: 'Content Type', description: @@ -238,5 +266,22 @@ export const commonFields: Record = { default: { '@path': '$.properties.query' } + }, + search_string: { + label: 'Search String', + type: 'string', + description: 'The text string entered by the user for the search. Optionally used with the Search event.', + default: { + '@path': '$.properties.search_string' + }, + depends_on: { + conditions: [ + { + fieldKey: 'event', + operator: 'is', + value: 'Search' + } + ] + } } } diff --git a/packages/browser-destinations/destinations/tiktok-pixel/src/reportWebEvent/fields/travel_fields.ts b/packages/browser-destinations/destinations/tiktok-pixel/src/reportWebEvent/fields/travel_fields.ts new file mode 100644 index 00000000000..a0dbdd47489 --- /dev/null +++ b/packages/browser-destinations/destinations/tiktok-pixel/src/reportWebEvent/fields/travel_fields.ts @@ -0,0 +1,216 @@ +import { InputField } from '@segment/actions-core' +import { TRAVEL_FIELDS } from '../constants' + +export const travel_fields: InputField = { + label: 'Travel Fields', + type: 'object', + description: 'Fields related to travel events.', + additionalProperties: false, + defaultObjectUI: 'keyvalue', + properties: { + city: { + label: 'Hotel City Location', + type: 'string', + description: 'Hotel city location.' + }, + region: { + label: 'Hotel Region', + type: 'string', + description: 'Hotel region location.' + }, + country: { + label: 'Hotel Country', + type: 'string', + description: 'Hotel country location.' + }, + checkin_date: { + label: 'Hotel Check-in Date', + type: 'string', + description: 'Hotel check-in date.' + }, + checkout_date: { + label: 'Hotel Check-out Date', + type: 'string', + description: 'Hotel check-out date.' + }, + num_adults: { + label: 'Number of Adults', + type: 'number', + description: 'Number of adults.' + }, + num_children: { + label: 'Number of Children', + type: 'number', + description: 'Number of children.' + }, + num_infants: { + label: 'Number of Infants', + type: 'number', + description: 'Number of infants flying.' + }, + suggested_hotels: { + label: 'Suggested Hotels', + description: 'Suggested hotels. This can be a single string value or an array of string values.', + type: 'string', + multiple: true + }, + departing_departure_date: { + label: 'Departure Date', + type: 'string', + description: + 'Date of flight departure. Accepted date formats: YYYYMMDD, YYYY-MM-DD, YYYY-MM-DDThh:mmTZD, and YYYY-MM-DDThh:mm:ssTZD' + }, + returning_departure_date: { + label: 'Arrival Date', + type: 'string', + description: + 'Date of return flight. Accepted date formats: YYYYMMDD, YYYY-MM-DD, YYYY-MM-DDThh:mmTZD, and YYYY-MM-DDThh:mm:ssTZD' + }, + origin_airport: { + label: 'Origin Airport', + type: 'string', + description: 'Origin airport.' + }, + destination_airport: { + label: 'Destination Airport', + type: 'string', + description: 'Destination airport.' + }, + destination_ids: { + label: 'Destination IDs', + description: + 'If a client has a destination catalog, the client can associate one or more destinations in the catalog with a specific flight event. For instance, link a particular route to a nearby museum and a nearby beach, both of which are destinations in the catalog. This field accepts a single string value or an array of string values.', + type: 'string', + multiple: true + }, + departing_arrival_date: { + label: 'Departing Arrival Date', + type: 'string', + description: + 'The date and time for arrival at the destination of the outbound journey. Accepted date formats: YYYYMMDD, YYYY-MM-DD, YYYY-MM-DDThh:mmTZD, and YYYY-MM-DDThh:mm:ssTZD' + }, + returning_arrival_date: { + label: 'Returning Arrival Date', + type: 'string', + description: + 'The date and time when the return journey is completed. Accepted date formats: YYYYMMDD, YYYY-MM-DD, YYYY-MM-DDThh:mmTZD, and YYYY-MM-DDThh:mm:ssTZD' + }, + travel_class: { + label: 'Flight Ticket Class', + type: 'string', + description: 'Class of the flight ticket, must be: "eco", "prem", "bus", "first".', + choices: [ + { value: 'eco', label: 'Economy' }, + { value: 'prem', label: 'Premium' }, + { value: 'bus', label: 'Bus' }, + { value: 'first', label: 'First' } + ] + }, + user_score: { + label: 'User Score', + type: 'number', + description: 'Represents the relative value of this potential customer to advertiser.' + }, + preferred_num_stops: { + label: 'Preferred Number of Stops', + type: 'integer', + description: 'The preferred number of stops the user is looking for. 0 for direct flight.' + }, + travel_start: { + label: 'Start Date of the Trip', + type: 'string', + description: + "The start date of user's trip. Accept date formats: YYYYMMDD, YYYY-MM-DD, YYYY-MM-DDThh:mmTZD, and YYYY-MM-DDThh:mm:ssTZD." + }, + travel_end: { + label: 'End Date of the Trip', + type: 'string', + description: + "The end date of user's trip. Accept date formats: YYYYMMDD, YYYY-MM-DD, YYYY-MM-DDThh:mmTZD, and YYYY-MM-DDThh:mm:ssTZD." + }, + suggested_destinations: { + label: 'Suggested Destination IDs', + description: + 'A list of IDs representing destination suggestions for this user. This parameter is not applicable for the Search event. This field accepts a single string value or an array of string values.', + type: 'string', + multiple: true + } + }, + default: { + city: { + '@path': '$.properties.city' + }, + region: { + '@path': '$.properties.region' + }, + country: { + '@path': '$.properties.country' + }, + checkin_date: { + '@path': '$.properties.checkin_date' + }, + checkout_date: { + '@path': '$.properties.checkout_date' + }, + num_adults: { + '@path': '$.properties.num_adults' + }, + num_children: { + '@path': '$.properties.num_children' + }, + num_infants: { + '@path': '$.properties.num_infants' + }, + suggested_hotels: { + '@path': '$.properties.suggested_hotels' // Confirmed this can be a single string or an array of strings + }, + departing_departure_date: { + '@path': '$.properties.departing_departure_date' + }, + returning_departure_date: { + '@path': '$.properties.returning_departure_date' + }, + origin_airport: { + '@path': '$.properties.origin_airport' + }, + destination_airport: { + '@path': '$.properties.destination_airport' + }, + destination_ids: { + '@path': '$.properties.destination_ids' // Confirmed this can be a single string or an array of strings + }, + departing_arrival_date: { + '@path': '$.properties.departing_arrival_date' + }, + returning_arrival_date: { + '@path': '$.properties.returning_arrival_date' + }, + travel_class: { + '@path': '$.properties.travel_class' + }, + user_score: { + '@path': '$.properties.user_score' + }, + preferred_num_stops: { + '@path': '$.properties.preferred_num_stops' + }, + travel_start: { + '@path': '$.properties.travel_start' + }, + travel_end: { + '@path': '$.properties.travel_end' + }, + suggested_destinations: { + '@path': '$.properties.suggested_destinations' // Confirmed this can be a single string or an array of strings + } + }, + depends_on: { + conditions: [ + { + fieldKey: 'event_spec_type', + operator: 'is', + value: TRAVEL_FIELDS + } + ] + } +} diff --git a/packages/browser-destinations/destinations/tiktok-pixel/src/reportWebEvent/fields/vehicle_fields.ts b/packages/browser-destinations/destinations/tiktok-pixel/src/reportWebEvent/fields/vehicle_fields.ts new file mode 100644 index 00000000000..7d916a84781 --- /dev/null +++ b/packages/browser-destinations/destinations/tiktok-pixel/src/reportWebEvent/fields/vehicle_fields.ts @@ -0,0 +1,255 @@ +import { InputField } from '@segment/actions-core' +import { VEHICLE_FIELDS } from '../constants' + +export const vehicle_fields: InputField = { + label: 'Vehicle Fields', + type: 'object', + description: 'Fields related to vehicle events.', + additionalProperties: false, + defaultObjectUI: 'keyvalue', + properties: { + postal_code: { + label: 'Postal Code', + type: 'string', + description: 'Postal code for the vehicle location.' + }, + make: { + label: 'Make of the Vehicle', + type: 'string', + description: 'Vehicle make/brand/manufacturer.' + }, + model: { + label: 'Model of the Vehicle', + type: 'string', + description: 'Vehicle model.' + }, + year: { + label: 'Year of the Vehicle', + type: 'number', + description: 'Year the vehicle was laucned in yyyy format.' + }, + state_of_vehicle: { + label: 'State of the Vehicle', + type: 'string', + description: 'Vehicle status.', + choices: [ + { value: 'New', label: 'New' }, + { value: 'Used', label: 'Used' }, + { value: 'CPO', label: 'CPO' } + ] + }, + mileage_value: { + label: 'Mileage Value', + type: 'number', + description: 'Vehicle mileage (in km or miles). Zero (0) for new vehicle.' + }, + mileage_unit: { + label: 'Mileage Unit', + type: 'string', + description: 'Mileage unites in miles (MI) or kilometers (KM).', + choices: [ + { value: 'MI', label: 'Miles' }, + { value: 'KM', label: 'Kilometers' } + ] + }, + exterior_color: { + label: 'Exterior Color of the Vehicle', + type: 'string', + description: 'Vehicle exterior color.' + }, + transmission: { + label: 'Transmission Type of the Vehicle', + type: 'string', + description: 'Vehicle transmission type.', + choices: [ + { value: 'Automatic', label: 'Automatic' }, + { value: 'Manual', label: 'Manual' }, + { value: 'Other', label: 'Other' } + ] + }, + body_style: { + label: 'Body Type of the Vehicle', + type: 'string', + description: 'Vehicle body type.', + choices: [ + { value: 'Convertible', label: 'Convertible' }, + { value: 'Coupe', label: 'Coupe' }, + { value: 'Hatchback', label: 'Hatchback' }, + { value: 'Minivan', label: 'Minivan' }, + { value: 'Truck', label: 'Truck' }, + { value: 'SUV', label: 'SUV' }, + { value: 'Sedan', label: 'Sedan' }, + { value: 'Van', label: 'Van' }, + { value: 'Wagon', label: 'Wagon' }, + { value: 'Crossover', label: 'Crossover' }, + { value: 'Other', label: 'Other' } + ] + }, + fuel_type: { + label: 'Fuel Type of the Vehicle', + type: 'string', + description: 'Vehicle fuel type.', + choices: [ + { value: 'Diesel', label: 'Diesel' }, + { value: 'Electric', label: 'Electric' }, + { value: 'Flex', label: 'Flex' }, + { value: 'Gasoline', label: 'Gasoline' }, + { value: 'Hybrid', label: 'Hybrid' }, + { value: 'Other', label: 'Other' } + ] + }, + drivetrain: { + label: 'Drivetrain of the Vehicle', + type: 'string', + description: 'Vehicle drivetrain.', + choices: [ + { value: 'AWD', label: 'AWD' }, + { value: 'FOUR_WD', label: 'Four WD' }, + { value: 'FWD', label: 'FWD' }, + { value: 'RWD', label: 'RWD' }, + { value: 'TWO_WD', label: 'Two WD' }, + { value: 'Other', label: 'Other' } + ] + }, + preferred_price_range_min: { + label: 'Minimum Preferred Price', + type: 'number', + description: 'Minimum preferred price of the vehicle.' + }, + preferred_price_range_max: { + label: 'Maximum Preferred Price', + type: 'number', + description: 'Maximum preferred price of the vehicle.' + }, + trim: { + label: 'Trim of the Vehicle', + type: 'string', + description: 'Vehicle trim.' + }, + vin: { + label: 'VIN of the Vehicle', + type: 'string', + description: 'Vehicle identification number. Maximum characters: 17.' + }, + interior_color: { + label: 'Interior Color of the Vehicle', + type: 'string', + description: 'Vehicle interior color.' + }, + condition_of_vehicle: { + label: 'Condition of the Vehicle', + type: 'string', + description: 'Vehicle drivetrain.', + choices: [ + { value: 'Excellent', label: 'Excellent' }, + { value: 'Good', label: 'Good' }, + { value: 'Fair', label: 'Fair' }, + { value: 'Poor', label: 'Poor' }, + { value: 'Other', label: 'Other' } + ] + }, + viewcontent_type: { + label: 'Soft Lead Landing Page', + type: 'string', + description: 'Optional for ViewContent. Use viewcontent_type to differentiate between soft lead landing pages.', + depends_on: { + match: 'any', + conditions: [{ fieldKey: 'event', operator: 'is', value: 'ViewContent' }] + } + }, + search_type: { + label: 'Other Search Page', + type: 'string', + description: + 'Optional for Search. Use search_type to differentiate other user searches (such as dealer lookup) from inventory search.', + depends_on: { + match: 'any', + conditions: [{ fieldKey: 'event', operator: 'is', value: 'Search' }] + } + }, + registration_type: { + label: 'Other Registration Page', + type: 'string', + description: + 'Optional for CompleteRegistration. Use registration_type to differentiate between different types of customer registration on websites.', + depends_on: { + match: 'any', + conditions: [{ fieldKey: 'event', operator: 'is', value: 'CompleteRegistration' }] + } + } + }, + default: { + postal_code: { + '@path': '$.properties.postal_code' + }, + make: { + '@path': '$.properties.make' + }, + model: { + '@path': '$.properties.model' + }, + year: { + '@path': '$.properties.year' + }, + state_of_vehicle: { + '@path': '$.properties.state_of_vehicle' + }, + mileage_value: { + '@path': '$.properties.mileage_value' + }, + mileage_unit: { + '@path': '$.properties.mileage_unit' + }, + exterior_color: { + '@path': '$.properties.exterior_color' + }, + transmission: { + '@path': '$.properties.transmission' + }, + body_style: { + '@path': '$.properties.body_style' + }, + fuel_type: { + '@path': '$.properties.fuel_type' + }, + drivetrain: { + '@path': '$.properties.drive_train' + }, + preferred_price_range_min: { + '@path': '$.properties.preferred_price_range_min' + }, + preferred_price_range_max: { + '@path': '$.properties.preferred_price_range_max' + }, + trim: { + '@path': '$.properties.trim' + }, + vin: { + '@path': '$.properties.vin' + }, + interior_color: { + '@path': '$.properties.interior_color' + }, + condition_of_vehicle: { + '@path': '$.properties.condition_of_vehicle' + }, + viewcontent_type: { + '@path': '$.properties.viewcontent_type' + }, + search_type: { + '@path': '$.properties.search_type' + }, + registration_type: { + '@path': '$.properties.registration_type' + } + }, + depends_on: { + conditions: [ + { + fieldKey: 'event_spec_type', + operator: 'is', + value: VEHICLE_FIELDS + } + ] + } +} diff --git a/packages/browser-destinations/destinations/tiktok-pixel/src/reportWebEvent/generated-types.ts b/packages/browser-destinations/destinations/tiktok-pixel/src/reportWebEvent/generated-types.ts index ac49bf05424..323cd7cdd92 100644 --- a/packages/browser-destinations/destinations/tiktok-pixel/src/reportWebEvent/generated-types.ts +++ b/packages/browser-destinations/destinations/tiktok-pixel/src/reportWebEvent/generated-types.ts @@ -1,6 +1,10 @@ // Generated file. DO NOT MODIFY IT BY HAND. export interface Payload { + /** + * Include fields for travel or vehicle events. + */ + event_spec_type?: string /** * Conversion event name. Please refer to the "Supported Web Events" section on in TikTok’s [Pixel SDK documentation](https://business-api.tiktok.com/portal/docs?id=1739585696931842) for accepted event names. */ @@ -87,6 +91,14 @@ export interface Payload { */ brand?: string }[] + /** + * Product IDs associated with the event, such as SKUs. Do not populate this field if the 'Contents' field is populated. This field accepts a single string value or an array of string values. + */ + content_ids?: string[] + /** + * Number of items when checkout was initiated. Used with the InitiateCheckout event. + */ + num_items?: number /** * Type of the product item. When the `content_id` in the `Contents` field is specified as a `sku_id`, set this field to `product`. When the `content_id` in the `Contents` field is specified as an `item_group_id`, set this field to `product_group`. */ @@ -107,4 +119,190 @@ export interface Payload { * The text string that was searched for. */ query?: string + /** + * The text string entered by the user for the search. Optionally used with the Search event. + */ + search_string?: string + /** + * Fields related to vehicle events. + */ + vehicle_fields?: { + /** + * Postal code for the vehicle location. + */ + postal_code?: string + /** + * Vehicle make/brand/manufacturer. + */ + make?: string + /** + * Vehicle model. + */ + model?: string + /** + * Year the vehicle was laucned in yyyy format. + */ + year?: number + /** + * Vehicle status. + */ + state_of_vehicle?: string + /** + * Vehicle mileage (in km or miles). Zero (0) for new vehicle. + */ + mileage_value?: number + /** + * Mileage unites in miles (MI) or kilometers (KM). + */ + mileage_unit?: string + /** + * Vehicle exterior color. + */ + exterior_color?: string + /** + * Vehicle transmission type. + */ + transmission?: string + /** + * Vehicle body type. + */ + body_style?: string + /** + * Vehicle fuel type. + */ + fuel_type?: string + /** + * Vehicle drivetrain. + */ + drivetrain?: string + /** + * Minimum preferred price of the vehicle. + */ + preferred_price_range_min?: number + /** + * Maximum preferred price of the vehicle. + */ + preferred_price_range_max?: number + /** + * Vehicle trim. + */ + trim?: string + /** + * Vehicle identification number. Maximum characters: 17. + */ + vin?: string + /** + * Vehicle interior color. + */ + interior_color?: string + /** + * Vehicle drivetrain. + */ + condition_of_vehicle?: string + /** + * Optional for ViewContent. Use viewcontent_type to differentiate between soft lead landing pages. + */ + viewcontent_type?: string + /** + * Optional for Search. Use search_type to differentiate other user searches (such as dealer lookup) from inventory search. + */ + search_type?: string + /** + * Optional for CompleteRegistration. Use registration_type to differentiate between different types of customer registration on websites. + */ + registration_type?: string + } + /** + * Fields related to travel events. + */ + travel_fields?: { + /** + * Hotel city location. + */ + city?: string + /** + * Hotel region location. + */ + region?: string + /** + * Hotel country location. + */ + country?: string + /** + * Hotel check-in date. + */ + checkin_date?: string + /** + * Hotel check-out date. + */ + checkout_date?: string + /** + * Number of adults. + */ + num_adults?: number + /** + * Number of children. + */ + num_children?: number + /** + * Number of infants flying. + */ + num_infants?: number + /** + * Suggested hotels. This can be a single string value or an array of string values. + */ + suggested_hotels?: string[] + /** + * Date of flight departure. Accepted date formats: YYYYMMDD, YYYY-MM-DD, YYYY-MM-DDThh:mmTZD, and YYYY-MM-DDThh:mm:ssTZD + */ + departing_departure_date?: string + /** + * Date of return flight. Accepted date formats: YYYYMMDD, YYYY-MM-DD, YYYY-MM-DDThh:mmTZD, and YYYY-MM-DDThh:mm:ssTZD + */ + returning_departure_date?: string + /** + * Origin airport. + */ + origin_airport?: string + /** + * Destination airport. + */ + destination_airport?: string + /** + * If a client has a destination catalog, the client can associate one or more destinations in the catalog with a specific flight event. For instance, link a particular route to a nearby museum and a nearby beach, both of which are destinations in the catalog. This field accepts a single string value or an array of string values. + */ + destination_ids?: string[] + /** + * The date and time for arrival at the destination of the outbound journey. Accepted date formats: YYYYMMDD, YYYY-MM-DD, YYYY-MM-DDThh:mmTZD, and YYYY-MM-DDThh:mm:ssTZD + */ + departing_arrival_date?: string + /** + * The date and time when the return journey is completed. Accepted date formats: YYYYMMDD, YYYY-MM-DD, YYYY-MM-DDThh:mmTZD, and YYYY-MM-DDThh:mm:ssTZD + */ + returning_arrival_date?: string + /** + * Class of the flight ticket, must be: "eco", "prem", "bus", "first". + */ + travel_class?: string + /** + * Represents the relative value of this potential customer to advertiser. + */ + user_score?: number + /** + * The preferred number of stops the user is looking for. 0 for direct flight. + */ + preferred_num_stops?: number + /** + * The start date of user's trip. Accept date formats: YYYYMMDD, YYYY-MM-DD, YYYY-MM-DDThh:mmTZD, and YYYY-MM-DDThh:mm:ssTZD. + */ + travel_start?: string + /** + * The end date of user's trip. Accept date formats: YYYYMMDD, YYYY-MM-DD, YYYY-MM-DDThh:mmTZD, and YYYY-MM-DDThh:mm:ssTZD. + */ + travel_end?: string + /** + * A list of IDs representing destination suggestions for this user. This parameter is not applicable for the Search event. This field accepts a single string value or an array of string values. + */ + suggested_destinations?: string[] + } } diff --git a/packages/browser-destinations/destinations/tiktok-pixel/src/reportWebEvent/index.ts b/packages/browser-destinations/destinations/tiktok-pixel/src/reportWebEvent/index.ts index c5667254ceb..f464877ccc4 100644 --- a/packages/browser-destinations/destinations/tiktok-pixel/src/reportWebEvent/index.ts +++ b/packages/browser-destinations/destinations/tiktok-pixel/src/reportWebEvent/index.ts @@ -1,9 +1,12 @@ import type { BrowserActionDefinition } from '@segment/browser-destination-runtime/types' import type { Settings } from '../generated-types' import type { Payload } from './generated-types' -import { formatPhone, handleArrayInput, formatString, formatAddress } from '../formatter' +import { getUser } from '../utils' +import { getAllProperties } from './utils' import { TikTokPixel } from '../types' -import { commonFields } from '../common_fields' +import { commonFields } from './fields/common_fields' +import { travel_fields } from './fields/travel_fields' +import { vehicle_fields } from './fields/vehicle_fields' const action: BrowserActionDefinition = { title: 'Report Web Event', @@ -12,36 +15,19 @@ const action: BrowserActionDefinition = { platform: 'web', defaultSubscription: 'type = "track"', fields: { - ...commonFields + ...commonFields, + vehicle_fields, + travel_fields }, perform: (ttq, { payload, settings }) => { if (payload.email || payload.phone_number || payload.external_id) { - ttq.identify({ - email: handleArrayInput(payload.email), - phone_number: formatPhone(handleArrayInput(payload.phone_number)), - external_id: handleArrayInput(payload.external_id), - first_name: formatString(payload.first_name), - last_name: formatString(payload.last_name), - city: formatAddress(payload.address?.city), - state: formatAddress(payload.address?.state), - country: formatAddress(payload.address?.country), - zip_code: formatString(payload.address?.zip_code) - }) + ttq.instance(settings.pixelCode).identify(getUser(payload)) } ttq.instance(settings.pixelCode).track( - payload.event, - { - contents: payload.contents ? payload.contents : [], - content_type: payload.content_type ? payload.content_type : undefined, - currency: payload.currency ? payload.currency : 'USD', - value: payload.value || payload.value === 0 ? payload.value : undefined, - query: payload.query ? payload.query : undefined, - description: payload.description ? payload.description : undefined, - order_id: payload.order_id ? payload.order_id : undefined, - shop_id: payload.shop_id ? payload.shop_id : undefined - }, - { + payload.event, + getAllProperties(payload), + { event_id: payload.event_id ? payload.event_id : '' } ) diff --git a/packages/browser-destinations/destinations/tiktok-pixel/src/reportWebEvent/utils.ts b/packages/browser-destinations/destinations/tiktok-pixel/src/reportWebEvent/utils.ts new file mode 100644 index 00000000000..df4a41530c1 --- /dev/null +++ b/packages/browser-destinations/destinations/tiktok-pixel/src/reportWebEvent/utils.ts @@ -0,0 +1,167 @@ +import { Payload } from './generated-types' +import { TTBaseProps, TTTravelProps, TTAutoProps } from '../types' +import { TRAVEL_FIELDS, VEHICLE_FIELDS } from './constants' + +export function getAllProperties(payload: Payload): TTBaseProps & TTAutoProps & TTTravelProps { + const { event_spec_type } = payload + + return { + ...getProps(payload), + ...(event_spec_type === TRAVEL_FIELDS ? getTravelProps(payload) : {}), + ...(event_spec_type === VEHICLE_FIELDS ? getAutoProp(payload) : {}) + } +} + +function getProps(payload: Payload): TTBaseProps { + const { + content_type, + currency, + value, + query, + description, + order_id, + shop_id, + content_ids, + num_items, + search_string, + contents + } = payload + + const requestProperties: TTBaseProps = { + contents: contents + ? contents.map(({ price, quantity, content_category, content_id, content_name, brand }) => ({ + price: price ?? undefined, + quantity: quantity ?? undefined, + content_category: content_category ?? undefined, + content_id: content_id ?? undefined, + content_name: content_name ?? undefined, + brand: brand ?? undefined + })) + : [], + ...(content_type !== undefined && { content_type }), + ...(currency !== undefined && { currency }), + ...(value !== undefined && { value }), + ...(query !== undefined && { query }), + ...(description !== undefined && { description }), + ...(order_id !== undefined && { order_id }), + ...(shop_id !== undefined && { shop_id }), + ...(content_ids !== undefined && { content_ids }), + ...(num_items !== undefined && { num_items }), + ...(search_string !== undefined && { search_string }) + } + + return requestProperties +} + +function getTravelProps(payload: Payload): TTTravelProps { + const { + city, + region, + country, + checkin_date, + checkout_date, + num_adults, + num_children, + num_infants, + suggested_hotels, + departing_departure_date, + returning_departure_date, + origin_airport, + destination_airport, + destination_ids, + departing_arrival_date, + returning_arrival_date, + travel_class, + user_score, + preferred_num_stops, + travel_start, + travel_end, + suggested_destinations + } = payload?.travel_fields ?? {} + + const requestProperties: TTTravelProps = { + ...(city !== undefined && { city }), + ...(region !== undefined && { region }), + ...(country !== undefined && { country }), + ...(checkin_date !== undefined && { checkin_date }), + ...(checkout_date !== undefined && { checkout_date }), + ...(num_adults !== undefined && { num_adults }), + ...(num_children !== undefined && { num_children }), + ...(num_infants !== undefined && { num_infants }), + ...(suggested_hotels !== undefined && { suggested_hotels }), + ...(departing_departure_date !== undefined && { departing_departure_date }), + ...(returning_departure_date !== undefined && { returning_departure_date }), + ...(origin_airport !== undefined && { origin_airport }), + ...(destination_airport !== undefined && { destination_airport }), + ...(destination_ids !== undefined && { destination_ids }), + ...(departing_arrival_date !== undefined && { departing_arrival_date }), + ...(returning_arrival_date !== undefined && { returning_arrival_date }), + ...(travel_class !== undefined && { travel_class }), + ...(user_score !== undefined && { user_score }), + ...(preferred_num_stops !== undefined && { preferred_num_stops }), + ...(travel_start !== undefined && { travel_start }), + ...(travel_end !== undefined && { travel_end }), + ...(suggested_destinations !== undefined && { suggested_destinations }) + } + + return requestProperties +} + +function getAutoProp(payload: Payload): TTAutoProps { + const { + postal_code, + make, + model, + year, + state_of_vehicle, + mileage_unit, + mileage_value, + exterior_color, + transmission, + body_style, + fuel_type, + drivetrain, + preferred_price_range_min, + preferred_price_range_max, + trim, + vin, + interior_color, + condition_of_vehicle, + viewcontent_type, + search_type, + registration_type + } = payload?.vehicle_fields ?? {} + + const requestProperties: TTAutoProps = { + ...(postal_code !== undefined && { postal_code }), + ...(make !== undefined && { make }), + ...(model !== undefined && { model }), + ...(year !== undefined && { year }), + ...(state_of_vehicle !== undefined && { state_of_vehicle }), + ...(exterior_color !== undefined && { exterior_color }), + ...(transmission !== undefined && { transmission }), + ...(body_style !== undefined && { body_style }), + ...(fuel_type !== undefined && { fuel_type }), + ...(drivetrain !== undefined && { drivetrain }), + ...(trim !== undefined && { trim }), + ...(vin !== undefined && { vin }), + ...(interior_color !== undefined && { interior_color }), + ...(condition_of_vehicle !== undefined && { condition_of_vehicle }), + ...(viewcontent_type !== undefined && { viewcontent_type }), + ...(search_type !== undefined && { search_type }), + ...(registration_type !== undefined && { registration_type }), + ...(mileage_unit !== undefined && + typeof mileage_value === 'number' && { + mileage: { + unit: mileage_unit, + value: mileage_value + } + }), + ...(typeof preferred_price_range_min === 'number' && + typeof preferred_price_range_max === 'number' && { + preferred_price_range: [preferred_price_range_min, preferred_price_range_max] + }) + } + + return requestProperties +} diff --git a/packages/browser-destinations/destinations/tiktok-pixel/src/types.ts b/packages/browser-destinations/destinations/tiktok-pixel/src/types.ts index 93042f663dd..6dc176ef900 100644 --- a/packages/browser-destinations/destinations/tiktok-pixel/src/types.ts +++ b/packages/browser-destinations/destinations/tiktok-pixel/src/types.ts @@ -1,61 +1,96 @@ export interface TikTokPixel { page: () => void instance: (pixel_code: string) => TikTokPixel - identify: ({ - email, - phone_number, - external_id, - first_name, - last_name, - city, - state, - country, - zip_code - }: { - email: string | undefined - phone_number: string | undefined - external_id: string | undefined - first_name: string | undefined - last_name: string | undefined - city: string | undefined - state: string | undefined - country: string | undefined - zip_code: string | undefined - }) => void + identify: (user: TTUser) => void track: ( event: string, - { - contents, - content_type, - currency, - value, - description, - query, - order_id, - shop_id - }: { - contents: - | { - price?: number | undefined - quantity?: number | undefined - content_category?: string | undefined - content_id?: string | undefined - content_name?: string | undefined - brand?: string | undefined - }[] - | [] - content_type: string | undefined - currency: string | undefined - value: number | undefined - description: string | undefined - query: string | undefined - order_id: string | undefined - shop_id: string | undefined - }, - { - event_id - }: { - event_id: string | undefined - } + { ...props }: TTBaseProps & TTTravelProps & TTAutoProps, + { event_id }: { event_id?: string } ) => void } + +export interface TTUser { + external_id: string + phone_number: string | undefined + email: string + locale?: string + first_name?: string + last_name?: string + city?: string + state?: string + country?: string + zip_code?: string +} + +export interface TTBaseProps { + contents: TTContentItem[] + content_type?: string + currency?: string + value?: number + query?: string + description?: string + order_id?: string + shop_id?: string + content_ids?: string[] + num_items?: number + search_string?: string +} + +export interface TTTravelProps { + city?: string + region?: string + country?: string + checkin_date?: string + checkout_date?: string + num_adults?: number + num_children?: number + num_infants?: number + suggested_hotels?: string[] + departing_departure_date?: string + returning_departure_date?: string + origin_airport?: string + destination_airiport?: string + destination_ids?: string[] + departing_arrival_date?: string + returning_arrival_date?: string + travel_class?: string + user_score?: number + preferred_num_stops?: number + travel_start?: string + travel_end?: string + suggested_destinations?: string[] +} + +export interface TTAutoProps { + postal_code?: string + make?: string + model?: string + year?: number + state_of_vehicle?: string + mileage?: { + value?: number + unit?: string + } + exterior_color?: string + transmission?: string + body_style?: string + fuel_type?: string + drivetrain?: string + preferred_price_range?: number[] + trim?: string + vin?: string + interior_color?: string + condition_of_vehicle?: string + viewcontent_type?: string + search_type?: string + registration_type?: string +} + +interface TTContentItem { + price?: number + quantity?: number + content_category?: string + content_id?: string + content_name?: string + brand?: string +} diff --git a/packages/browser-destinations/destinations/tiktok-pixel/src/utils.ts b/packages/browser-destinations/destinations/tiktok-pixel/src/utils.ts new file mode 100644 index 00000000000..d2511946fce --- /dev/null +++ b/packages/browser-destinations/destinations/tiktok-pixel/src/utils.ts @@ -0,0 +1,17 @@ +import { Payload } from './reportWebEvent/generated-types' +import { formatPhone, handleArrayInput, formatString, formatAddress } from './formatter' +import { TTUser } from './types' + +export function getUser(payload: Payload): TTUser { + return { + email: handleArrayInput(payload.email), + phone_number: formatPhone(handleArrayInput(payload.phone_number)), + external_id: handleArrayInput(payload.external_id), + first_name: formatString(payload.first_name), + last_name: formatString(payload.last_name), + city: formatAddress(payload.address?.city), + state: formatAddress(payload.address?.state), + country: formatAddress(payload.address?.country), + zip_code: formatString(payload.address?.zip_code) + } +} \ No newline at end of file diff --git a/packages/destination-actions/src/destinations/tiktok-conversions/reportWebEvent/fields/travel_fields.ts b/packages/destination-actions/src/destinations/tiktok-conversions/reportWebEvent/fields/travel_fields.ts index a225c5428c9..d095571a64c 100644 --- a/packages/destination-actions/src/destinations/tiktok-conversions/reportWebEvent/fields/travel_fields.ts +++ b/packages/destination-actions/src/destinations/tiktok-conversions/reportWebEvent/fields/travel_fields.ts @@ -173,8 +173,8 @@ export const travel_fields: InputField = { origin_airport: { '@path': '$.properties.origin_airport' }, - destination_airiport: { - '@path': '$.properties.destination_airiport' + destination_airport: { + '@path': '$.properties.destination_airport' }, destination_ids: { '@path': '$.properties.destination_ids' // Confirmed this can be a single string or an array of strings