Skip to content

Commit

Permalink
Merge 7e0c024 into 15c44fe
Browse files Browse the repository at this point in the history
  • Loading branch information
ejaffee01 committed Aug 31, 2023
2 parents 15c44fe + 7e0c024 commit 3d7a973
Show file tree
Hide file tree
Showing 293 changed files with 2,836 additions and 6,393 deletions.
72 changes: 72 additions & 0 deletions .github/workflows/deploy_hold.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
name: Deploy assets to AWS S3 and GCP Cloud Storage with hold state setup in github's production environment

on:
workflow_call:
inputs:
bucket:
required: false
type: string
default: analytics
directory:
required: true
type: string
cache-control:
required: false
type: string
default: no-cache
secrets:
AWS_ACCESS_KEY_ID:
required: true
AWS_SECRET_ACCESS_KEY:
required: true
GCP_SA_KEY:
required: true

jobs:
deploy-aws:
runs-on: ubuntu-latest
environment: production # sets in github repo with reviewer requirement protection rule
steps:
- uses: actions/checkout@v3
- name: Download build-output-US artifact
uses: actions/download-artifact@v3
with:
name: build-output-US
path: dist/
- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v1-node16
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: us-east-1
- name: Deploy to S3
run: |
aws s3 cp ./dist/ s3://assets.sitescdn.net/${{ inputs.bucket }}/${{ inputs.directory }} \
--acl public-read \
--recursive \
--cache-control ${{ inputs.cache-control }}
deploy-gcp:
runs-on: ubuntu-latest
environment: production # sets in github repo with reviewer requirement protection rule
steps:
- uses: actions/checkout@v3
- name: Download build-output-EU artifact
uses: actions/download-artifact@v3
with:
name: build-output-EU
path: dist/
- name: Authenticate to Google Cloud
id: auth
uses: google-github-actions/auth@v1
with:
credentials_json: "${{ secrets.GCP_SA_KEY }}"
- name: Deploy to GCP Bucket
uses: google-github-actions/upload-cloud-storage@v1
with:
path: dist/
parent: false
destination: assets-eu.sitescdn.net/${{ inputs.bucket }}/${{ inputs.directory }}
process_gcloudignore: false
headers: |-
cache-control: ${{ inputs.cache-control }}
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
node_modules/
coverage/
dist/
lib/
temp/
.env
Expand Down
243 changes: 133 additions & 110 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,10 @@ A Typescript library for sending Yext Analytics events.

[Full Documentation](./docs/analytics.md)

## Features
# Yext Analytics
Yext Analytics is a Typescript library for sending analytics events that occur on your digital experiences to the Yext Analytics platform. You can record user actions that we offer out-of-the-box, such as page views and clicks, or custom actions that are unique to your business! Yext uses the same analytics reporting features across Search, Pages, and Chat so these products all use one interface.

- Works in both the **browser** and **Node.js**
- Works in the **browser** only.
- 100% **TypeScript**, with detailed analytics event models
- Compatible with both **CommonJS** and **ES6** imports

