diff --git a/docs/analytics.md b/docs/analytics.md
index 3151656a..4190ff9b 100644
--- a/docs/analytics.md
+++ b/docs/analytics.md
@@ -17,6 +17,7 @@
| Function | Description |
| --- | --- |
| [analytics(config)](./analytics.analytics.md) | The Yext Analytics Events SDK. Returns an AnalyticsEventService given an AnalyticsConfig. |
+| [reportBrowserAnalytics()](./analytics.reportbrowseranalytics.md) | An alternative entry point for the Yext Analytics Events SDK, currently used by Google Tag Manager. This method reads the config and payload from the variable analyticsEventPayload stored in the global window object. The config and payload are then passed to the report function to be sent to the Yext Analytics Events API. |
## Interfaces
diff --git a/docs/analytics.reportbrowseranalytics.md b/docs/analytics.reportbrowseranalytics.md
new file mode 100644
index 00000000..499160b9
--- /dev/null
+++ b/docs/analytics.reportbrowseranalytics.md
@@ -0,0 +1,17 @@
+
+
+[Home](./index.md) > [@yext/analytics](./analytics.md) > [reportBrowserAnalytics](./analytics.reportbrowseranalytics.md)
+
+## reportBrowserAnalytics() function
+
+An alternative entry point for the Yext Analytics Events SDK, currently used by Google Tag Manager. This method reads the config and payload from the variable analyticsEventPayload stored in the global window object. The config and payload are then passed to the report function to be sent to the Yext Analytics Events API.
+
+Signature:
+
+```typescript
+export declare function reportBrowserAnalytics(): Promise;
+```
+Returns:
+
+Promise<string>
+
diff --git a/etc/analytics.api.md b/etc/analytics.api.md
index be9b5cfc..5bad0080 100644
--- a/etc/analytics.api.md
+++ b/etc/analytics.api.md
@@ -113,6 +113,9 @@ export enum RegionEnum {
US = "us"
}
+// @public
+export function reportBrowserAnalytics(): Promise;
+
// @public
export type VersionLabel = EnumOrString;
diff --git a/src/convertStringToValue.ts b/src/convertStringToValue.ts
new file mode 100644
index 00000000..fc43d580
--- /dev/null
+++ b/src/convertStringToValue.ts
@@ -0,0 +1,70 @@
+import { EventPayload } from './EventPayload';
+
+// Define the list of possibly numerical properties to check and convert
+const propertiesToCheck = [
+ 'sessionTrackingEnabled',
+ 'versionNumber',
+ 'siteUid',
+ 'count',
+ 'entity',
+ 'amount',
+ 'latitude',
+ 'longitude',
+ 'timestamp',
+ 'bot',
+ 'internalUser',
+ 'isDirectAnswer'
+];
+
+export function convertStringToValue(
+ data: Record
+): EventPayload {
+ // Recursive function to traverse and convert nested objects
+ function recursiveConversion(obj: Record) {
+ for (const property in obj) {
+ if (propertiesToCheck.includes(property)) {
+ // Check if the property is in the list of properties to convert,
+ // and if it's a string that represents a number, convert it to a number.
+ // If it's a boolean string, convert it to a boolean.
+ if (!isNaN(Number(obj[property]))) {
+ obj[property] = Number(obj[property]);
+ } else if (obj[property] === 'true' || obj[property] === 'false') {
+ obj[property] = obj[property] === 'true';
+ }
+ }
+ // If the property is an object, recursively call the function on it
+ else if (typeof obj[property] === 'object') {
+ recursiveConversion(obj[property] as Record);
+ }
+ }
+ }
+
+ // Copy the input data to avoid modifying the original
+ const result: Record = { ...data };
+ // Start the recursive conversion
+ recursiveConversion(result);
+
+ // Handle customValues separately as it's nested properties can have a user defined key name
+ if (result.customValues && typeof result.customValues === 'object') {
+ convertCustomValues(result.customValues as Record);
+ }
+
+ // Return the modified result
+ return {
+ ...result,
+ action: result.action as EventPayload['action']
+ };
+}
+
+// Function to convert custom values within customValues object
+function convertCustomValues(obj: Record) {
+ for (const key in obj) {
+ if (
+ obj.hasOwnProperty(key) &&
+ typeof obj[key] === 'string' &&
+ !isNaN(Number(obj[key]))
+ ) {
+ obj[key] = Number(obj[key]);
+ }
+ }
+}
diff --git a/src/index.ts b/src/index.ts
index 249ded6c..b2fa8fd2 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -1,6 +1,7 @@
import { AnalyticsConfig } from './AnalyticsConfig';
import { AnalyticsEventReporter } from './AnalyticsEventReporter';
import { AnalyticsEventService } from './AnalyticsEventService';
+import { convertStringToValue } from './convertStringToValue';
/**
* The Yext Analytics Events SDK.
@@ -11,6 +12,39 @@ export function analytics(config: AnalyticsConfig): AnalyticsEventService {
return new AnalyticsEventReporter(config);
}
+/**
+ * An alternative entry point for the Yext Analytics Events SDK, currently used by Google Tag Manager.
+ * This method reads the config and payload from the variable analyticsEventPayload stored
+ * in the global window object. The config and payload are then passed to the report function to be sent
+ * to the Yext Analytics Events API.
+ * @public
+ */
+export function reportBrowserAnalytics(): Promise {
+ const gtmPayload = window['analyticsEventPayload'];
+ let response: Promise;
+ if (gtmPayload) {
+ const config = gtmPayload[0][1] as Record;
+ const data = gtmPayload[1][1] as Record;
+ if (config) {
+ // User text input inside of Google Tag Manager defaults to a String type for all fields.
+ // However, the Events API expects true boolean and number types for certain fields.
+ // The below convertStringToValue method calls take care of converting the String types
+ // to the correct one's for the config and payload objects.
+ const correctedConfig = convertStringToValue(config);
+ const correctedData = convertStringToValue(data);
+ const reporter = new AnalyticsEventReporter(
+ correctedConfig as AnalyticsConfig
+ );
+ response = reporter.report(correctedData);
+ } else {
+ response = Promise.reject('No config found in payload.');
+ }
+ } else {
+ response = Promise.reject('No payload found.');
+ }
+ return response;
+}
+
export * from './AnalyticsConfig';
export * from './AnalyticsEventService';
export * from './Environment';
@@ -19,3 +53,10 @@ export * from './EventPayload';
export * from './EnumOrString';
export * from './Action';
export * from './VersionLabel';
+
+declare global {
+ interface Window {
+ analyticsEventPayload?: GTMPayload;
+ }
+}
+type GTMPayload = Record>;
diff --git a/src/test-gtm/index.html b/src/test-gtm/index.html
new file mode 100644
index 00000000..7a2ac4df
--- /dev/null
+++ b/src/test-gtm/index.html
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
+ Analytics Test
+
+
+
+
+
+