From 5d43251286c39524052f1707d54fb864f8dd7826 Mon Sep 17 00:00:00 2001 From: Marcos Passos Date: Mon, 23 Sep 2024 18:10:07 -0600 Subject: [PATCH] Update readme and remove docs (#307) --- .github/assets/header-dark-mobile.svg | 115 +++ .github/assets/header-dark.svg | 115 +++ .github/assets/header-light-mobile.svg | 131 +++ .github/assets/header-light.svg | 131 +++ README.md | 202 +---- docs/evaluator.md | 44 - docs/events.md | 1127 ------------------------ docs/patch.md | 351 -------- docs/plug.md | 421 --------- docs/quick-start.md | 450 ---------- docs/session.md | 52 -- docs/testing.md | 107 --- docs/tracker.md | 71 -- docs/troubleshooting.md | 114 --- docs/user.md | 116 --- 15 files changed, 524 insertions(+), 3023 deletions(-) create mode 100644 .github/assets/header-dark-mobile.svg create mode 100644 .github/assets/header-dark.svg create mode 100644 .github/assets/header-light-mobile.svg create mode 100644 .github/assets/header-light.svg delete mode 100644 docs/evaluator.md delete mode 100644 docs/events.md delete mode 100644 docs/patch.md delete mode 100644 docs/plug.md delete mode 100644 docs/quick-start.md delete mode 100644 docs/session.md delete mode 100644 docs/testing.md delete mode 100644 docs/tracker.md delete mode 100644 docs/troubleshooting.md delete mode 100644 docs/user.md diff --git a/.github/assets/header-dark-mobile.svg b/.github/assets/header-dark-mobile.svg new file mode 100644 index 00000000..df6b6399 --- /dev/null +++ b/.github/assets/header-dark-mobile.svg @@ -0,0 +1,115 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.github/assets/header-dark.svg b/.github/assets/header-dark.svg new file mode 100644 index 00000000..c6fcba4c --- /dev/null +++ b/.github/assets/header-dark.svg @@ -0,0 +1,115 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.github/assets/header-light-mobile.svg b/.github/assets/header-light-mobile.svg new file mode 100644 index 00000000..f24da787 --- /dev/null +++ b/.github/assets/header-light-mobile.svg @@ -0,0 +1,131 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.github/assets/header-light.svg b/.github/assets/header-light.svg new file mode 100644 index 00000000..ed9a8b17 --- /dev/null +++ b/.github/assets/header-light.svg @@ -0,0 +1,131 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/README.md b/README.md index bad7a508..cb4c4520 100644 --- a/README.md +++ b/README.md @@ -1,196 +1,58 @@

- Plug JS + + + + + + + Croct JavaScript SDK + + +
+ Croct JavaScript SDK
+ Bring dynamic, personalized content natively into your applications.

- -

- +
+ πŸ“˜ Quick start → +
+

Version - Build - Maintainability - Coverage Gzipped bundle size -


- πŸ“¦ Releases - Β· - 🐞 Report Bug - Β· - ✨ Request Feature + Coverage

-## Overview - -Plug JS is the easiest way to collect, manage, and consume real-time data to fuel personalized experiences. -A single line of code gives you a fully-featured devkit for building natively personalized applications. - -- **Zero configuration.** No setup steps required. -- **No backend necessary.** Deliver personalized experiences from static sites. -- **Fast queries.** Double-digit millisecond latency for real-time evaluations. -- **Fully extensible API.** Easily add and share new features via plugins. -- **Type-Safe.** Typescript typings included. -- **Playground integration** One-click to connect, no configuration needed. - -## Installation +
-There are two ways to install the Croct SDK: +### Introduction -### NPM +Croct is a headless CMS that helps you manage content, run AB tests, and personalize experiences without the hassle of complex integrations. -The recommended way to install the SDK is via [NPM](https://npmjs.com). It pairs nicely with module bundlers such as -Webpack or Browserify and includes Typescript typings. +### Installation -In most cases, it should be as simple as running the following in your project: +Run this command to install the SDK: ```sh npm install @croct/plug ``` +See our [quick start guide](https://docs.croct.com/reference/sdk/javascript/installation) for more details. -Then, call [`croct.plug`](docs/plug.md#plug) passing the App ID to initialize the SDK: - -```js -import croct from '@croct/plug'; - -croct.plug({appId: ''}); -``` - -### Script Tag - -To install the SDK as a script tag, add the following line to the `` tag of your site on any pages you plan to use the SDK to personalize or track events: - -```html - - -``` - -You should replace the `` placeholder with the respective App ID. For more information about the available options, see [`croct.plug`](docs/plug.md#plug). - -## Getting Started - -> πŸ–οΈ **Just for your convenience** -> We will use CodePen throughout the tutorial to let you play with the examples right in your browser. - -Follow the steps below to connect the playground with CodePen: - -1. [Open the playground](http://play.croct.com/) -2. Click on the _"Don't have an API Key?"_ link to proceed in sandbox mode -3. Enter the URL `https://codepen.io/pen` -4. Click on _"Let's play!"_ - -
- -

- Connecting -

+### Documentation -> πŸ’‘οΈ **Hint** -> You will typically use an API key to connect to your development, staging, or production environments in real cases, -> but you can also use a local URL, such as `https://localhost/myapp`. +Visit our [official documentation](https://docs.croct.com/reference/sdk/javascript/installation). -Now, try evaluating the expression below: +### Support -``` -user is returning -``` +Join our official [Slack channel](https://croct.link/community) to get help from the Croct team and other developers. -After clicking on the _Evaluate_ button, you will see the result at the bottom of the page, which is either `true` or -`false` depending on whether it is the first time playing with this example. +### Contribution -Let's now implement our first personalization feature. Click on the three-dots icon on the editor's top right corner -and select _"Open in CodePen"_. Then, copy the code below and paste into the HTML panel: - -```html - - - -``` - -Try clicking _"πŸ‘‹ Say Hey"_, and you should see a personalized greeting. - -πŸŽ‰ **Congratulations!** You have successfully implemented your first personalization feature using Croct. For a more -in-depth walk-through, check out our [quick start guide](docs/quick-start.md). - -## Documentation - -The following references provide guidance to help you get started, integrate, and troubleshoot problems: - -- [Quick Start Guide](docs/quick-start.md) -- [Plug Reference](docs/plug.md) -- [Tracker Reference](docs/tracker.md) -- [Evaluator Reference](docs/evaluator.md) -- [Event Reference](docs/events.md) -- [Patch Reference](docs/patch.md) -- [User Reference](docs/user.md) -- [Session Reference](docs/session.md) -- [Testing](docs/testing.md) -- [Troubleshooting](docs/troubleshooting.md) - -If you are new to the Croct platform, the [quick start guide](docs/quick-start.md) is a good starting point for -application developers to begin learning the essential concepts. - -## Support - -If the [troubleshooting section](docs/troubleshooting.md) does not cover your problem, don't worry, there are -alternative ways to get help from the Croct community. - -### Stack Overflow - -Someone else from the community may have already asked a similar question or may be able to help with your problem. - -The Croct team will also monitor posts with the "croct" tag. If there aren't any existing questions that help, -please [ask a new one](https://stackoverflow.com/questions/ask?tags=croct%20plugjs). - -### GitHub - -If you have what looks like a bug, or you would like to make a feature request, please -[open a new issue on GitHub](https://github.com/croct-tech/plug-js/issues/new/choose). - -Before you file an issue, a good practice is to search for issues to see whether others have the same or similar problems. -If you are unable to find an open issue addressing the problem, then feel free to open a new one. - -### Slack Channel - -Many people from the Croct community hang out on the Croct Slack Group. -Feel free to [join us and start a conversation](https://croct.link/community). - -## Contributing - -Contributions to the package are always welcome! +Contributions are always welcome! - Report any bugs or issues on the [issue tracker](https://github.com/croct-tech/plug-js/issues). - For major changes, please [open an issue](https://github.com/croct-tech/plug-js/issues) first to discuss what you would like to change. -- Please make sure to update tests as appropriate. - -## Testing - -Before running the test suites, the development dependencies must be installed: - -```sh -npm install -``` - -Then, to run all tests: - -```sh -npm test -``` +- Please make sure to update tests as appropriate. Run tests with `npm test`. -## License +### License -This project is released under the [MIT License](LICENSE). +This library is licensed under the [MIT license](LICENSE). diff --git a/docs/evaluator.md b/docs/evaluator.md deleted file mode 100644 index f9c84a1d..00000000 --- a/docs/evaluator.md +++ /dev/null @@ -1,44 +0,0 @@ -# Evaluator API Reference - -This reference documents all methods available in the Evaluator API and explains in detail how these methods work. - -## Index - -- [evaluate](#evaluate) - -## evaluate - -This method evaluates an expression written in CQL. - -Check out our [quick start guide](quick-start.md) for an introduction to what is CQL and how it works. - -> ℹ️️ **Note** -> We currently impose a hard limit of 500 characters on the length of expression. -> We plan to remove this limitation in the near future. - - -### Signature - -The `evaluation` method has the following signature: - -```ts -croct.evaluator.evaluate(expression: string, options?: EvaluationOptions): Promise -``` - -These are the currently supported options: - -| Option | Type | Description | -|--------------|--------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| `timeout` | number | The maximum evaluation time in milliseconds. Once reached, the evaluator will abort the evaluator and reject the promise with a timeout error. | -| `attributes` | JSON | This option represents a map of attributes to inject into the evaluation context. For example, passing the attributes `{cities: ['New York', 'San Francisco']}` you can reference them in expressions like `context's cities include location's city`. Context attributes allow null, numbers, booleans, strings up to 50 character length, and arrays of primitives with up to 200 elements. | - -The return is a [Promise](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise) that -resolves to the evaluation result. - -### Code Sample - -Here's a minimal example showing how evaluate an expression: - -```ts -croct.evaluator.evaluate('session is starting').then(console.log); -``` diff --git a/docs/events.md b/docs/events.md deleted file mode 100644 index ac8ddbb7..00000000 --- a/docs/events.md +++ /dev/null @@ -1,1127 +0,0 @@ -# Events - -Events represent something that happened and help understanding how a user interacts with your application. Besides -telling the story of what happened during a user’s journey, these events also provide data to enrich the -evaluation context and refine the models that continuously improve user experience. - -The SDK tracks most of the general-purpose events automatically for you. All other events depend on your use case, so -it is up to you to decide which events make sense for your application. In the following sections, you will find a -summary of all events available to help you decide which events can benefit your application. - -## Table of Contents - -- [Event Summary](#event-summary) -- [User Events](#user-events) - * [userSignedUp](#usersignedup) - * [userSignedIn](#usersignedin) - * [userSignedOut](#usersignedout) - * [userProfileChanged](#userprofilechanged) -- [Web Events](#web-events) - * [tabOpened](#tabopened) - * [tabUrlChanged](#taburlchanged) - * [tabVisibilityChanged](#tabvisibilitychanged) - * [pageOpened](#pageopened) - * [pageLoaded](#pageloaded) -- [E-commerce Events](#e-commerce-events) - * [productViewed](#productviewed) - * [cartViewed](#cartviewed) - * [cartModified](#cartmodified) - * [checkoutStarted](#checkoutstarted) - * [orderPlaced](#orderplaced) -- [Analytics Events](#analytics-events) - * [goalCompleted](#goalcompleted) -- [Miscellaneous Events](#miscellaneous-events) - * [interestShown](#interestShown) - * [postViewed](#postViewed) - * [sessionAttributesChanged](#sessionattributeschanged) - * [nothingChanged](#nothingchanged) - * [eventOccurred](#eventoccurred) - * [linkOpened](#linkOpened) - -## Event Summary - -There are several event types that you can record within the customer journey: - -| Event | Category | Auto tracking | Description | -|---------------------------------------------------------|---------------|---------------|--------------------------------------------------| -| [`userSignedUp`](#usersignedup) | User | No | Records a user sign-up. | -| [`userSignedIn`](#usersignedin) | User | Yes | Records a user sign-in. | -| [`userSignedOut`](#usersignedout) | User | Yes | Records a user sign-out. | -| [`userProfileChanged`](#userprofilechanged) | User | Yes | Records user profile changes. | -| [`tabOpened`](#tabopened) | Web | Yes | Records a tab open. | -| [`tabUrlChanged`](#taburlchanged) | Web | Yes | Records a tab's URL change. | -| [`tabVisibilityChanged`](#tabvisibilitychanged) | Web | Yes | Records a tab visibility change. | -| [`pageOpened`](#pageopened) | Web | Yes | Records a page open. | -| [`pageLoaded`](#pageloaded) | Web | Yes | Records a page load. | -| [`productViewed`](#productviewed) | E-commerce | No | Records a product view. | -| [`cartViewed`](#cartviewed) | E-commerce | No | Records a shopping cart view. | -| [`cartModified`](#cartmodified) | E-commerce | No | Records a shopping cart change. | -| [`checkoutStarted`](#checkoutstarted) | E-commerce | No | Records a checkout start. | -| [`orderPlaced`](#orderplaced) | E-commerce | No | Records a placed order. | -| [`goalCompleted`](#goalcompleted) | Analytics | No | Records a goal completion. | -| [`interestShown`](#interestShown) | Miscellaneous | No | Records a user has shown interest in something. | -| [`postViewed`](#postViewed) | Miscellaneous | No | Records a post view. | -| [`linkOpened`](#linkOpened) | Miscellaneous | No | This event records a link opening. | -| [`sessionAttributesChanged`](#sessionattributeschanged) | Miscellaneous | Yes | Records session's attributes changes. | -| [`nothingChanged`](#nothingchanged) | Miscellaneous | Yes | Records a period of inactivity. | -| [`eventOccurred`](#eventOccurred) | Miscellaneous | No | Records a custom event. | - -## User Events - -The user category has the following events: - -### userSignedUp - -This event records that a user signed up. - -You should track this event when a user signs up for your application. - -If the user profile does not exist, the engine will create a new one with the provided information. -This event does not affect existing profiles. - -For the personalization engine, the semantics of this event does not encompass the -[`userSignedIn`](#usersignedin) event. If your application automatically signs in users after registration, make sure -to call the [`identify`](plug.md#identify) method after the sign-up. - -#### Properties - -This event supports the following properties: - -| Property | Type | Constraints | Required | Description | -|------------------------------|----------|-------------------------------------------------|----------|---------------------------------------------------------------| -| `userId` | `string` | 1 and 254 characters | Yes | The ID that uniquely identifies the user on your application. | -| `profile` | `object` | | No | The user profile. | -| `profile.firstName` | `String` | Between 1 and 50 characters long | No | The first name. | -| `profile.lastName` | `String` | Between 1 and 50 characters long | No | The last name. | -| `profile.birthDate` | `String` | Valid date in the form `YYYY-MM-DD` | No | The birth date. | -| `profile.gender` | `String` | Either `male`, `female`, `neutral` or `unknown` | No | The gender. | -| `profile.email` | `String` | Between 1 and 254 characters long | No | The email address. | -| `profile.alternateEmail` | `String` | Between 1 and 254 characters long | No | The alternate email address. | -| `profile.phone` | `String` | Between 1 and 30 characters long | No | The phone number. | -| `profile.alternatePhone` | `String` | Between 1 and 30 characters long | No | The alternate phone number. | -| `profile.address` | `object` | | No | The user address. | -| `profile.address.street` | `String` | Between 1 and 100 characters long | No | The address' street. | -| `profile.address.district` | `String` | Between 1 and 100 characters long | No | The address' district. | -| `profile.address.city` | `String` | Between 1 and 100 characters long | No | The address' city. | -| `profile.address.region` | `String` | Between 1 and 100 characters long | No | The address' region. | -| `profile.address.country` | `String` | Between 1 and 100 characters long | No | The address' country. | -| `profile.address.postalCode` | `String` | Between 1 and 20 characters long | No | The address' postal code. | -| `profile.avatar` | `String` | Well-formed URL | No | The personal avatar URL. | -| `profile.company` | `String` | Between 1 and 200 characters long | No | The company's name. | -| `profile.companyUrl` | `String` | Well-formed URL | No | The company's website URL. | -| `profile.jobTitle` | `String` | Between 1 and 50 characters long | No | The job title. | -| `profile.custom` | `object` | JSON object | No | The map of custom attributes. | - -#### Code Sample - -Here are some examples of how to track this event: - -
- Minimal Example - -```ts -croct.track('userSignedUp', { - userId: '1ed2fd65-a027-4f3a-a35f-c6dd97537392' -}); -``` - -
- -
- Complete Example - -```ts -croct.track('userSignedUp', { - userId: '1ed2fd65-a027-4f3a-a35f-c6dd97537392', - profile: { - firstName: 'Carol', - lastName: 'Doe', - birthDate: '2000-08-31', - gender: 'female', - email: 'carol@croct.com', - alternateEmail: 'example@croct.com', - phone: '+15555983800', - alternatePhone: '+15555983800', - address: { - street: '123 Some Street', - district: 'Kings Oak', - city: 'San Francisco', - state: 'California', - region: 'California', - country: 'US', - continent: 'NA' - }, - avatar: 'http://croct.com/carol.png', - company: 'Croct', - companyUrl: 'http://croct.com', - jobTitle: 'Head of Marketing', - custom: { - points: 1, - favoriteEmoji: '🐊', - } - } -}); -``` - -
- -### userSignedIn - -This event records that a user signed in. - -The SDK automatically tracks this event when you call either the [`identify`](plug.md#identify) or -[`setToken`](plug.md#settoken) method. - -### userSignedOut - -This event records that a user signed out. - -The SDK automatically tracks this event when you call either the [`anonymize`](plug.md#identify) or -[`setToken`](plug.md#settoken) method. - -### userProfileChanged - -This event records that a user profile has changed. - -The SDK automatically tracks this event when you call [`save`](patch.md#save) on the patch returned by the -[`user.edit()`](user.md#edit) method. - -## Web Events - -The web category has the following events: - -### tabOpened - -This event records that a user opened a new tab. - -The SDK automatically tracks this event when the user opens your application in a new tab. - -### tabUrlChanged - -This event records that the tab URL changed. - -The SDK automatically tracks this event when the user navigates between pages on your application. - -### tabVisibilityChanged - -This event records that the tab visibility changed. - -The SDK automatically tracks this event when user minimizes the window or switches to another tab. - -### pageOpened - -This event records that a user opened a page. - -The SDK automatically tracks this event when the user opens a page on your application. - -### pageLoaded - -This event records that a page finished loading. - -The SDK automatically tracks this event when a page has been completely loaded, without waiting for stylesheets or -images to finish loading. - -## E-commerce Events - -The e-commerce category has the following events: - -### productViewed - -This event records the user viewed a product. - -You should track this event when a user opens a product page. - -#### Properties - -This event supports the following properties: - -| Property | Type | Required | Constraints | Description | -|-------------------------|----------|----------|-----------------------------------|----------------------------------------------------------------------| -| `product` | `object` | Yes | | The product details. | -| `product.productId` | `string` | Yes | Between 1 and 50 characters long | The ID that uniquely identifies the product on your store. | -| `product.name` | `string` | Yes | Between 1 and 200 characters long | The name of the product. | -| `product.displayPrice` | `number` | Yes | Non-negative | The price of the product displayed in the store. | -| `product.sku` | `string` | No | Between 1 and 50 characters long | The code that uniquely identifies the product variant on your store. | -| `product.category` | `string` | No | Between 1 and 100 characters long | The category of the product. | -| `product.brand` | `string` | No | Between 1 and 100 characters long | The brand associated with the product. | -| `product.variant` | `string` | No | Between 1 and 50 characters long | The variant of the product, such as size, color and style. | -| `product.originalPrice` | `number` | No | Non-negative | The original price of the product. | -| `product.url` | `string` | No | Well-formed URL | The URL of the product page. | -| `product.imageUrl` | `string` | No | Well-formed URL | The URL of the main product image. | - -**Note:** - -- The `sku` and `productId` do not have to be different. Usually, the `productId` is the internal identifier, - like `12345`, and the SKU is a public-facing identifier like `SM-124-GREEN`. -- The `displayPrice` is the price the user pays, while the `originalPrice` is usually the regular retail price. - -#### Code Sample - -Here are some examples of how to track this event: - -
- Minimal Example - -```ts -croct.track('productViewed', { - product: { - productId: '12345', - name: 'Smartphone 9', - displayPrice: 599.00 - } -}); -``` - -
- -
- Complete Example - -```ts -croct.track('productViewed', { - product: { - productId: '12345', - sku: 'a9b2745f-9d0b-4bfe-8ebd-7376dd932169', - name: 'Smartphone 9', - category: 'Smartphone', - brand: 'Pear', - variant: '64GB Green', - displayPrice: 599.00, - originalPrice: 699.00, - url: 'https://www.acme.com/product/smartphone9', - imageUrl: 'https://www.acme.com/images/smartphone9-64gb-green.png' - } -}); -``` - -
- -### cartViewed - -This event records the user viewed the shopping cart. - -You should track this event when a user views the shopping cart page or summary. - -#### Properties - -This event supports the following properties: - -| Property | Type | Required | Constraints | Description | -|---------------------------------------|----------|----------|-----------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| `cart` | `object` | Yes | | The cart information. | -| `cart.currency` | `string` | Yes | Between 1 and 10 characters long | The currency in which the monetary values are expressed in the shopping cart. We recommend using the 3-letter currency codes defined by the [ISO 4217](https://en.wikipedia.org/wiki/ISO_4217) standard. For currencies having no official recognition in [ISO 4217](https://en.wikipedia.org/wiki/ISO_4217), consider using ISO-like codes adopted locally or commercially, such as `XBT` for BitCoin. | -| `cart.total` | `number` | Yes | Non-negative | The total revenue or grand total associated with the transaction. It includes shipping, tax, and any other adjustment. | -| `cart.items` | `array` | Yes | | The list of items. | -| `cart.items[*].product` | `object` | Yes | | The product details. | -| `cart.items[*].product.productId` | `string` | Yes | Between 1 and 50 characters long | The ID that uniquely identifies the product on your store. | -| `cart.items[*].product.name` | `string` | Yes | Between 1 and 200 characters long | The name of the product. | -| `cart.items[*].product.displayPrice` | `number` | Yes | Non-negative | The price of the product displayed in the store. | -| `cart.items[*].index` | `number` | Yes | Non-negative | The index, starting from zero, which represents the order in which the item was added to the shopping cart. | -| `cart.items[*].quantity` | `number` | Yes | Positive | The number of units of the item. | -| `cart.items[*].total` | `number` | Yes | Non-negative | The total for the item. It includes discounts and any other adjustment. | -| `cart.items[*].product.sku` | `string` | No | Between 1 and 50 characters long | The code that uniquely identifies the product variant on your store. | -| `cart.items[*].product.category` | `string` | No | Between 1 and 100 characters long | The category of the product. | -| `cart.items[*].product.brand` | `string` | No | Between 1 and 100 characters long | The brand associated with the product. | -| `cart.items[*].product.variant` | `string` | No | Between 1 and 50 characters long | The variant of the product, such as size, color and style. | -| `cart.items[*].product.originalPrice` | `number` | No | Non-negative | The original price of the product. | -| `cart.items[*].product.url` | `string` | No | Well-formed URL | The URL of the product page. | -| `cart.items[*].product.imageUrl` | `string` | No | Well-formed URL | The URL of the main product image. | -| `cart.items[*].discount` | `number` | No | Non-negative | The amount of the discount applied to the item. | -| `cart.items[*].coupon` | `number` | No | Between 1 and 50 characters long | The coupon applied to the item. | -| `cart.subtotal` | `number` | No | Non-negative | The total of all items and quantities in the shopping cart including applied item promotions. Applied cart discounts, estimated shipping, and applied shipping discounts should be excluded from the subtotal amount. | -| `cart.shippingPrice` | `number` | No | Non-negative | The total shipping price for the items in the shopping cart, including any handling charges. | -| `cart.taxes` | `object` | No | Non-empty string keys and values | The taxes associated with the transaction. | -| `cart.costs` | `object` | No | Non-empty string keys and values | The costs associated with the transaction, such as manufacturing costs, shipping expenses not borne by the customer, or any other costs. | -| `cart.discount` | `number` | No | Non-negative | The amount of the discount applied to the shopping cart. | -| `cart.coupon` | `string` | No | Between 1 and 50 characters long | The coupon applied to the shopping cart. | -| `cart.lastUpdateTime` | `number` | No | Non-negative | The time when the shopping cart was last updated, in milliseconds since epoch. | - -**Note:** - -- The `sku` and `productId` do not have to be different. Usually, the `productId` is the internal identifier, - like `12345`, and the SKU is a public-facing identifier like `SM-124-GREEN`. -- The `displayPrice` is the price the user pays, while the `originalPrice` is usually the regular retail price. -- When you don't specify a value for the `lastUpdateTime` property, the SDK considers the time at which you tracked the - event as the last update time. - -#### Code Sample - -Here are some examples of how to track this event: - -
- Minimal Example - -```ts -croct.track('cartViewed', { - cart: { - currency: 'USD', - total: 776.49, - items: [ - { - index: 0, - total: 699.00, - quantity: 1, - product: { - productId: '12345', - name: 'Smartphone 9', - displayPrice: 699.00 - } - } - ] - } -}); -``` - -
- -
- Complete Example - -```ts -croct.track('cartViewed', { - cart: { - currency: 'USD', - items: [ - { - index: 0, - quantity: 1, - total: 699.00, - discount: 100.00, - coupon: 'PROMO', - product: { - productId: '12345', - sku: 'SM-124-GREEN', - name: 'Smartphone 9', - category: 'Smartphone', - brand: 'Acme', - variant: '64GB Green', - displayPrice: 699.00, - originalPrice: 799.00, - url: 'https://www.acme.com/product/smartphone9', - imageUrl: 'https://www.acme.com/images/smartphone9-64gb-green.png' - } - }, - { - index: 1, - quantity: 1, - total: 39.00, - discount: 10.00, - coupon: 'PROMO', - product: { - productId: '98765', - sku: '03132db8-2c37-4aef-9827-60d0206683d9', - name: 'Silicone Case', - category: 'Cases', - brand: 'Acme', - variant: 'Black', - displayPrice: 39.00, - originalPrice: 49.00, - url: 'https://www.acme.com/product/silicone-case', - imageUrl: 'https://www.acme.com/images/silicone-case-black' - } - } - ], - taxes: { - state: 53.51, - local: 23.98 - }, - costs: { - manufacturing: 275.81, - cos: 85.37 - }, - subtotal: 848.00, - shippingPrice: 59.99, - discount: 169.99, - total: 815.49, - coupon: 'FREE-SHIPPING', - lastUpdateTime: 123456789 - } -}); -``` - -
- -### cartModified - -This event records the user modified the shopping cart. - -You should track this event when a user modifies the shopping cart page, either by adding, removing, or updating items. - -#### Properties - -This event supports the following properties: - -| Property | Type | Required | Constraints | Description | -|---------------------------------------|----------|----------|-----------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| `cart` | `object` | Yes | | The cart information. | -| `cart.currency` | `string` | Yes | Between 1 and 10 characters long | The currency in which the monetary values are expressed in the shopping cart. We recommend using the 3-letter currency codes defined by the [ISO 4217](https://en.wikipedia.org/wiki/ISO_4217) standard. For currencies having no official recognition in [ISO 4217](https://en.wikipedia.org/wiki/ISO_4217), consider using ISO-like codes adopted locally or commercially, such as `XBT` for BitCoin. | -| `cart.total` | `number` | Yes | Non-negative | The total revenue or grand total associated with the transaction. It includes shipping, tax, and any other adjustment. | -| `cart.items` | `array` | Yes | | The list of items. | -| `cart.items[*].product` | `object` | Yes | | The product details. | -| `cart.items[*].product.productId` | `string` | Yes | Between 1 and 50 characters long | The ID that uniquely identifies the product on your store. | -| `cart.items[*].product.name` | `string` | Yes | Between 1 and 200 characters long | The name of the product. | -| `cart.items[*].product.displayPrice` | `number` | Yes | Non-negative | The price of the product displayed in the store. | -| `cart.items[*].index` | `number` | Yes | Non-negative | The index, starting from zero, which represents the order in which the item was added to the shopping cart. | -| `cart.items[*].quantity` | `number` | Yes | Positive | The number of units of the item. | -| `cart.items[*].total` | `number` | Yes | Non-negative | The total for the item. It includes discounts and any other adjustment. | -| `cart.items[*].product.sku` | `string` | No | Between 1 and 50 characters long | The code that uniquely identifies the product variant on your store. | -| `cart.items[*].product.category` | `string` | No | Between 1 and 100 characters long | The category of the product. | -| `cart.items[*].product.brand` | `string` | No | Between 1 and 100 characters long | The brand associated with the product. | -| `cart.items[*].product.variant` | `string` | No | Between 1 and 50 characters long | The variant of the product, such as size, color and style. | -| `cart.items[*].product.originalPrice` | `number` | No | Non-negative | The original price of the product. | -| `cart.items[*].product.url` | `string` | No | Well-formed URL | The URL of the product page. | -| `cart.items[*].product.imageUrl` | `string` | No | Well-formed URL | The URL of the main product image. | -| `cart.items[*].discount` | `number` | No | Non-negative | The amount of the discount applied to the item. | -| `cart.items[*].coupon` | `number` | No | Between 1 and 50 characters long | The coupon applied to the item. | -| `cart.subtotal` | `number` | No | Non-negative | The total of all items and quantities in the shopping cart including applied item promotions. Applied cart discounts, estimated shipping, and applied shipping discounts should be excluded from the subtotal amount. | -| `cart.shippingPrice` | `number` | No | Non-negative | The total shipping price for the items in the shopping cart, including any handling charges. | -| `cart.taxes` | `object` | No | Non-empty string keys and values | The taxes associated with the transaction. | -| `cart.costs` | `object` | No | Non-empty string keys and values | The costs associated with the transaction, such as manufacturing costs, shipping expenses not borne by the customer, or any other costs. | -| `cart.discount` | `number` | No | Non-negative | The amount of the discount applied to the shopping cart. | -| `cart.coupon` | `string` | No | Between 1 and 50 characters long | The coupon applied to the shopping cart. | -| `cart.lastUpdateTime` | `number` | No | Non-negative | The time when the shopping cart was last updated, in milliseconds since epoch. | - -**Note:** - -- The `sku` and `productId` do not have to be different. Usually, the `productId` is the internal identifier, - like `12345`, and the SKU is a public-facing identifier like `SM-124-GREEN`. -- The `displayPrice` is the price the user pays, while the `originalPrice` is usually the regular retail price. -- When you don't specify a value for the `lastUpdateTime` property, the SDK considers the time at which you tracked the - event as the last update time. - -#### Code Sample - -Here are some examples of how to track this event: - -
- Minimal Example - -```ts -croct.track('cartModified', { - cart: { - currency: 'USD', - total: 776.49, - items: [ - { - index: 0, - total: 699.00, - quantity: 1, - product: { - productId: '12345', - name: 'Smartphone 9', - displayPrice: 699.00 - } - } - ] - } -}); -``` - -
- -
- Complete Example - -```ts -croct.track('cartModified', { - cart: { - currency: 'USD', - items: [ - { - index: 0, - quantity: 1, - total: 699.00, - discount: 100.00, - coupon: 'PROMO', - product: { - productId: '12345', - sku: 'SM-124-GREEN', - name: 'Smartphone 9', - category: 'Smartphone', - brand: 'Acme', - variant: '64GB Green', - displayPrice: 699.00, - originalPrice: 799.00, - url: 'https://www.acme.com/product/smartphone9', - imageUrl: 'https://www.acme.com/images/smartphone9-64gb-green.png' - } - }, - { - index: 1, - quantity: 1, - total: 39.00, - discount: 10.00, - coupon: 'PROMO', - product: { - productId: '98765', - sku: '03132db8-2c37-4aef-9827-60d0206683d9', - name: 'Silicone Case', - category: 'Cases', - brand: 'Acme', - variant: 'Black', - displayPrice: 39.00, - originalPrice: 49.00, - url: 'https://www.acme.com/product/silicone-case', - imageUrl: 'https://www.acme.com/images/silicone-case-black' - } - } - ], - taxes: { - state: 53.51, - local: 23.98 - }, - costs: { - manufacturing: 275.81, - cos: 85.37 - }, - subtotal: 848.00, - shippingPrice: 59.99, - discount: 169.99, - total: 815.49, - coupon: 'FREE-SHIPPING', - lastUpdateTime: 123456789 - } -}); -``` - -
- -### checkoutStarted - -This event records the checkout process started. - -You should track this event on the page that the user lands on after clicking on the checkout button. - -#### Properties - -This event supports the following properties: - -| Property | Type | Required | Constraints | Description | -|---------------------------------------|----------|----------|-----------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| `cart` | `object` | Yes | | The cart information. | -| `cart.currency` | `string` | Yes | Between 1 and 10 characters long | The currency in which the monetary values are expressed in the shopping cart. We recommend using the 3-letter currency codes defined by the [ISO 4217](https://en.wikipedia.org/wiki/ISO_4217) standard. For currencies having no official recognition in [ISO 4217](https://en.wikipedia.org/wiki/ISO_4217), consider using ISO-like codes adopted locally or commercially, such as `XBT` for BitCoin. | -| `cart.total` | `number` | Yes | Non-negative | The total revenue or grand total associated with the transaction. It includes shipping, tax, and any other adjustment. | -| `cart.items` | `array` | Yes | | The list of items in the shopping cart. | -| `cart.items[*].product` | `object` | Yes | | The product details. | -| `cart.items[*].product.productId` | `string` | Yes | Between 1 and 50 characters long | The ID that uniquely identifies the product on your store. | -| `cart.items[*].product.name` | `string` | Yes | Between 1 and 200 characters long | The name of the product. | -| `cart.items[*].product.displayPrice` | `number` | Yes | Non-negative | The price of the product displayed in the store. | -| `cart.items[*].index` | `number` | Yes | Non-negative | The index, starting from zero, which represents the order in which the item was added to the shopping cart. | -| `cart.items[*].quantity` | `number` | Yes | Positive | The number of units of the item. | -| `cart.items[*].total` | `number` | Yes | Non-negative | The total for the item. It includes discounts and any other adjustment. | -| `cart.items[*].product.sku` | `string` | No | Between 1 and 50 characters long | The code that uniquely identifies the product variant on your store. | -| `cart.items[*].product.category` | `string` | No | Between 1 and 100 characters long | The category of the product. | -| `cart.items[*].product.brand` | `string` | No | Between 1 and 100 characters long | The brand associated with the product. | -| `cart.items[*].product.variant` | `string` | No | Between 1 and 50 characters long | The variant of the product, such as size, color and style. | -| `cart.items[*].product.originalPrice` | `number` | No | Non-negative | The original price of the product. | -| `cart.items[*].product.url` | `string` | No | Well-formed URL | The URL of the product page. | -| `cart.items[*].product.imageUrl` | `string` | No | Well-formed URL | The URL of the main product image. | -| `cart.items[*].discount` | `number` | No | Non-negative | The amount of the discount applied to the item. | -| `cart.items[*].coupon` | `number` | No | Between 1 and 50 characters long | The coupon applied to the item. | -| `orderId` | `string` | No | | The ID that uniquely identifies the order on your store. | -| `cart.subtotal` | `number` | No | Non-negative | The total of all items and quantities in the shopping cart including applied item promotions. Applied cart discounts, estimated shipping, and applied shipping discounts should be excluded from the subtotal amount. | -| `cart.shippingPrice` | `number` | No | Non-negative | The total shipping price for the items in the shopping cart, including any handling charges. | -| `cart.taxes` | `object` | No | Non-empty string keys and values | The taxes associated with the transaction. | -| `cart.costs` | `object` | No | Non-empty string keys and values | The costs associated with the transaction, such as manufacturing costs, shipping expenses not borne by the customer, or any other costs. | -| `cart.discount` | `number` | No | Non-negative | The amount of the discount applied to the shopping cart. | -| `cart.coupon` | `string` | No | Between 1 and 50 characters long | The coupon applied to the shopping cart. | -| `cart.lastUpdateTime` | `number` | No | Non-negative | The timestamp when the shopping cart was last updated, in milliseconds since epoch. | - -**Note:** - -- The `sku` and `productId` do not have to be different. Usually, the `productId` is the internal identifier, - like `12345`, and the SKU is a public-facing identifier like `SM-124-GREEN`. -- The `displayPrice` is the price the user pays, while the `originalPrice` is usually the regular retail price. -- It may seem unusual to specify the order ID at the start of the checkout process, but some e-commerce platforms - generate the order ID at the start or even before the process begins. - -#### Code Sample - -Here are some examples of how to track this event: - -
- Minimal Example - -```ts -croct.track('checkoutStarted', { - cart: { - currency: 'USD', - total: 776.49, - items: [ - { - index: 0, - total: 699.00, - quantity: 1, - product: { - productId: '12345', - name: 'Smartphone 9', - displayPrice: 699.00 - } - } - ] - } -}); -``` - -
- -
- Complete Example - -```ts -croct.track('checkoutStarted', { - orderId: '123', - cart: { - currency: 'USD', - items: [ - { - index: 0, - quantity: 1, - total: 699.00, - discount: 100.00, - coupon: 'PROMO', - product: { - productId: '12345', - sku: 'SM-124-GREEN', - name: 'Smartphone 9', - category: 'Smartphone', - brand: 'Acme', - variant: '64GB Green', - displayPrice: 699.00, - originalPrice: 799.00, - url: 'https://www.acme.com/product/smartphone9', - imageUrl: 'https://www.acme.com/images/smartphone9-64gb-green.png' - } - }, - { - index: 1, - quantity: 1, - total: 39.00, - discount: 10.00, - coupon: 'PROMO', - product: { - productId: '98765', - sku: '03132db8-2c37-4aef-9827-60d0206683d9', - name: 'Silicone Case', - category: 'Cases', - brand: 'Acme', - variant: 'Black', - displayPrice: 39.00, - originalPrice: 49.00, - url: 'https://www.acme.com/product/silicone-case', - imageUrl: 'https://www.acme.com/images/silicone-case-black' - } - } - ], - taxes: { - state: 53.51, - local: 23.98 - }, - costs: { - manufacturing: 275.81, - cos: 85.37 - }, - subtotal: 848.00, - shippingPrice: 59.99, - discount: 169.99, - total: 815.49, - coupon: 'FREE-SHIPPING', - lastUpdateTime: 123456789 - } -}); -``` - -
- -### orderPlaced - -This event records a placed order. - -You should track this event when the user places an order. - -#### Properties - -This event supports the following properties: - -| Property | Type | Required | Constraints | Description | -|----------------------------------------|----------|----------|----------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| `order` | `object` | Yes | | The order details. | -| `order.orderId` | `string` | Yes | | The ID that uniquely identifies the order on your store. | -| `order.currency` | `string` | Yes | Between 1 and 10 characters long | The currency in which the monetary values are expressed in the order. We recommend using the 3-letter currency codes defined by the [ISO 4217](https://en.wikipedia.org/wiki/ISO_4217) standard. For currencies having no official recognition in [ISO 4217](https://en.wikipedia.org/wiki/ISO_4217), consider using ISO-like codes adopted locally or commercially, such as `XBT` for BitCoin. | -| `order.total` | `number` | Yes | Non-negative | The total revenue or grand total associated with the transaction. It includes shipping, tax, and any other adjustment. | -| `order.items` | `array` | Yes | | The list of items. | -| `order.items[*].product` | `object` | Yes | | The product details. | -| `order.items[*].product.productId` | `string` | Yes | Between 1 and 50 characters long | The ID that uniquely identifies the product on your store. | -| `order.items[*].product.name` | `string` | Yes | Between 1 and 200 characters long | The name of the product. | -| `order.items[*].product.displayPrice` | `number` | Yes | Non-negative | The price of the product displayed in the store. | -| `order.items[*].index` | `number` | Yes | Non-negative | The index, starting from zero, representing the order in which the item was added to the shopping cart. | -| `order.items[*].quantity` | `number` | Yes | Positive | The number of units of the item ordered. | -| `order.items[*].total` | `number` | Yes | Non-negative | The total for the item. It includes discounts and any other adjustment. | -| `order.items[*].product.sku` | `string` | No | Between 1 and 50 characters long | The code that uniquely identifies the product variant on your store. | -| `order.items[*].product.category` | `string` | No | Between 1 and 100 characters long | The category of the product. | -| `order.items[*].product.brand` | `string` | No | Between 1 and 100 characters long | The brand associated with the product. | -| `order.items[*].product.variant` | `string` | No | Between 1 and 50 characters long | The variant of the product, such as size, color and style. | -| `order.items[*].product.originalPrice` | `number` | No | Non-negative | The original price of the product. | -| `order.items[*].product.url` | `string` | No | Well-formed URL | The URL of the product page. | -| `order.items[*].product.imageUrl` | `string` | No | Well-formed URL | The URL of the main product image. | -| `order.items[*].discount` | `number` | No | Non-negative | The amount of the discount applied to the item. | -| `order.items[*].coupon` | `number` | No | Between 1 and 50 characters long | The coupon applied to the item. | -| `order.subtotal` | `number` | No | Non-negative | The total of all items and quantities in the order including applied item promotions. Applied order discounts, estimated shipping, and applied shipping discounts should be excluded from the subtotal amount. | -| `order.shippingPrice` | `number` | No | Non-negative | The total shipping price for the items in the order, including any handling charges. | -| `order.taxes` | `object` | No | Non-empty string keys and values | The taxes associated with the transaction. | -| `order.costs` | `object` | No | Non-empty string keys and values | The costs associated with the transaction, such as manufacturing costs, shipping expenses not borne by the customer, or any other costs. | -| `order.discount` | `number` | No | Non-negative | The amount of the discount applied to the order. | -| `order.coupon` | `string` | No | Between 1 and 50 characters long | The coupon applied to the order. | -| `order.paymentMethod` | `string` | No | Between 1 and 50 characters long | The payment method used in the payment. | -| `order.installments` | `number` | No | Non-negative | The number of installments of the transaction. | -| `order.status` | `string` | No | Either `placed`, `paid` or `completed` | The current status of the order. | - -**Note:** - -- The `sku` and `productId` do not have to be different. Usually, the `productId` is the internal identifier, - like `12345`, and the SKU is a public-facing identifier like `SM-124-GREEN`. -- The `displayPrice` is the price the user pays, while the `originalPrice` is usually the regular retail price. -- The `paymentMethod` property accepts arbitrary values, such as `credit-card`, `credit-balance`, `visa`, `paypal` - or `bitcoin`. - -#### Code Sample - -Here are some examples of how to track this event: - -
- Minimal Example - -```ts -croct.track('orderPlaced', { - order: { - orderId: '123', - currency: 'USD', - total: 776.49, - items: [ - { - index: 0, - total: 699.00, - quantity: 1, - product: { - productId: '12345', - name: 'Smartphone 9', - displayPrice: 699.00 - } - } - ] - } -}); -``` - -
- -
- Complete Example - -```ts -croct.track('orderPlaced', { - order: { - orderId: '123', - currency: 'USD', - items: [ - { - index: 0, - quantity: 1, - total: 699.00, - discount: 100.00, - coupon: 'PROMO', - product: { - productId: '12345', - sku: 'a9b2745f-9d0b-4bfe-8ebd-7376dd932169', - name: 'Smartphone 9', - category: 'Smartphone', - brand: 'Acme', - variant: '64GB Green', - displayPrice: 699.00, - originalPrice: 799.00, - url: 'https://www.acme.com/product/smartphone9', - imageUrl: 'https://www.acme.com/images/smartphone9-64gb-green' - } - }, - { - index: 1, - quantity: 1, - total: 39.00, - discount: 10.00, - coupon: 'PROMO', - product: { - productId: '98765', - sku: 'CS-987-BLACK', - name: 'Silicone Case', - category: 'Cases', - brand: 'Acme', - variant: 'Black', - displayPrice: 39.00, - originalPrice: 49.00, - url: 'https://www.acme.com/product/silicone-case', - imageUrl: 'https://www.acme.com/images/silicone-case-black.png' - } - } - ], - taxes: { - state: 53.51, - local: 23.98 - }, - costs: { - manufacturing: 275.81, - cos: 85.37 - }, - subtotal: 848.00, - shippingPrice: 59.99, - discount: 169.99, - total: 815.49, - coupon: 'FREE-SHIPPING', - paymentMethod: 'credit-card', - installments: 1, - status: 'paid' - } -}); -``` - -
- -## Analytics Events - -The analytics category has the following events: - -### goalCompleted - -This event records a completed activity, called a conversion. - -You should track this event when a user completes a desired goal, such as filling out a form or downloading a resource. - -#### Properties - -This event supports the following properties: - -| Property | Type | Required | Constraints | Description | -|------------|----------|----------|------------------------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| `goalId` | `string` | Yes | Between 3 and 100 characters long, containing only letters, digits, and separators (`-`,`_`, `:`), starting and ending with letters or digits. | The ID of the goal. | -| `currency` | `string` | No | Between 1 and 10 characters long | The currency in which the monetary value is expressed. We recommend using the 3-letter currency codes defined by the [ISO 4217](https://en.wikipedia.org/wiki/ISO_4217) standard. For currencies having no official recognition in [ISO 4217](https://en.wikipedia.org/wiki/ISO_4217), consider using ISO-like codes adopted locally or commercially, such as `XBT` for BitCoin. | -| `value` | `number` | No | Non-negative | The monetary value associated with the completion of the goal. This can represent an estimated value or a symbolic value. For example, if the sales team can close 10% of people who sign up for a newsletter, and the average transaction is $500, then a possible value for newsletter sign-ups can be $50 (i.e., 10% of $500). | - -#### Code Sample - -Here are some examples of how to track this event: - -
- Minimal Example - -```ts -croct.track('goalCompleted', { - goalId: 'newsletter-sign-up', -}); -``` - -
- -
- Complete Example - -```ts -croct.track('goalCompleted', { - goalId: 'newsletter-sign-up', - currency: 'USD', - value: 9.99 -}); -``` - -
- -## Miscellaneous Events - -The miscellaneous category has the following events: - -### interestShown - -This event records that a user has shown interest in something. - -You should track this event when a user sees some content or perform some action that represents interest. - -#### Properties - -This event supports the following properties: - -| Property | Type | Required | Constraints | Description | -|-------------|---------|----------|---------------------------------------------------|-------------------------------------| -| `interests` | `array` | Yes | Up to 10 strings between 1 and 50 characters long | The list of demonstrated interests. | - -#### Code Sample - -Here is an example of how to track this event: - -
- Example - -```ts -croct.track('interestShown', { - interests: ['music', 'movies'], -}); -``` - -
- -### postViewed - -This event records that a user has viewed a post. - -You should track this event when a user sees some post. - -#### Properties - -This event supports the following properties: - -| Property | Type | Required | Constraints | Description | -|--------------------|----------|----------|---------------------------------------------------|-----------------------------------------------------------------------| -| `post` | `object` | Yes | | The post details. | -| `post.postId` | `string` | Yes | Between 1 and 100 characters long | The ID that uniquely identifies the post across the website. | -| `post.title` | `string` | Yes | Between 1 and 100 characters long | The title of the post. | -| `post.publishTime` | `number` | Yes | Non-negative | The timestamp of the post publication, in milliseconds since epoch. | -| `post.url` | `string` | No | Well-formed URL | The URL of the post page. | -| `post.tags` | `array` | No | Up to 10 strings between 1 and 50 characters long | The set of post tags. | -| `post.categories` | `array` | No | Up to 10 strings between 1 and 50 characters long | The categories the post belongs to. | -| `post.authors` | `array` | No | Up to 10 strings between 1 and 50 characters long | The authors of the post. | -| `post.updateTime` | `number` | No | Non-negative | The timestamp of the post's last update, in milliseconds since epoch. | - -#### Code Sample - -Here are a few examples of how to track this event: - -
- Minimal Example - -```ts -croct.track('postViewed', { - post: { - postId: 'announcing-our-seed-round', - title: 'Announcing our $1.3M seed round', - publishTime: 123456789, - } -}); -``` - -
- -
- Complete Example - -```ts -croct.track('postViewed', { - post: { - postId: 'announcing-our-seed-round', - url: 'https://croct.com/blog/announcing-our-seed-round', - title: 'Announcing our $1.3M seed round', - tags: ['seed-round'], - categories: ['croct-news'], - authors: ['John Doe'], - publishTime: 123456789, - updateTime: 123456790, - } -}); -``` - -
- -### sessionAttributesChanged - -This event records that session attributes have changed. - -The SDK automatically tracks this event when you call [`save`](patch.md#save) on the patch returned by the -[`session.edit()`](session.md#edit) method. - -### nothingChanged - -This event records that the user has been inactive for a while. - -The SDK automatically tracks this event after a period of inactivity. The event's frequency decreases as the -idle period increases until reaching a maximum of four events per hour. - -### eventOccurred - -This event records the occurrence of a domain-specific event. - -You must track this event whenever you want to record that something happened for later analysis. - -#### Properties - -This event supports the following properties: - -| Property | Type | Required | Constraints | Description | -|---------------------|----------|-----------|----------------------------------|--------------------------------------------------------------------------------------| -| `name` | `string` | Yes | Between 1 and 50 characters long | The name of the event. | -| `personalizationId` | `string` | No | Between 1 and 50 characters long | The name of the audience associated with the event. | -| `audience` | `string` | No | Between 1 and 50 characters long | The audience associated with the event. For example, "loyal-shoppers" or "mothers". | -| `testId` | `string` | No | Between 1 and 50 characters long | The ID of the test associated with the event. | -| `groupId` | `string` | No | Between 1 and 50 characters long | The ID of the test group associated with the event. | -| `details` | `object` | No | Map of primitives | The details about the event. | - -The following additional restrictions apply to the `details` property: - -- It allows up to 10 attributes -- Attribute names should be strings up to 300 characters long, starting with a letter or underscore and - optionally followed by more letters, digits or underscores -- Attribute values can be strings up to 300 characters long, numbers, booleans, and null. - -#### Code Sample - -Here are a few examples of how to track this event: - -
- Minimal Example - -```ts -croct.track('eventOccurred', { - name: 'userLiked', -}); -``` - -
- -
- Complete Example - -```ts -croct.track('eventOccurred', { - "name": "personalizationApplied", - "personalizationId": "banner-home", - "audience": "loyal-users", - "testId": "test-banner-home", - "groupId": "A", -}); -``` - -
- -### linkOpened - -This event records that the user opened a link. - -You should track this event when a user opens in a link. - -#### Properties - -This event supports the following properties: - -| Property | Type | Required | Constraints | Description | -|----------|----------|----------|-------------|-------------------------------| -| `link` | `string` | Yes | A valid URI | The link that the user opened | - -#### Code Sample - -Here is an example of how to track this event: - -
- Example - -```ts -croct.track('linkOpened', { - link: 'https://croct.com/', -}); -``` - -
diff --git a/docs/patch.md b/docs/patch.md deleted file mode 100644 index ba0c28b6..00000000 --- a/docs/patch.md +++ /dev/null @@ -1,351 +0,0 @@ -# Patch - -Patches allow you to modify a particular entity, such as user profiles or session attributes, without knowing -its current state. - -Most operations require specifying the path to the target attribute. The path format is similar to the way you are -already used to access nested structures in JavaScript. - -For objects and maps, you should use the `object.property` notation: - -```ts -patch.set('custom.pet', 'crocodile'); -``` - -For lists, you should use the `list[index]` notation: - -```ts -patch.set('custom.pets[0]', 'crocodile'); -``` - -Notice that the processing performed by a patch is atomic to prevent entities from ending up in an inconsistent state. -So either all operations are applied, or none of them are. - -## API Reference - -This reference documents all methods available in the Patch API and explains in detail how these methods work. - -### Index - -- [set](#set) -- [add](#add) -- [combine](#combine) -- [merge](#merge) -- [increment](#increment) -- [decrement](#decrement) -- [remove](#remove) -- [clear](#clear) -- [unset](#unset) -- [save](#save) - -### set - -This method sets a value at a given path. - -This operation will overwrite the value in the specified path. Note that this operation will fail if the -parent path does not exist or is not a list or map. For example, given the path `foo.bar`, if the value at `foo` -does not exist or is not a map, the operation will fail. - -#### Signature - -The `set` method has the following signature: - -```ts -patch.set(path: string, value: JsonValue): Patch -``` - -The return is the `Patch` instance itself to allow operation chaining. - -#### Code Sample - -Here's a minimal example showing how to set a value: - -```ts -patch.set('custom.pet', 'crocodile'); -``` - -### add - -This method adds a value to a collection. - -The following table shows how the operation behaves in different scenarios: - -| Current Value | Given Value | Result | -|---------------|-------------|-------------------| -| `null` | `'a'` | `['a']` | -| `'a'` | `null` | `['a']` | -| `'a'` | `'b'` | `['a', 'b']` | -| `['a']` | `null` | `['a']` | -| `[]` | `'a'` | `['a']` | -| `['a', 'b']` | `'a'` | `['a', 'b', 'a']` | - -#### Signature - -The `add` method has the following signature: - -```ts -patch.add(path: string, element: JsonValue): this -``` - -The return is the `Patch` instance itself to allow operation chaining. - -#### Code Sample - -Here's a minimal example showing how to add a value to a collection: - -```ts -patch.add('custom.pets', 'crocodile'); -``` - -### combine - -This method combines two set of values. - -The following table shows how the operation behaves in different scenarios: - -| Current Value | Given Value | Result | -|---------------|---------------|--------------| -| `[]` | `[]` | `[]` | -| `[]` | `['a', 'a']` | `['a']` | -| `['a']` | `null` | `['a']` | -| `['a']` | `'b'` | `['a', 'b']` | -| `['a']` | `['b', null]` | `['a', 'b']` | -| `[null]` | `['a']` | `['a']` | -| `null` | `null` | `[]` | -| `null` | `['a']` | `['a']` | -| `null` | `'a'` | `['a']` | -| `'a'` | `'b'` | `['a', 'b']` | -| `'a'` | `['b']` | `['a', 'b']` | -| `'a'` | `['a']` | `['a']` | - -#### Signature - -The `combine` method has the following signature: - -```ts -patch.combine(path: string, value: JsonValue): this -``` - -The return is the `Patch` instance itself to allow operation chaining. - -#### Code Sample - -Here's a minimal example showing how to combine sets: - -```ts -patch.combine('custom.pets', ['crocodile', 'iguana']); -``` - -### merge - -This method merges two maps or lists. - -The following table shows how the operation behaves in different scenarios: - -| Current Value | Given Value | Result | -|---------------|--------------|------------------------| -| `{}` | `{}` | `{}` | -| `{}` | `{a: 1}` | `{a: 1}` | -| `{a: 1}` | `{b: 2}` | `{a: 1, b: 2}` | -| `{a: 1}` | `{a: 2}` | `{a: 2}` | -| `null` | `{a: 1}` | `{a: 1}` | -| `null` | `[1]` | `[1]` | -| `1` | `[2]` | `[1, 2]` | -| `[]` | `[1]` | `[1]` | -| `[1]` | `[2]` | `[1, 2]` | -| `['a', 'b']` | `['b', 'c']` | `['a', 'b', 'b', 'c']` | - -#### Signature - -The `merge` method has the following signature: - -```ts -patch.merge(path: string, value: JsonArray | JsonMap): this -``` - -The return is the `Patch` instance itself to allow operation chaining. - -#### Code Sample - -Here's a minimal example showing how to merge maps: - -```ts -patch.merge('preferences', {color: 'green'}); -``` - -### increment - -This method increments a value by a given amount. - -The following table shows how the operation behaves in different scenarios: - -| Current Value | Amount | Result | -|---------------|--------|--------| -| `null` | 10 | 10 | -| `0` | 10 | 10 | -| `-1` | 10 | 9 | - -#### Signature - -The `increment` method has the following signature: - -```ts -patch.increment(path: string, value: number = 1): this -``` - -The return is the `Patch` instance itself to allow operation chaining. - -#### Code Sample - -Here's a minimal example showing how to increment a value: - -```ts -patch.increment('custom.score', 10); -``` - -### decrement - -This method decrements a value by a given amount. - -The following table shows how the operation behaves in different scenarios: - -| Current Value | Amount | Result | -|---------------|--------|--------| -| `null` | 10 | -10 | -| `0` | 10 | -10 | -| `1` | 10 | -9 | - -#### Signature - -The `decrement` method has the following signature: - -```ts -patch.decrement(path: string, value: number = 1): this -``` - -The return is the `Patch` instance itself to allow operation chaining. - -#### Code Sample - -Here's a minimal example showing how to decrement a value: - -```ts -patch.decrement('custom.score', 10); -``` - -### remove - -This method removes values from a collection. - -The following table shows how the operation behaves in different scenarios: - -| Current Value | Given Value | Result | -|------------------------|-------------|-------------------| -| `['a', 'b', 'c']` | `'a'` | `['b', 'c']` | -| `['a', 'b', 'c', 'c']` | `'c'` | `['a', 'b']` | -| `['a', 'b', 'c']` | `'d'` | `['a', 'b', 'c']` | -| `['a', {b: 1}, 'c']` | `{b: 1}` | `['a', 'c']` | - -#### Signature - -The `remove` method has the following signature: - -```ts -patch.remove(path: string, value: JsonValue): this -``` - -The return is the `Patch` instance itself to allow operation chaining. - -#### Code Sample - -Here's a minimal example showing how to remove a value from a collection: - -```ts -patch.remove('custom.pets', 'crocodile'); -``` - -### clear - -This method clears the value at given path. - -The following table shows how the operation behaves in different scenarios: - -| Current Value | Result | -|---------------|--------| -| `null` | `null` | -| `[]` | `[]` | -| `['a']` | `[]` | -| `'foo'` | `null` | - -Note that the operation will not fail if the path does not exist. - -#### Signature - -The `clear` method has the following signature: - -```ts -patch.clear(path: string): this -``` - -The return is the `Patch` instance itself to allow operation chaining. - -#### Code Sample - -Here's a minimal example showing how to clear a given path: - -```ts -patch.clear('custom.pets'); -``` - -### unset - -This method deletes a given path. - -The difference between `unset` and `clear` is that `unset` deletes the path, -while `clear` removes the value by setting it to null or removing all its elements. - -Note that the operation will not fail if the path does not exist. - -#### Signature - -The `unset` method has the following signature: - -```ts -patch.unset(path: string): this -``` - -The return is the `Patch` instance itself to allow operation chaining. - -#### Code Sample - -Here's a minimal example showing how to unset a value: - -```ts -patch.unset('custom.pets'); -``` - -### save - -This method builds the patch and emits an event to record the specified changes. - -Notice that the processing performed by a patch is atomic to prevent entities from ending up in an inconsistent state. -So either all operations are applied, or none of them are. - -#### Signature - -The `save` method has the following signature: - -```ts -patch.save(): Promise -``` - -The return is a [Promise](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise) that -resolves to the tracked event after successful transmission. - -#### Code Sample - -Here's a minimal example showing how save the specified changes: - -```ts -patch.save(); -``` diff --git a/docs/plug.md b/docs/plug.md deleted file mode 100644 index b126b8d9..00000000 --- a/docs/plug.md +++ /dev/null @@ -1,421 +0,0 @@ -# Plug API Reference - -This reference documents all methods and properties available in the Plug API and explains in detail how they work. - -# Index - -- [plug](#plug) -- [unplug](#unplug) -- [identify](#identify) -- [anonymize](#anonymize) -- [setToken](#settoken) -- [unsetToken](#unsettoken) -- [getUserId](#getuserid) -- [isAnonymous](#isanonymous) -- [evaluate](#evaluate) -- [fetch](#fetch) -- [track](#track) -- [user](#user) -- [session](#session) - -## plug - -This method initializes the SDK according to the provided options. - -You should initialize the SDK only once in the application, usually on the application startup. -Subsequent calls to this method will fail without reporting errors. - -To reconfigure the plug, you can call the [`unplug`](#unplug) method to reset the SDK to its initial state -before initializing it with the new configuration. - -### Signature - -The `plug` method has the following signature: - -```ts -croct.plug(configuration?: Configuration): void -``` - -These are the currently supported options: - -| Option | Type | Required | Default Value | Description | -|---------------------------|-------------------|----------|---------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| `appId` | string | Depends | None | The ID of the application you set up on Croct. This option is required unless you have loaded the SDK using a HTML snippet that already specifies the application ID. | -| `debug` | boolean | No | `false` | If `true`, turns on debug mode, which logs helpful messages to the console. See [Testing](testing.md#debug-mode) for more details. | -| `test` | boolean | No | `false` | If `true`, enables the test mode. See [Testing](testing.md#test-mode) for more details. | -| `track` | boolean | No | `true` | If `true`, enables the automatic event tracking on initialization. | -| `clientId` | string | No | None | The ID of the client using the application. | -| `token` | string\|null | No | None | The JWT token issued by Croct. If `null`, clears any token specified on previous calls. | -| `userId` | string | No | None | The ID of the user logged into the application. Internally, the SDK will issue a token using the specified ID as the subject claim of the token. The `token` and `userId` options are mutually exclusive. | -| `tokenScope` | string | No | `global` | Defines how the SDK should synchronize the token across multiple tabs, see [token scopes](#token-scopes) for more details. | -| `eventMetadata` | JSON | No | None | Any additional information that may be useful to include as part of the event metadata. A common use case is to record the version of the application for future reference. | -| `logger` | object | No | None | A custom logger to handle log messages. By default, all logs are suppressed. | -| `urlSanitizer` | function | No | None | A function to sanitize URLs that allows removing sensitive information from URLs, such as tokens, that should not be sent to the platform. | -| `baseEndpointUrl` | string | No | None | The base URL to use for the API calls. By default, the SDK will use the production endpoint. | -| `cidAssignerEndpointUrl` | string | No | None | The URL to use for the client ID assignment. By default, the SDK will use the production endpoint. | - - -### Token scopes - -The token scope determines how the SDK synchronize the token across multiple tabs to match your application's behaviour. - -> ℹ️️ **Note** -> Although the SDK supports multiple identified users in different tabs, such separation does not apply -> to anonymous users. For the SDK, there is only one anonymous user per browser, regardless of the scope. - -#### Global scope - -An application is said to have a global user scope if it supports only one user at a time, in contrast to applications -that allow you to switch between multiple accounts in the same session. - -In practice, as all tabs share the same scope, it means that if you identify or anonymize a user on one tab, -it will reflect on all other tabs. - - -#### Isolated scope - -The isolated scope inhibits the synchronization of tokens between tabs. You should use an isolated scope if your -application does not keep users signed in across multiple tabs. - -#### Contextual - -The contextual scope is similar to the isolated except that new tabs keep the user identification from -the last viewed tab. - -You should consider using this scope if your application allows users to access multiple accounts simultaneously -in different tabs. This behavior resembles how Gmail works: if you are logged in with an account and open a link, -the user remains the same as the origin page. - -### Code Sample - -Here's a minimal example showing how to initialize the SDK: - -```ts -croct.plug({appId: '00000000-0000-0000-0000-000000000000'}); -``` - -## unplug - -This method releases managed resources and resets the SDK to its initial state. - -Calling this method on an uninitialized SDK instance will not have any effect. - -### Signature - -The `unplug` method has the following signature: - -```ts -croct.unplug(): Promise -``` - -The return is a [Promise](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise) to -wait until all resources are released. - -## identify - -This method identifiers the user through a unique identifier. - -The SDK will automatically emit `userSignedOut` and `userSignedIn` events when the user identity changes. Also, -changing the user in the course of a session will cause the current session to end and a new one to start. - -Calling this method will issue a new token regardless of whether the specified ID is the same as the current one. - -### Signature - -The `identify` method has the following signature: - -```ts -croct.identify(userId: string): void -``` - -## anonymize - -This method clears the ID of the currently identified user. - -The SDK will automatically emit a `userSignedOut` event. Also, changing the user in the course of a session -will cause the current session to end and a new one to start. - -Calling this method will not produce any effect or errors when the user is already anonymous. - -### Signature - -This `anonymize` method has the following signature: - -```ts -croct.anonymize(): void -``` - -## setToken - -This method replaces any existing token with a new one. - -The token must be a valid JWT token issued by the Croct authentication service. - -Passing `null` as the token will have the same effect as calling the [`unsetToken`](#unsettoken) method. - -### Signature - -This `setToken` method has the following signature: - -```ts -croct.setToken(token: string | null): void -``` - -## unsetToken - -This method clears any existing token. - -The SDK will automatically emit a `userSignedOut` event. Also, changing the user in the course of a session -will cause the current session to end and a new one to start. - -Calling this method will not produce any effect or errors when no token exists. - -### Signature - -The `unsetToken` method has the following signature: - -```ts -croct.unsetToken(): void -``` - -## getUserId - -This method gets the ID of the currently identified user. - -If you just want to check whether the user is anonymous, consider using the [`isAnonymous`](#isanonymous) method instead. - -### Signature - -The `getUserId` method has the following signature: - -```ts -croct.getUserId(): string | null -``` - -This method returns the ID that identifies the user or `null` if the user is anonymous - -## isAnonymous - -This method checks whether the current user is anonymous. - -### Signature - -The `isAnonymous` method has the following signature: - -```ts -croct.isAnonymous(): boolean -``` - -This method returns `true` if the user is anonymous, `false` otherwise. - -## evaluate - -This method evaluates a query written in CQL. - -Check out our [quick start guide](quick-start.md) for an introduction to what is CQL and how it works. - -> ℹ️️ **Note** -> We currently impose a hard limit of 500 characters on the length of query. -> We plan to remove this limitation in the near future. - -### Signature - -The `evaluation` method has the following signature: - -```ts -croct.evaluate(query: string, options?: EvaluationOptions): Promise -``` - -These are the currently supported options: - -| Option | Type | Description | -|--------------|--------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| `timeout` | number | The maximum evaluation time in milliseconds. Once reached, the evaluator will abort the evaluation and reject the promise with a timeout error. | -| `attributes` | JSON | The map of attributes to inject in the evaluation context. For example, passing the attributes `{cities: ['New York', 'San Francisco']}` will allow you to reference them in queries like `context's cities include location's city`. | - -The return is a [Promise](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise) that -resolves to the evaluation result. - -### Code Sample - -Here's a minimal example showing how evaluate a query: - -```ts -croct.evaluate('session is starting').then(console.log); -``` - -## fetch - -This method fetches the content for a slot. - -### Signature - -The `fetch` method has the following signature: - -```ts -croct.fetch(id: string, options?: FetchOptions): Promise<{content: JsonObject}> -``` - -You can specify the version of the slot by passing a versioned ID in the form `id@version`. For example, -passing `home-banner@1` will fetch the content for the `home-banner` slot in version 1. Not specifying a -version number is the same as passing `home-banner@latest`, which will load the latest version of the slot. - -> βœ… **Best practice** -> It's strongly recommended to specify a slot version for production deployments. -> That way, you ensure the front end will always receive content with the expected -> schema while your team can freely evolve the content's schema in parallel. - -These are the currently supported options: - -| Option | Type | Description | -|-------------------|--------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| `preferredLocale` | string | The preferred locale for the content. If not specified, the default locale will be used. | -| `attributes` | JSON | The map of attributes to inject in the evaluation context. For example, passing the attributes `{cities: ['New York', 'San Francisco']}` will allow you to reference them in queries like `context's cities include location's city`. | -| `timeout` | number | The maximum evaluation time in milliseconds. Once reached, the plug will abort the fetch and reject the promise with a timeout error. | - -A slot represents a personalizable element of the interface. Each slot has a predefined structure whose content may vary -according to a personalization strategy. - -The return is a [Promise](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise) that -resolves to the slot content in the format as follows: - -```ts -{ - content: {[key: string]: JsonValue}, -} -``` - -It is common for your slot structure to change over time. To provide a smooth workflow and ensure your application -won't break during new releases, we've introduced the concept of slot versioning. - -Our versioning system automatically increments the slot version number whenever you make a backward-incompatible change. -For example, if you add a new field to the slot structure, the version number increases by one. When your application -requests content, we take the requested slot version and return the latest available compatible content. - -To take advantage of this feature, make sure to specify the slot version when requesting content: - -```ts -croct.fetch('my-slot', {version: '1'}); -``` - -### Code Sample - -The following example assumes that a slot with ID `home-banner` and the following schema exists: - -```ts -type HomeBanner = { - title: string, - subtitle: string, - image: string, - cta: { - text: string, - href: string, - } -} -``` - -Here's a minimal example showing how to fetch the content for the slot `home-banner`: - -```ts -croct.fetch('home-banner').then(console.log); -``` - -In this example, you should see the following output: - -```json -{ - "content": { - "title": "Unlock the Power of Personalization", - "subtitle": "Dive into the world of one-to-one engagement.", - "image": "https://croct.com/signup.png", - "cta": { - "text": "Try Croct now", - "href": "/signup" - } - } -} -``` - -#### πŸ’‘ ProTip - -You can specify the type of slot content in the method call to strongly type the promise's result: - -```ts -croct.fetch('home-hero').then(console.log); -``` - -You can also declare the type of all available slots in a declaration file using module augmentation for an even more -robust solution: - -```ts -// slots.d.ts -declare module '@croct/plug/slot' { - interface SlotMap { - 'home-banner': HomeBanner; - } -} - -export {}; -``` - -If you use an IDE with Typescript code completion support, you will get autocomplete suggestions for -slot IDs and content properties as a bonus: - -![Autocomplete](https://user-images.githubusercontent.com/943036/110214204-54e3de00-7e82-11eb-82d1-f25264c3865b.gif) - -## track - -This method records actions your users perform on your application. - -For a list of available events, see the [event reference](events.md). - -### Signature - -The `track` method has the following signature: - -```ts -croct.track(event: string, payload: EventPayload): Promise -``` - -The return is a [Promise](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise) that -resolves to the tracked event after successful transmission. - -### Code Sample - -Here's a minimal example showing how track an event: - -```ts -croct.track('goalCompleted', {goalId: 'newsletter-sign-up'}); -``` - -## user - -This property holds a reference to the user facade. - -Please refer to the [User API reference](user.md) for more details. - -### Code Sample - -Here's a minimal example showing how to edit a user profile: - -```ts -croct.user.edit() - .add('interests', 'JavaScript') - .save() -``` - -## session - -This property holds a reference to the session facade. - -Please refer to the [Session API reference](session.md) for more details. - -### Code Sample - -Here's a minimal example showing how to edit a user profile: - -```ts -croct.session.edit() - .set('plan', 'starter') - .save() -``` diff --git a/docs/quick-start.md b/docs/quick-start.md deleted file mode 100644 index a9bbcc30..00000000 --- a/docs/quick-start.md +++ /dev/null @@ -1,450 +0,0 @@ -# Quick Start Guide - -Welcome to the beginner's guide to Croct SDK for JavaScript. - -This guide aims to introduce the SDK's main features and explain how you can use the -[playground](https://play.croct.com) to assist you in developing new personalization features. - -Although some JavaScript knowledge will make following along easier, this guide is well suited even for non-developers. - -Let's start! - -## Table of Contents - -- [Introduction](#introduction) -- [Setting up](#setting-up) -- [Evaluating Expressions](#evaluating-expressions) - * [Evaluating Expressions on the Playground](#evaluating-expressions-on-the-playground) - * [Evaluating Expressions Programmatically](#evaluating-expressions-programmatically) -- [Collecting Information](#collecting-information) - * [Enriching Profiles](#enriching-profiles) - * [Enriching Sessions](#enriching-sessions) -- [Tracking Events](#tracking-events) -- [Identifying Users](#identifying-users) -- [Next steps](#next-steps) - -## Introduction - -You may have already experienced a situation where someone from the marketing or product team wanted to provide a -personalized experience for a particular audience, but that never got off the ground because it turned out to be -much more complicated than expected. - -That was the spark for creating the Contextual Query Language (CQL), an English-based language designed to abstract -away from marketing, product, and development teams the complexities behind delivering personalized experiences online. - -CQL makes it easy for everyone to write simple or sophisticated conditions in plain English in such a way that developers -can use it directly in the code without any additional step. - -``` -# CQL expressions are self-explanatory -user's age is greater than 18 -``` - -The example above shows a boolean expression, meaning that the result will be either `true` or `false` depending on -whether the user is older than 18 or not. - - -For developers, CQL serves as an abstraction layer between the application and the underlying personalization infrastructure: - -``` -user is returning and location's state is "California" -``` - -In the previous example, note that there are multiple ways for obtaining the visitor's location, such as the IP address -or GPS coordinates. Although GPS coordinates provide more accurate information than the IP address, it depends on the -user granting permission to the application to use the location service. - -That's where CQL shines. You define the business rules, and the personalization engine takes care of the tedious work -for you, such as managing permissions and selecting the best location source in the previous example. - -Plus, it opens up new horizons for connecting 3rd party data providers to your personalization data layer: - -``` -# Score synchronized with your CRM -user's score - -# Verified using your anti-fraud solution of choice -user is a fraud -``` - -Things get even more powerful when you realize that you can use the same context to run machine learning models in -real-time. You will soon be able to perform AI-powered evaluations like the following: - -``` -# This doesn't seem as complex as designing, training, and running ML models, does it? -user is churning -``` - -Because it is textual, you can use the same expression everywhere: straight in the code, playground, WordPress, -or any other platform integrated with Croct. - -In the next sections, we will explore how we can use CQL to craft personalized user journeys that inspire long-term, -value-driven customer relationships. - -## Setting Up - -> πŸ–οΈ **Just for your convenience** -> We will be using CodePen for all of the examples in this tutorial because it lets you play with them right in the browser. - -Follow the steps below to connect the playground with CodePen: - -1. [Open the playground](http://play.croct.com/) -2. Click on the _"Don't have an API Key?"_ link to proceed in sandbox mode -3. Enter the URL `https://codepen.io/pen` -4. Click on _"Let's play!"_ -5. Finally, click on the button labeled _"codepen.io/pen"_ at the top right of the page - -
- -

- Connecting -

- -After the page loads, you should notice an indication on the playground tab that you have an unseen notification. -Switching back to the playground tab, you should see a notification saying _"Connection established"_ that indicates -the playground is now connected to the CodePen editor. - -> πŸ’‘οΈοΈ **Hint** -> You will typically use an API key to connect to your development, staging, or production environments in real cases, -> but you can also use a local URL, such as `https://localhost/myapp`. - -Now, let's get our hands dirty and play around with CQL! - -## Evaluating Expressions - -The next sections show how you can evaluate CQL expressions using the playground or directly in the code. - -### Evaluating Expressions on the Playground - -To evaluate an expression on the playground, just type the expression in the editor and click the "Evaluate" button. - -Try evaluating the expression below: - -``` -today -``` - -At the bottom of the page, you will see the result of the expression, which in this case is the current date. - -Now, try evaluating the following expression: - -``` -today plus 1 day is equal to tomorrow -``` - -As expected, the result of the evaluation is `true`. Now, let's try a more interesting expression: - -``` -location's city -``` - -This time, the evaluation result should show your approximate location based on your IP address. - -You can also mix boolean expressions using conjunctions to form more sophisticated expressions: - -``` -user's interests include "rental" and location's city is "New York" -``` - -To see the list of expressions and variables available, click on the _"Cheat Sheet"_ link at the top of the page. - -### Evaluating Expressions Programmatically - -One of the coolest things about CQL is that you can programmatically evaluate expressions using the same expressions -written in plain English. - -Let's go back to the CodePen editor to evaluate our first expression programmatically. In our first example, -we are going to greet a visitor depending on whether it is the first time accessing your application or not. - -Simply copy the code below and paste into the HTML panel to see it in action: - -```html - -``` - -After CodePen updates the preview, you should see an alert saying _"Welcome!"_ or _"Welcome back!"_ depending on whether -it is your first time playing around with CQL on CodePen. - -> 🐞 **It's not a bug. It's a feature, we swear!** -> Sessions expire after 30 minutes of inactivity in the sandbox environment, and we erase all data every hour. -> So the _returning user_ expression will only evaluate to true in that half an hour window after the session expires. - -Note that you are not limited to boolean expressions only. For example, let's update the example again to show -how many sessions you have had: - -```html - -``` - -The [`croct.evaluate`](plug.md#evaluate) method returns a [Promise](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise) -that resolves to the evaluation result. The second argument, omitted for the sake of simplicity, allows passing -evaluation options, like variables and timeout. For all options, refer to the [Evaluation API reference](evaluator.md#evaluate). - -## Collecting Information - -So far, we haven't collected any information explicitly. Even so, it is already possible to answer several -interesting questions like: - -- Has this visitor been seen before? -`user is returning` -- What is the approximate location of the visitor? -`location's city` -- How long has it been since the session started? -`session's duration` -- Did the visitor come through a marketing campaign? -`campaign's name` - -These are just a few of the many questions you can ask based on anonymous information automatically collected by the SDK. - -> πŸ›‘οΈ **We embrace privacy by design** -> We do not automatically collect sensitive information that can identify the user, such as GPS coordinates or -> values entered in fields. We have [open-sourced the SDK](https://github.com/croct-tech/sdk-js) as an effort to bring -> more transparency about data collection. - -In addition to the information collected automatically, you can also enrich profiles and sessions with relevant -information to personalize your product or offer progressively, as we will see on the next sections. - -### Enriching Profiles - -Let's update our example and see how we can enrich user profiles to expand your personalization capabilities: - -```html - - - -``` - -Now, let's break this example down a little and understand what's going on. First, we introduce a button to call the -function `askBirthDate`. We then store the birth date answered in the variable `birthDate` and finally enrich the -visitor's profile with that information. - -> Note that you did not have to provide an ID to persist information about the anonymous user because the SDK took care -of that for you. - -We can now show the visitor's age based on the entered birth date: - -```html - - - - -``` - -Now, click on _"Ask my birth date"_, enter your birth date and then click on _"Show my age"_, and you should see -your age. - -### Enriching Sessions - -While working with personalization, it is common to collect session-specific information for evaluation or -analysis purposes. For such cases, the SDK provides a way to store data that remains available for evaluation only for -the session's duration. - -In the following example, we will implement a way to understand the user's doubts. We can then use this information to -display content that helps answer those questions along the journey. - -After updating the example on CodePen with the code below, you should see something that resembles an FAQ: - -```html -
- How much does Croct cost? -

Try Croct free for 14 days, no credit card required.

-
- -
- Do I need to be a developer to use Croct? -

No, you don't need to be a developer to use Croct.

-
- -
- - - - - - -``` - -Try clicking on the buttons and questions, and you will see that the answer will change according to the questions you -have expanded. We could use a similar approach to personalize elements of the application to clarify those questions. - -## Tracking Events - -Events are the fuel of personalization engines. It serves two primary purposes: recording facts for path analysis and -feeding the evaluation data layer. As already mentioned, the SDK automatically collects general-purpose events for you, -such as viewed pages and idle periods, to name a few. For non-generic events, it is up to you decide which events can -benefit your application. - -The following example demonstrates how the personalization engine uses events to enrich the evaluation context. -Back on CodePen, update the code with the next example: - -```html - - -

- - - - - -``` - -Once the example loads, follow the steps below to see how the tracking and evaluation mechanisms work together: - -1. Click on the button labeled _"Show offer"_. Since you have no items in your cart, you should see an alert saying _"No eligible offers"_. -2. Now add an item to the cart by clicking on _"β˜• Buy a coffee"_. -3. Click _"Show offers"_ again, and this time you should see a message that says _"How about adding a delicious cookie for $3 more?"_. Click _"Ok"_ to confirm. -4. Try clicking on _"Show offers"_ again. You should now see the message _"No eligible offers"_ as you have already upgraded to the combo. - -Besides standard events, you can track custom events for analytical purposes. The example below shows how you can -use custom events to track likes: - -```html - - - -``` - -You can also include additional information that may be useful for your analysis, such as which content the user liked in the previous example. -Check out the [documentation](events.md#eventoccurred) for more details. - -## Identifying Users - -So far, all the examples we have seen involve anonymous users only. However, for applications that allow users to -register for an account, the SDK provides a way to identify users using the same identifier as you use internally to -assemble cross-channel data into a unified customer view. - -The following example covers the steps to identify, retrieve identifiers, and anonymize users: - -```html - - - - - - - - -``` - -When identifying a user, the personalization engine automatically takes care of unifying sessions and profiles -in the background without a single extra line of code. - -> ⚠️ **Important** -> Never use guessable attributes as an identifier, such as email, phone, or incremental IDs. Instead, -> we strongly recommend using a cryptographically-secure UUIDs. - -## Next steps - -That's it! You have now the basics of how to use the Croct SDK. - -If you want to learn more about Croct SDK, check out the other sections in the [documentation](../README.md#documentation). -And if you faced any problems experimenting with the SDK, you can look for answers in the -[troubleshooting](troubleshooting.md) section or [ask the Croct community for help](../README.md#support). diff --git a/docs/session.md b/docs/session.md deleted file mode 100644 index 03a521db..00000000 --- a/docs/session.md +++ /dev/null @@ -1,52 +0,0 @@ -# Session API Reference - -This reference documents all methods available in the Session API and explains in detail how these methods work. - -## Index - -- [edit](#edit) - -## edit - -This method creates a patch to apply changes to the session attributes. - -The following restrictions apply to session attributes: - -- Each session allows up to 10 custom attributes -- Attribute names should be strings up to 20 characters long, starting with a letter or underscore and optionally -followed by letters, digits, or underscores -- Attributes can be primitives (strings, numbers, booleans, and null) or composites (lists and maps). -- Strings should be up to 100 characters long -- Lists can contain up to 30 elements, including primitives, lists of primitives, or maps of primitives -- Maps can contain up to 30 elements, including primitives, lists of primitives, or maps of primitives -- Map keys should be strings up to 50 characters long - -We recommend using descriptive names in camel case, like `plan`, `recommendPlan` and, `pickedPlan`. Following these -recommendations will make your attributes look like the standard ones, which results in queries with better readability. - -Notice that the attribute names are case-insensitive, meaning both `recommendPlan` and `recommendplan` refer to the same -attribute and could ultimately override each other. - -### Signature - -The `edit` method has the following signature: - -```ts -croct.session.edit(): Patch -``` - -The return is a patch for specifying the sequence of operations to apply to the session. -Calling save on the patch will return a [Promise](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise) -that resolves to the `sessionAttributesChanged` event after successful transmission. - -Refer to the [patch documentation](patch.md) for more details on how patching works. - -### Code Sample - -Here's a minimal example showing how to edit session attributes: - -```ts -croct.session.edit() - .set('plan', 'starter') - .save() -``` diff --git a/docs/testing.md b/docs/testing.md deleted file mode 100644 index f82279d6..00000000 --- a/docs/testing.md +++ /dev/null @@ -1,107 +0,0 @@ -# Testing - -For an enhanced developer experience, the SDK provides both debug and test modes to assist you with testing. - -## Debug mode - -The debug mode enables fine-grained logging to help developers detect and diagnose issues with the integration. -Each log receives a severity level, so you can filter only those messages you need. - -The severity levels and their respective meanings are: - -- 🧐 **Debug** - Fine-grained messages that provide context to understand the steps leading to errors and warnings. -- πŸ€“ **Info** - Informational messages that highlight the SDK's state and progress. -- πŸ€” **Warning** - Potential issues that might be problems or might not. -- 😱 **Error** - Abnormal or unexpected behaviors that need attention. - -### Enabling debug mode - -To enable the debug mode, you need to set `debug` to true when [initializing the SDK](plug.md#plug): - -```ts -croct.plug({debug: true}); -``` - -You can now check the console output at runtime for the debug logs. - -## Test mode - -The test mode enables the SDK to track events in test environments to ensure that the integration is working -as expected. It works by replacing the actual transport layer with a fake one to simulate successful calls. - -### Enabling test mode - -> ✨ If you use Jest or any other testing framework that sets the `NODE_ENV=test`, it should just work out of the box -> without any additional configuration. - -By default, the SDK automatically detects test environments based on the `NODE_ENV`. To explicitly enable or disable -the test mode, you can either: - -- Pass `test` as `true` when [initializing the SDK](plug.md#plug) -- Set the `CROCT_TEST_MODE` environment variable to `true` - -The order of precedence is as follows: - -1. If the `test` option is passed, that overrides any other environment settings -2. If the `CROCT_TEST_MODE` environment variable is set, that takes precedence over the automatic detection of -test environments -3. If neither `test` nor `CROCT_TEST_MODE` is set, the SDK detects the test environment automatically based on -the `NODE_ENV` - -### Testing events - -The SDK tracks an event for every operation executed on the server side. - -For example, executing the code below will trigger the [`userProfileChanged`](events.md#userprofilechanged) event with changes to the user profile: - -```ts -croct.user.edit() - .add('interest', 'tests') - .save() -``` - -This flexible design allows you to listen to events and test your integration without the tedious work of mocking the API, which is particularly cumbersome for chained or nested operations like in the previous example. - -A better solution consists of listening to the event with a test spy. Taking the previous code as an example, you can check if your integration is working as expected by listening to the target event: - -```ts -import {EventListener, EventInfo} from '@croct/plug/sdk/tracking'; - -test('should add an interest to the user profile', async () => { - await croct.plug({ - appId: '00000000-0000-0000-0000-000000000000', - }); - - const listener: EventListener = jest.fn(); - - croct.tracker.addListener(listener); - - await croct.user.edit() - .add('interest', 'tests') - .save(); - - expect(listener).toHaveBeenCalledWith( - expect.objectContaining>>({ - status: 'confirmed', - event: { - type: 'userProfileChanged', - patch: { - operations: [ - { - path: 'interest', - type: 'add', - value: 'tests', - }, - ], - }, - }, - }), - ); -}) -``` - -You can find more details about the available SDK events in the [Event reference](events.md). diff --git a/docs/tracker.md b/docs/tracker.md deleted file mode 100644 index e030906f..00000000 --- a/docs/tracker.md +++ /dev/null @@ -1,71 +0,0 @@ -# Tracker API Reference - -This reference documents all methods available in the Tracker API and explains in detail how these methods work. - -## track - -This method records actions your users perform on your application. - -For a list of available events, see the [event reference](events.md). - -### Signature - -The `track` method has the following signature: - -```ts -croct.tracker.track(event: string, payload: EventPayload): Promise -``` - -The return is a [Promise](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise) that -resolves to the tracked event after successful transmission. - -### Code Sample - -Here's a minimal example showing how track an event: - -```ts -croct.tracker.track('goalCompleted', {goalId: 'newsletter-sign-up'}); -``` - -## enable - -This method enables automatic event tracking. - -### Signature - -The `enable` method has the following signature: - -```ts -croct.tracker.enable(): void -``` - -### Code Sample - -Here's an example showing how to enable automatic event tracking: - -```ts -croct.tracker.enable(); -``` - -## disable - -This method disables automatic event tracking. - -> πŸ’‘οΈ **Hint** -> You can still track events by calling the [`track`](#track) method even with automatic event tracking disabled. - -### Signature - -The `disable` method has the following signature: - -```ts -croct.tracker.disable(): void -``` - -### Code Sample - -Here's an example showing how to disable automatic event tracking: - -```ts -croct.tracker.disable(); -``` diff --git a/docs/troubleshooting.md b/docs/troubleshooting.md deleted file mode 100644 index 1e5afdf0..00000000 --- a/docs/troubleshooting.md +++ /dev/null @@ -1,114 +0,0 @@ -# Troubleshooting - -Sometimes things go wrong. Here is a list of resolutions to some of the problems you may be experiencing. - -## Index - -- [I'm not able to connect my application to the playground](#im-not-able-to-connect-my-application-to-the-playground) -- [Some user attributes remain null even after applying a patch](#some-user-attributes-remain-null-after-applying-a-patch) -- [I installed a plugin, but it didn't work](#i-installed-a-plugin-but-it-didnt-work) -- [How to handle numeric user identifiers](#how-to-handle-numeric-user-identifiers) - -## I'm not able to connect my application to the playground - -These are the most common problems involving playground connectivity: - -### Application ID Mismatch - -Double-check if the API key you are using to access the playground applies to the application specified in the SDK initialization. - -If you are using a URL to access the playground, make sure you are initializing the SDK with sandbox application ID -`00000000-0000-0000-0000-000000000000`. - -### URL Redirection - -The playground uses a query-string parameter to initiate the connection to an application. Check if the -`__cplay` parameter is present in the URL of the application opened from the playground. If not, your server may be -redirecting the request, which prevents establishing a connection with your application. - -## Some user attributes remain null after applying a patch - -If you are applying a patch and the attributes are still null, you may be experiencing one of the following problems: - -### Invalid Patch - -If any operations included in your patch fail, the whole patch fails, and you'll not see the changes you are expecting. - -Check out the User API and Session API documentation to ensure your patch conforms with the respective attributes' constraints. - -### Personally Identified Information (PII) - -If you are trying to access personally identifiable information for an anonymous user, the result will be null until -the user gets identified. - -In an effort to protect users’ privacy, Croct does not allow you to access personally identifiable information about -anonymous users as there is no way for anonymous users to invoke their right to be forgotten. - -You can temporarily collect information to let the session unification process automatically migrate them to an -identified profile when the user signs up. If the user does not signs up, the personalization engine will anonymize -the profile after the session has expired. - -## I installed a plugin, but it didn’t work - -First, make sure you imported and enabled the plugin in the same file where you initialized the SDK – the import is -essential for the SDK to discover and load all the plugins you want to use. - -The following example shows how to enable the Google Analytics Plugin using the default settings: - -```ts -import croct from '@croct/plug'; - -// Install the plugin -import '@croct/plug-google-analytics'; -croct.plug({ - plugins: { - // Enable the plugin - googleAnalytics: true, - } -}); -``` - -If the problem persists, check if the plugin has been found and loaded by going through the following steps: - -1. Enable the debug mode -```ts -croct.plug({ - debug: true, - plugins: { - googleAnalytics: true, - } -}); -``` -2. Open your browser and check if there is an error like _"Plugin 'pluginName' is not registered"_ in the console - 1. If so, go over the previous points to double-check if you didn't skip any step. - 2. Otherwise, use one of our [support channels](https://github.com/croct-tech/plug-js#support) to get further assistance. We'll be happy to help you. - -## How to handle numeric user identifiers - -If your application uses a numeric data type to identify users, you'll need to convert it to a string before calling -methods that identify the user, such as [`croct.identify`](plug.md#identify). Otherwise, you'll receive the error -_"The user ID must be a string"_. - -> ⚠️ **Important** -> Never use guessable values as an identifier, such as email, phone, or incremental IDs. Instead, -> we strongly recommend using a cryptographically-secure UUIDs or signed tokens. -> For the latter, please contact your customer success manager for more information. - -For random numeric IDs, our recommendation is to convert the number to a string on the server-side, taking the -necessary precautions to ensure that the number will be represented as an integer (digits only) and not as a decimal or -in scientific notation. - -If the recommended solution isn't practical for your application, you can alternatively convert the number to string -on the client-side as the following example shows: - -```ts -function convertId(id) { - if (!Number.isSafeInteger(id)) { - throw new Error(`The ID "${id}" cannot be safely converted to a string.`) - } - - return id.toFixed(0); -} - -croct.identify(convertId(randomUserId)) -``` diff --git a/docs/user.md b/docs/user.md deleted file mode 100644 index 0920b169..00000000 --- a/docs/user.md +++ /dev/null @@ -1,116 +0,0 @@ -# User API Reference - -This reference documents all methods available in the User API and explains in detail how these methods work. - -## Index - -- [isAnonymous](#isanonymous) -- [isIdentified](#isidentified) -- [edit](#edit) - -## isAnonymous - -This method checks whether the user is anonymous. - -If you want to check if the user is identified, consider using the [`isIdentified`](#isidentified) instead. - -### Signature - -The `isAnonymous` method has the following signature: - -```ts -croct.user.isAnonymous(): boolean -``` - -This method returns `true` if the user is anonymous, `false` otherwise. - -## isIdentified - -This method checks whether the user is identified. - -If you want to check if the user is anonymous, consider using the [`isAnonymous`](#isanonymous) method instead. - -### Signature - -The `isIdentified` method has the following signature: - -```ts -croct.user.isIdentified(): boolean -``` - -This method returns `true` if the user is identified, `false` otherwise. - -## edit - -This method creates a patch to apply changes to the user's profile. - -These are the currently supported attributes: - -| Attribute | Type | Constraints | Description | -|----------------------|----------|---------------------------------------------------|-------------------------------| -| `firstName` | `String` | Between 1 and 50 characters long | The first name. | -| `lastName` | `String` | Between 1 and 50 characters long | The last name. | -| `birthDate` | `String` | Valid date in the form `YYYY-MM-DD` | The birth date. | -| `gender` | `String` | Either `male`, `female`, `neutral` or `unknown` | The gender. | -| `email` | `String` | Between 1 and 254 characters long | The email address. | -| `alternateEmail` | `String` | Between 1 and 254 characters long | The alternate email address. | -| `phone` | `String` | Between 1 and 30 characters long | The phone number. | -| `alternatePhone` | `String` | Between 1 and 30 characters long | The alternate phone number. | -| `address` | `object` | | The user address. | -| `address.street` | `String` | Between 1 and 100 characters long | The address' street. | -| `address.district` | `String` | Between 1 and 100 characters long | The address' district. | -| `address.city` | `String` | Between 1 and 100 characters long | The address' city. | -| `address.region` | `String` | Between 1 and 100 characters long | The address' region. | -| `address.country` | `String` | Between 1 and 100 characters long | The address' country. | -| `address.postalCode` | `String` | Between 1 and 20 characters long | The address' postal code. | -| `avatar` | `String` | Well-formed URL | The personal avatar URL. | -| `company` | `String` | Between 1 and 200 characters long | The company's name. | -| `companyUrl` | `String` | Well-formed URL | The company's website URL. | -| `jobTitle` | `String` | Between 1 and 50 characters long | The job title. | -| `interests` | `array` | Up to 30 strings between 1 and 30 characters long | The demonstrated interests. | -| `activities` | `array` | Up to 30 strings between 1 and 30 characters long | The performed activities. | -| `custom.*` | `object` | Up to 10 attributes | The map of custom attributes. | - -The following restrictions apply to custom attributes: - -- Each profile allows up to 10 custom attributes -- Attribute names should be strings up to 20 characters long, starting with a letter or underscore and optionally -followed by letters, digits, or underscores -- Attributes can be primitives (strings, numbers, booleans, and null) or composites (lists and maps). -- Strings should be up to 100 characters long -- Lists can contain up to 30 elements, including primitives, lists of primitives, or maps of primitives -- Maps can contain up to 30 elements, including primitives, lists of primitives, or maps of primitives -- Map keys should be strings up to 50 characters long - -We recommend using descriptive names in camel case, like `pets`, `favoriteColor` and, `loyaltyNumber`. Following these -recommendations will make your custom attributes look like the standard ones, which results in queries with better -readability. - -Notice that the attribute names are case-insensitive, meaning both `loyaltyNumber` and `loyaltynumber` refer to the same -attribute and could ultimately override each other. - -### Signature - -The `edit` method has the following signature: - -```ts -croct.user.edit(): Patch -``` - -The return is a patch for specifying the sequence of operations to apply to the user's profile. -Calling save on the patch will return a [Promise](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise) -that resolves to the `userProfileChanged` event after successful transmission. - -Refer to the [patch documentation](patch.md) for more details on how patching works. - -### Code Sample - -Here's a minimal example showing how to edit a user profile: - -```ts -croct.user.edit() - .set('company', 'Croct') - .add('interests', 'JavaScript') - .add('custom.pets', 'crocodile') - .save() -```