Expand All @@ -27,149 +28,171 @@ First, install the library via [npm](https://www.npmjs.com/get-npm):
```bash
npm install @yext/analytics
```
### Initialize Analytics Reporter

Next, import and initialize the library in your application. Yext currently has different analytics reporting features between Search and Pages and so they have slightly different interfaces for working with them. There is also a combined interface that you can use when you are building a Search experience entirely on Pages (e.g. a Locator or a Help Site).

### Search Analytics

Next, import and initialize the library in your application. When initializing your analytics reporter, you only need to provide an API Key that has access to the Events API. Other attributes such as your business ID will be automatically inferred. You can acquire this API key in the developer console of the Yext Platform.
```ts
import { provideSearchAnalytics } from '@yext/analytics'; // can also be imported as provideAnalytics
import { Analytics } from "@yext/analytics";

const searchAnalytics = provideSearchAnalytics({
experienceKey: '<your experience key>',
experienceVersion: 'PRODUCTION',
businessId: 123456, // this comes from the url of your Yext account
});
// Root analytics service with no defaults.
const rootAnalytics = new Analytics({ key: "MY_API_KEY" });
```
In many cases, you might need to repeatedly specify the same properties, such as a Pages site ID or Chat bot ID. Yext Analytics allows you to avoid having to repeatedly specify the same code by allowing you to set **default values**.

To use the library with Node, use the following import instead:
```ts
const { provideSearchAnalytics } = require('@yext/analytics');
```

Now that the search analytics reporter is initialized, let's fire off an event:

You can add a `.with()` method to the root analytics service you initialized, which returns a new analytics object with the specified JSON merged on top of the existing defaults.
```ts
searchAnalytics.report({
type: 'CTA_CLICK',
entityId: '1',
verticalKey: 'people',
searcher: 'VERTICAL',
queryId: '12345678-1234-1234-1234-123456789012'
});
```
import { Analytics } from "@yext/analytics";

#### Search Analytics Event Types
When specifying the analytics type, either the [SearchAnalyticsEventType](./docs/analytics.searchanalyticseventtype.md) enum or its corresponding string can be specified. For example, you can specify the 'CTA_CLICK' event with either 'CTA_CLICK' or
with `AnalyticsEventType.CtaClick`. Once the event type is specified, TypeScript is able to enforce the required and
optional properties for that event type.
// Root analytics service with no defaults.
const rootAnalytics = new Analytics({ key: "MY_API_KEY" });

### Pages Analytics
// Pages analytics service with Pages defaults.
const pageAnalytics = rootAnalytics.with({ pages: { siteId: 123 } });

```ts
import { providePagesAnalytics } from '@yext/analytics';

const pagesAnalytics = providePagesAnalytics({
debug: false, // enables console debugging logs if set to true
pageType: {
pageSetId: 'My Page Set', // the name of the feature in your features.json or the name of your template file
id: 90210, // the uid of the entity your page represents
name: 'static',
},
pagesReferrer: 'https://www.google.com', // e.g. document.referrer
path: '/foo/bar', // e.g. window.location.pathname
businessId: 12345, // this comes from the url of your Yext account
production: false, // set to true if you are in the production environment
siteId: 654321, // the id of your site, you can find this in the url of your deploy page
});
// Chat analytics service with both Chat **and** Pages defaults.
const chatAnalytics = pageAnalytics.with({ chat: { botId: "my-bot" } });
```
Calling `pageAnalytics.report()` sends an event with the `pages` object, plus anything passed to `report`. Calling `chatAnalytics.report()` sends an event with both the `pages` and `chat` objects, plus anything passed to `report`. You can override the default values defined in the .with() method by sending them along with the event.

Now that the pages analytics reporter is initialized, we can fire a pageview:
For other configuration features, see [AnalyticsConfig.ts](/docs/analytics.analyticsconfig.md)
### Fire an Event
Now that we’ve initialized our analytics reporter, we can fire an event! This sends a `CHAT_IMPRESSION` event type, along with a `sessionId`, a `pages.siteId`, and a `chat.botId`.
```ts
pagesAnalytics.pageView();
chatAnalytics.report({
action: "CHAT_IMPRESSION"
});
```
### Additional Configuration
#### Session Tracking
Session tracking is now available for Chat, Pages, and Search. Yext uses a browser-based method (sessionStorage) to track this. By default, session tracking is **enabled** in **both** the US and EU environments. This can be disabled by setting `sessionTrackingEnabled` to `false`.

If a user clicks on a CTA, we can track a CTA Click Event
When `sessionTrackingEnabled` is set to `true`, Analytics will automatically generate a ULID for `sessionId` and bind that ULID to events from the same browser session. Users may also provide their own `sessionId`, which takes precedence over the auto-generated ID by Analytics. [To read more about how we generate ULIDs, check out ulidx.](https://github.com/perry-mitchell/ulidx)

#### Custom Events
You can also send custom analytics events.
```ts
import { CtaClick } from '@yext/analytics';

pagesAnalytics.track(CtaClick);
pagesAnalytics.report({
action: "C_MY_CUSTOM_EVENT"
});
```

We can also fire an event on any other type of user interaction and give it a custom name:
Additionally, you can send arbitrary conversion events by specifying a `value` JSON object with a dollar `amount` and a `currency` in ISO format.
```ts
pagesAnalytics.track({eventType: 'C_MY_CUSTOM_EVENT'});
chatAnalytics.report({
action: "C_CONVERSION_EVENT"
value: {
amount: 10,
currency: "USD",
},
});
```
To learn more about sending conversion events, see our [API documentation](https://hitchhikers.yext.com/docs/eventsapis/events/events#operation/sendEvents).

### Chat Analytics
Chat Analytics work somewhat differently. For Chat Analytics, you only need to provide an API Key, and other attributes such as your business ID will be automatically inferred. You can acquire this API key in the developer console of the Yext Platform.

When `sessionTrackingEnabled` is set to true, Chat Analytics will automatically generate a ULID for `sessionId` and append to events from the same browser session. User may also provide their own `sessionId`, which takes precedence over the auto-generated id by Chat Analytics.
#### Custom Properties
You can attach custom properties to your analytics events by specifying either `customTags` or `customValues` with your request. `customTags` represent up to ten **string** key-value pairs and `customValues` represent up to ten **numeric** key-value pairs.

For example, if I set up an `ORDER` event for my restaurant and wanted to track whether a promotional code was used on the order, I could add an `promoCode` custom tag to the event.
```ts
import { provideChatAnalytics } from '@yext/analytics';
const chatAnalytics = provideChatAnalytics({
apiKey: '<your api key>',
pagesAnalytics.report({
action: "C_CONVERSION_EVENT",
sessionId: "e790f75d-4f1e-4a1b-b57b-9a456019b176",
value: {
amount: 35.50,
currency: "USD",
},
customTags: {
"promoCode": "SPRING15OFF"
}
});

analytics.report({
action: 'CHAT_IMPRESSION',
sessionId: 'e790f75d-4f1e-4a1b-b57b-9a456019b176',
sessionTrackingEnabled: true,
chat: {
botId: 'my-chat-bot',
```
Additionally, if I wanted to record the discount amount of the promotion, I could add a `promoDiscount` custom value to the `ORDER` event.
```ts
pagesAnalytics.report({
action: "C_CONVERSION_EVENT",
sessionId: "e790f75d-4f1e-4a1b-b57b-9a456019b176",
value: {
amount: 35.50,
currency: "USD",
},
customTags: {
"promoCode": "SPRING15OFF"
},
customValues: {
"promoDiscount": 41.76
}
})
});
```
### Debugging
We use `fetch()` + `keepalive` by default in [supported browsers](https://developer.mozilla.org/en-US/docs/Web/API/fetch) to make debugging easier. For browsers like Firefox that do not support `keepalive`, [we use the Beacon API](https://developer.mozilla.org/en-US/docs/Web/API/Beacon_API). Users can set `forceFetch: true` in their config, which will make these browsers use `fetch()` instead of the `Beacon API`. Be warned, since `forceFetch` uses `fetch()` without `keepalive`, **requests in progress for browsers like FireFox will be canceled if the page is unloaded**.

## Module support
- The ESM (ES6) build will be used automatically by module bundlers that support it (e.g. Webpack). It can be specified directly by importing `@yext/analytics/lib/esm`
- The CommonJS build will be used automatically by Node, but it can be specified directly by importing `@yext/analytics/lib/commonjs`

### Conversion Tracking
## License

Yext offers conversion tracking that can attribute values to conversion events that are driven by user interaction
with Yext's products. Once you have [setup conversion tracking](https://hitchhikers.yext.com/modules/ana104-conversion/01-conversion-overview/)
you can create a conversionTracking provider like so:
Yext Analytics is an open-sourced library licensed under the [BSD-3 License](./LICENSE).

```ts
import { provideConversionTrackingAnalytics } from '@yext/analytics';
const conversionTracker = provideConversionTrackingAnalytics();
```
## Third Party Licenses

In order to track conversions, you will need to set a Cookie on your users and pass the id of that cookie to the
conversion tracker when a conversion event occurs. Which can be done like so:
The licenses of our 3rd party dependencies are collected here: [THIRD-PARTY-NOTICES](./THIRD-PARTY-NOTICES).

```ts
conversionTracker.trackConversion({
cookieId: '12466678', //the unique id that you generated for the user cookie
cid: '12345-abcde-67890-fghij', //the value of the tag found in the conversion tracking setup page in your account
cv: 10, // the optional monetary value of the conversion event.
})
```
## Appendix

Additionally, if you are implementing Conversion tracking on a pages site, once you have setup the pages analytics tracker, you should turn on conversion tracking so that interactions on your pages site can be properly credited with conversions. That can be done like so:
### Merge Operations
When we merge the JSON, we abide by the following guidelines. For primitives:
* Merging an existing key with null/undefined **deletes the key**.
* Merging an existing key with a non-null value **updates the value**.
* Merging a new key **adds the new value**.

```ts
pagesAnalytics.setConversionTrackingEnabled(true, 'cookie id of the user goes here');
const x = {
foo: "bar",
num: 123,
baz: "remove me"
}

const y = {
num: 789,
bool: True
baz: null
}

merge(x,y)
/** ---------- Result -------------
* {
* foo: "bar",
* num: 789,
* bool: True
* }
*/
```

Then, when you track a page view it will automatically be credited for conversion tracking purposes. Additionally, if an event on your pages should be treated as a conversion, you would track it like so:
For objects, we recursively apply the above rules within the object. Merging multi-level objects strictly combines values on a level-by-level basis, so the first level of each JSON is merged, then the next, until there is nothing left to merge.

```ts
pagesAnalytics.track('event_to_track', {
cid: '12345-abcde-67890-fghij', // the value of the tag found in the conversion tracking setup page in your account
cv: 10, // the optional monetary value of the conversion event.
});
```

And that's it! See **[our documentation](./docs/analytics.md)** for a full list of analytics events.

## Module support
- The ESM (ES6) build will be used automatically by module bundlers that support it (e.g. Webpack). It can be specified directly by importing `@yext/analytics/lib/esm`
- The CommonJS build will be used automatically by Node, but it can be specified directly by importing `@yext/analytics/lib/commonjs`

## License

Yext Analytics is an open-sourced library licensed under the [BSD-3 License](./LICENSE).

## Third Party Licenses
const x = {
foo: {
bar: {
baz: 123
}
}
}

The licenses of our 3rd party dependencies are collected here: [THIRD-PARTY-NOTICES](./THIRD-PARTY-NOTICES).
const y = {
foo: {
baz: 789
}
}

merge(x,y)
/** ---------- Result -------------
* {
* foo: {
* bar: {
* baz: 123
* },
* baz: 789
* }
* }
*/
```
2 changes: 1 addition & 1 deletion api-extractor.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@
*
* SUPPORTED TOKENS: <projectFolder>, <packageName>, <unscopedPackageName>
*/
"mainEntryPointFilePath": "<projectFolder>/lib/esm/index.d.ts",
"mainEntryPointFilePath": "<projectFolder>/lib/esm/src/index.d.ts",

/**
* A list of NPM package names whose exports should be treated as part of this package.
Expand Down
13 changes: 0 additions & 13 deletions docs/analytics.accordiontoggleevent.entityid.md

This file was deleted.

Loading

0 comments on commit 3d7a973

Please sign in to comment.