diff --git a/docs/analytics.eventpayload.browseragent.md b/docs/analytics.eventpayload.browseragent.md index 3d4d9b2c..bd96e455 100644 --- a/docs/analytics.eventpayload.browseragent.md +++ b/docs/analytics.eventpayload.browseragent.md @@ -12,10 +12,10 @@ Information about the visitors device and browser. browserAgent?: { browser?: string; browserVersion?: string; - os?: string; - osVersion?: string; device?: string; deviceClass?: string; + os?: string; + osVersion?: string; userAgent?: string; }; ``` diff --git a/docs/analytics.eventpayload.ip.md b/docs/analytics.eventpayload.ip.md index 80a9050d..1b781675 100644 --- a/docs/analytics.eventpayload.ip.md +++ b/docs/analytics.eventpayload.ip.md @@ -11,6 +11,6 @@ The IP address for the event. ```typescript ip?: { address: string; - algorithm?: string; + algorithm: string; }; ``` diff --git a/docs/analytics.eventpayload.location.md b/docs/analytics.eventpayload.location.md new file mode 100644 index 00000000..4f4bf032 --- /dev/null +++ b/docs/analytics.eventpayload.location.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@yext/analytics](./analytics.md) > [EventPayload](./analytics.eventpayload.md) > [location](./analytics.eventpayload.location.md) + +## EventPayload.location property + +The location information of the visitor for the event. Either a Coordinates object with both latitude and longitude or a string with the country of the visitor for the event, as a ISO 3166-1 alpha-2 country code. + +**Signature:** + +```typescript +location?: Coordinates | string; +``` diff --git a/docs/analytics.eventpayload.md b/docs/analytics.eventpayload.md index 2af05540..25f57eeb 100644 --- a/docs/analytics.eventpayload.md +++ b/docs/analytics.eventpayload.md @@ -19,7 +19,7 @@ export interface EventPayload | [action](./analytics.eventpayload.action.md) | | [Action](./analytics.action.md) | The user action which caused the event, e.g. ADD\_TO\_CART, THUMBS\_UP, C\_CUSTOM\_ACTION | | [authorization?](./analytics.eventpayload.authorization.md) | | string | _(Optional)_ The authorization token for the request. This will be setup from the Key or Bearer in the config. | | [bot?](./analytics.eventpayload.bot.md) | | boolean | _(Optional)_ Whether the event is the result of bot activity. | -| [browserAgent?](./analytics.eventpayload.browseragent.md) | | { browser?: string; browserVersion?: string; os?: string; osVersion?: string; device?: string; deviceClass?: string; userAgent?: string; } | _(Optional)_ Information about the visitors device and browser. | +| [browserAgent?](./analytics.eventpayload.browseragent.md) | | { browser?: string; browserVersion?: string; device?: string; deviceClass?: string; os?: string; osVersion?: string; userAgent?: string; } | _(Optional)_ Information about the visitors device and browser. | | [chat?](./analytics.eventpayload.chat.md) | | { botId: string; conversationId?: string; responseId?: string; } | _(Optional)_ Fields specific to reporting Chat Analytics Events | | [clientSdk?](./analytics.eventpayload.clientsdk.md) | | Record<string, string> | _(Optional)_ For the Yext client SDKs involved in the event, this is an object mapping the names of those SDKs to the version labels of those SDKs. | | [count?](./analytics.eventpayload.count.md) | | number | _(Optional)_ When the record summarizes multiple events, the number of events the record represents. The event is treated as if it is duplicated this many times. | @@ -28,14 +28,17 @@ export interface EventPayload | [destinationUrl?](./analytics.eventpayload.destinationurl.md) | | string | _(Optional)_ The URL of the page the event is directing the visitor to. | | [entity?](./analytics.eventpayload.entity.md) | | string \| number | _(Optional)_ The Yext entity to which the event corresponds. If passed as a string, the value is the mutable, customer-settable entity ID for the entity associated with the event. If passed as a number, it is the immutable entity ID (UID) set by the system. This is an internal ID. | | [internalUser?](./analytics.eventpayload.internaluser.md) | | boolean | _(Optional)_ Indicates whether the event is the result of internal activity. | -| [ip?](./analytics.eventpayload.ip.md) | | { address: string; algorithm?: string; } | _(Optional)_ The IP address for the event. | +| [ip?](./analytics.eventpayload.ip.md) | | { address: string; algorithm: string; } | _(Optional)_ The IP address for the event. | | [label?](./analytics.eventpayload.label.md) | | string | _(Optional)_ A label assigned to the event, e.g. a CTA label. | | [locale?](./analytics.eventpayload.locale.md) | | string | _(Optional)_ The locale of the user who generated the event. | +| [location?](./analytics.eventpayload.location.md) | | Coordinates \| string | _(Optional)_ The location information of the visitor for the event. Either a Coordinates object with both latitude and longitude or a string with the country of the visitor for the event, as a ISO 3166-1 alpha-2 country code. | | [pageUrl?](./analytics.eventpayload.pageurl.md) | | string | _(Optional)_ The URL of the page where the event occurred | | [referrerUrl?](./analytics.eventpayload.referrerurl.md) | | string | _(Optional)_ The URL of the page which the visitor came from prior to the event. | | [search?](./analytics.eventpayload.search.md) | | { searchId?: string; queryId?: string; verticalKey?: string; isDirectAnswer?: boolean; versionLabel?: [VersionLabel](./analytics.versionlabel.md); versionNumber?: number; experienceKey: string; } | _(Optional)_ Fields specific to reporting Yext Search Analytics Events | +| [searchTerm?](./analytics.eventpayload.searchterm.md) | | string | _(Optional)_ | | [sessionId?](./analytics.eventpayload.sessionid.md) | | string \| null | _(Optional)_ Unique identifier to tie together events in a single browsing session | | [sites?](./analytics.eventpayload.sites.md) | | { siteUid?: number; template?: string; } | _(Optional)_ Fields specific to reporting Yext Pages Analytics Events | | [timestamp?](./analytics.eventpayload.timestamp.md) | | Date \| string | _(Optional)_ The timestamp at which the event occurred, in ISO format. | +| [value?](./analytics.eventpayload.value.md) | | { amount: number; currency: string; } | _(Optional)_ The monetary value of the event. | | [visitor?](./analytics.eventpayload.visitor.md) | | Record<string, string> | _(Optional)_ Information used to associate analytics with a particular user. | diff --git a/docs/analytics.eventpayload.searchterm.md b/docs/analytics.eventpayload.searchterm.md new file mode 100644 index 00000000..ca6a7444 --- /dev/null +++ b/docs/analytics.eventpayload.searchterm.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [@yext/analytics](./analytics.md) > [EventPayload](./analytics.eventpayload.md) > [searchTerm](./analytics.eventpayload.searchterm.md) + +## EventPayload.searchTerm property + +**Signature:** + +```typescript +searchTerm?: string; +``` diff --git a/docs/analytics.eventpayload.value.md b/docs/analytics.eventpayload.value.md new file mode 100644 index 00000000..6882f57c --- /dev/null +++ b/docs/analytics.eventpayload.value.md @@ -0,0 +1,16 @@ + + +[Home](./index.md) > [@yext/analytics](./analytics.md) > [EventPayload](./analytics.eventpayload.md) > [value](./analytics.eventpayload.value.md) + +## EventPayload.value property + +The monetary value of the event. + +**Signature:** + +```typescript +value?: { + amount: number; + currency: string; + }; +``` diff --git a/etc/analytics.api.md b/etc/analytics.api.md index fc3008de..be9b5cfc 100644 --- a/etc/analytics.api.md +++ b/etc/analytics.api.md @@ -47,10 +47,10 @@ export interface EventPayload { browserAgent?: { browser?: string; browserVersion?: string; - os?: string; - osVersion?: string; device?: string; deviceClass?: string; + os?: string; + osVersion?: string; userAgent?: string; }; chat?: { @@ -67,10 +67,12 @@ export interface EventPayload { internalUser?: boolean; ip?: { address: string; - algorithm?: string; + algorithm: string; }; label?: string; locale?: string; + // Warning: (ae-forgotten-export) The symbol "Coordinates" needs to be exported by the entry point index.d.ts + location?: Coordinates | string; pageUrl?: string; referrerUrl?: string; search?: { @@ -82,12 +84,18 @@ export interface EventPayload { versionNumber?: number; experienceKey: string; }; + // (undocumented) + searchTerm?: string; sessionId?: string | null; sites?: { siteUid?: number; template?: string; }; timestamp?: Date | string; + value?: { + amount: number; + currency: string; + }; visitor?: Record; } diff --git a/src/Coordinates.ts b/src/Coordinates.ts new file mode 100644 index 00000000..c00f5e76 --- /dev/null +++ b/src/Coordinates.ts @@ -0,0 +1,6 @@ +export type Coordinates = { + coordinates: { + latitude: number; + longitude: number; + }; +}; diff --git a/src/EventPayload.ts b/src/EventPayload.ts index c0618ee3..d86fe8fb 100644 --- a/src/EventPayload.ts +++ b/src/EventPayload.ts @@ -1,4 +1,5 @@ import { Action } from './Action'; +import { Coordinates } from './Coordinates'; import { VersionLabel } from './VersionLabel'; /** @@ -11,20 +12,6 @@ export interface EventPayload { action: Action; /** The authorization token for the request. This will be setup from the Key or Bearer in the config. */ authorization?: string; - /** Unique identifier to tie together events in a single browsing session */ - sessionId?: string | null; - /** The URL of the page where the event occurred */ - pageUrl?: string; - /** The URL of the page the event is directing the visitor to. */ - destinationUrl?: string; - /** The URL of the page which the visitor came from prior to the event. */ - referrerUrl?: string; - /** A label assigned to the event, e.g. a CTA label. */ - label?: string; - /** The locale of the user who generated the event. */ - locale?: string; - /** The timestamp at which the event occurred, in ISO format. */ - timestamp?: Date | string; /** Whether the event is the result of bot activity. */ bot?: boolean; /** Information about the visitors device and browser. */ @@ -33,24 +20,17 @@ export interface EventPayload { browser?: string; /** The browser version associated with the event. */ browserVersion?: string; - /** The operating system associated with the event. */ - os?: string; - /** The operating system version associated with the event. */ - osVersion?: string; /** The device associated with the event. */ device?: string; /** The device class associated with the event. */ deviceClass?: string; + /** The operating system associated with the event. */ + os?: string; + /** The operating system version associated with the event. */ + osVersion?: string; /** The user agent associated with the event. */ userAgent?: string; }; - /** - * For the Yext client SDKs involved in the event, this is an object mapping - * the names of those SDKs to the version labels of those SDKs. - */ - clientSdk?: Record; - /** Indicates whether the event is the result of internal activity. */ - internalUser?: boolean; /** Fields specific to reporting Chat Analytics Events */ chat?: { /** The ID of the bot that generated the event. */ @@ -60,31 +40,11 @@ export interface EventPayload { /** The ID of the individual response in which the event occurred. */ responseId?: string; }; - /** Fields specific to reporting Yext Search Analytics Events */ - search?: { - /** Unique identifier of the search */ - searchId?: string; - /** Unique identifier for a single query across pagination */ - queryId?: string; - /** The vertical key on which the event occurred, if any */ - verticalKey?: string; - /** Whether or not the event occurred on a direct answer card */ - isDirectAnswer?: boolean; - /** The label of the version number of the search config. - * Either "PRODUCTION" or "STAGING" */ - versionLabel?: VersionLabel; - /** The version number of the search config */ - versionNumber?: number; - /** The identifier of the search experience. */ - experienceKey: string; - }; - /** Fields specific to reporting Yext Pages Analytics Events */ - sites?: { - /* The UID of the site an event was tied to. */ - siteUid?: number; - /* The ID of the template from which a site was generated. */ - template?: string; - }; + /** + * For the Yext client SDKs involved in the event, this is an object mapping + * the names of those SDKs to the version labels of those SDKs. + */ + clientSdk?: Record; /** * When the record summarizes multiple events, the number of events the record represents. * The event is treated as if it is duplicated this many times. @@ -100,17 +60,70 @@ export interface EventPayload { * Keys are case-insensitive. */ customValues?: Record; + /** The URL of the page the event is directing the visitor to. */ + destinationUrl?: string; /** The Yext entity to which the event corresponds. If passed as a string, the value is * the mutable, customer-settable entity ID for the entity associated with the event. * If passed as a number, it is the immutable entity ID (UID) set by the system. This is an internal ID. */ entity?: string | number; + /** Indicates whether the event is the result of internal activity. */ + internalUser?: boolean; /** The IP address for the event.*/ ip?: { /** The IPv4 address associated with the event. */ address: string; /** The algorithm to use to anonymize the IP address after collection. */ - algorithm?: string; + algorithm: string; + }; + /** A label assigned to the event, e.g. a CTA label. */ + label?: string; + /** The locale of the user who generated the event. */ + locale?: string; + /** The location information of the visitor for the event. + * Either a Coordinates object with both latitude and longitude or a string + * with the country of the visitor for the event, as a ISO 3166-1 alpha-2 country code. */ + location?: Coordinates | string; + /** The URL of the page where the event occurred */ + pageUrl?: string; + /** The URL of the page which the visitor came from prior to the event. */ + referrerUrl?: string; + /** Fields specific to reporting Yext Search Analytics Events */ + search?: { + /** Unique identifier of the search */ + searchId?: string; + /** Unique identifier for a single query across pagination */ + queryId?: string; + /** The vertical key on which the event occurred, if any */ + verticalKey?: string; + /** Whether or not the event occurred on a direct answer card */ + isDirectAnswer?: boolean; + /** The label of the version number of the search config. Either "PRODUCTION" or "STAGING" */ + versionLabel?: VersionLabel; + /** The version number of the search config */ + versionNumber?: number; + /** The identifier of the search experience. */ + experienceKey: string; + }; + /* The query entered by the user. */ + searchTerm?: string; + /** Unique identifier to tie together events in a single browsing session */ + sessionId?: string | null; + /** Fields specific to reporting Yext Pages Analytics Events */ + sites?: { + /* The UID of the site an event was tied to. */ + siteUid?: number; + /* The ID of the template from which a site was generated. */ + template?: string; + }; + /** The timestamp at which the event occurred, in ISO format. */ + timestamp?: Date | string; + /** The monetary value of the event. */ + value?: { + /** The monetary value. */ + amount: number; + /** The ISO 4217 currency code of the currency the value is expressed in. */ + currency: string; }; /** * Information used to associate analytics with a particular user. diff --git a/test-gtm/index.html b/test-gtm/index.html new file mode 100644 index 00000000..7a2ac4df --- /dev/null +++ b/test-gtm/index.html @@ -0,0 +1,36 @@ + + + + + + + + + Analytics Test + + + + + +

Analytics Test

+ + + diff --git a/tests/AnalyticsEventReporter.test.ts b/tests/AnalyticsEventReporter.test.ts index a5283040..731749a3 100644 --- a/tests/AnalyticsEventReporter.test.ts +++ b/tests/AnalyticsEventReporter.test.ts @@ -553,4 +553,171 @@ describe('Test report function', () => { } ); }); + + it('should call post with correct fields - full payload', async () => { + mockPostWithBeacon.mockReturnValueOnce(true); + mockUseBeacon.mockReturnValueOnce(true); + const navigator = { + userAgent: 'Firefox', + sendBeacon: () => { + return true; + } + }; + Object.defineProperty(window, 'navigator', { + value: navigator, + writable: true + }); + + const config: AnalyticsConfig = { + key: 'validKey', + region: RegionEnum.EU, + forceFetch: false, + sessionTrackingEnabled: true + }; + const reporter = new AnalyticsEventReporter(config).with({ + action: 'ADD_TO_CART', + bot: false, + browserAgent: { + browser: 'chrome', + browserVersion: '1.0.0', + device: 'desktop', + deviceClass: 'desktop', + os: 'windows', + osVersion: '10', + userAgent: 'chrome' + }, + chat: { + botId: 'botId', + conversationId: 'conversationId', + responseId: 'responseId' + }, + clientSdk: { + chat: '1.0.0' + }, + count: 5, + customTags: { + customTag: 'customTagValue' + }, + customValues: { + customValue: 1 + }, + destinationUrl: 'https://google.com', + entity: 'entityId', + internalUser: false, + ip: { + address: '1.0.0.0', + algorithm: 'HASH' + }, + label: 'label', + locale: 'en_US', + location: { + coordinates: { + latitude: 1, + longitude: 1 + } + }, + pageUrl: 'https://yext.com', + referrerUrl: 'https://yext.com', + search: { + versionNumber: 5, + isDirectAnswer: false, + experienceKey: 'experienceKey', + queryId: 'queryId' + }, + searchTerm: 'searchTerm', + sessionId: 'sessionId', + sites: { + siteUid: 321, + template: 'template' + }, + timestamp: '1912-08-01T05:00:00.000Z', + value: { + amount: 1, + currency: 'USD' + }, + visitor: { + 'visitor-id': 'visitor-id' + } + }); + + const res = await reporter.report({ + action: 'C_CUSTOM_ACTION', + destinationUrl: 'https://google.com' + }); + + // Expect true to be returned for beacon request + expect(res).toEqual(''); + /** Expect merge to have completed correctly, the url to be constructed correctly, + and the clientSdk and authorization to be added to the request body in the correct format. **/ + expect(mockPostWithBeacon).toHaveBeenCalledWith( + 'https://eu.yextevents.com/accounts/me/events', + { + action: 'C_CUSTOM_ACTION', + authorization: 'KEY validKey', + bot: false, + browserAgent: { + browser: 'chrome', + browserVersion: '1.0.0', + device: 'desktop', + deviceClass: 'desktop', + os: 'windows', + osVersion: '10', + userAgent: 'chrome' + }, + chat: { + botId: 'botId', + conversationId: 'conversationId', + responseId: 'responseId' + }, + clientSdk: { + ANALYTICS: '1.0.0-beta.2', + chat: '1.0.0' + }, + count: 5, + customTags: { + customTag: 'customTagValue' + }, + customValues: { + customValue: 1 + }, + destinationUrl: 'https://google.com', + entity: 'entityId', + internalUser: false, + ip: { + address: '1.0.0.0', + algorithm: 'HASH' + }, + label: 'label', + locale: 'en_US', + location: { + coordinates: { + latitude: 1, + longitude: 1 + } + }, + pageUrl: 'https://yext.com', + referrerUrl: 'https://yext.com', + search: { + versionNumber: 5, + isDirectAnswer: false, + experienceKey: 'experienceKey', + queryId: 'queryId' + }, + searchTerm: 'searchTerm', + sessionId: 'sessionId', + sites: { + siteUid: 321, + template: 'template' + }, + timestamp: '1912-08-01T05:00:00.000Z', + value: { + amount: 1, + currency: 'USD' + }, + visitor: { + 'visitor-id': 'visitor-id' + } + } + ); + }); });