Attentive
Introduction
Attentive is an SMS software platform that helps your business strengthen customer relationships.
This article will describe the steps to take to allow you to integrate with the Attentive platform and build custom applications.
Setup Attentive
Create a custom App for your account:
Navigate to Attentive and click on Marketplace.

Click Create App in the top right corner.

Enter a unique name for your app in the App name field.
Enter your email address in the Contact email field.
Edit the Permissions (From No Access to Write) for the following APIs (by default, all APIs have No Access selected):

All Attentive API documentation can be found here.
Click Create.
API Key modal displays
It is essential that you copy and keep the API key in a secure place.

Click X to exit the modal after you’ve saved your API key.
Create the Attentive destination function
Complete the following steps to create a destination function:
Navigate to your Segment Workspace.
Click on Connections and click on Add Destinations.

In the Functions tab, click on New Function

select the Destination option and click on the Build button.

Replace the code in the editor with this snippet. Don't copy lines below this comment.
Click on the Settings tab to the right and add the following properties:
- attentiveAccessToken (string): The access token to use to make authenticated API calls to Attentive.
- productViewEventName (string): The product view event name to map to Attentive product view events.
- addToCartEventName (string): The add to cart event name to map to Attentive add to cart events.
- purchaseEventName (string): The purchase event name to map to Attentive purchase events.
- allowCustomEvents (boolean): When set to true, any event that is not a Product View, Add To Cart, or Purchase event will be tracked via the custom events API.
Click on Configure.
Fill the form with the function Name (mandatory) and Description (optional) and click Create Function.

Click on Connect Destination button, and finally select the source.
It is common to connect both Back and Front-End Production sources
Edit destination functions settings.
Now that you have created the destination function, let's review the Settings
On the left sidebar click on Connections/Destinations.
Click Destination and search for Attentive.

Select Front-End and in the Settings select:
addToCartEventName = Product Added
allowCustomEvents = ON
attentiveAccessToken = "paste the key you stored above when creating a custom app for your account".
productViewEventName = Product Viewed
purchaseEventName = Order Completed
Repeat same Settings for Back-End Production Source

Add the Attentive tag to the codebase
The last step is to add the attentive tag script to the codebase. The process may vary based on frameworks and architecture strategies.
Replace the customer name with the right one. An example: https://cdn.attn.tv/chord/dtag.js
<script src="https://cdn.attn.tv/customername/dtag.js"></script>
Below, there are some popular examples with Gatsby and NextJS:
NextJS
Using the Script component inside _app.js
Using the Script component inside _document.js
Gatsby
Using html.js
Using a plugin
Using Gatsby Server Rendering APIs
SNIPPET if you do not have access to Github
function formatAddToCartEventProduct(product) { return { productId: product.product_id, productVariantId: product.sku, productImage: product.image_url, productUrl: product.url, name: product.name, price: [ { value: product.price, currency: product?.currency || 'USD' } ], quantity: product.quantity } } function formatProductViewedEventProduct(product) { return { productId: product.product_id, productVariantId: product.sku, productImage: product.image_url, productUrl: product.url, name: product.name, price: [ { value: product.price, currency: product?.currency || 'USD' } ], quantity: product.quantity } } function formatPurchaseEventProducts(products, currency = 'USD') { if (!Array.isArray(products) || products.length === 0) return [] return products.map(product => ({ productId: product.product_id, productVariantId: product.product_sku, productImage: product.image_url, productUrl: product.url, name: product.name, price: [ { value: product.price, currency: currency } ], quantity: product.quantity })) } /** * Handle track event * @param {SegmentTrackEvent} event * @param {FunctionSettings} settings */ async function onTrack(event, settings) { const attentiveEvents = [ settings.productViewEventName, settings.addToCartEventName, settings.purchaseEventName ] const endpointMap = { [settings.productViewEventName]: 'https://api.attentivemobile.com/v1/events/ecommerce/product-view', [settings.addToCartEventName]: 'https://api.attentivemobile.com/v1/events/ecommerce/add-to-cart', [settings.purchaseEventName]: 'https://api.attentivemobile.com/v1/events/ecommerce/purchase' } const isCustomEvent = !attentiveEvents.includes(event.event) // Validate the event type. if (!settings.allowCustomEvents && isCustomEvent) return if (isCustomEvent) return await trackCustomEvent(event, settings) const endpoint = endpointMap[event.event] let items = [] if (event.event === settings.productViewEventName) { items = [formatProductViewedEventProduct(event.properties)] } if (event.event === settings.addToCartEventName) { items = [formatAddToCartEventProduct(event.properties)] } if (event.event === settings.purchaseEventName) { items = formatPurchaseEventProducts( event.properties?.products, event.properties?.currency ) } const body = { items, occurredAt: event.originalTimestamp, user: { email: event.properties?.email ?? 'anonymous@chord.co' } } try { const response = await fetch(endpoint, { method: 'POST', headers: { Authorization: `Bearer ${settings.attentiveAccessToken}`, 'Content-Type': 'application/json' }, body: JSON.stringify(body) }) if ([400, 401, 403, 404, 500].includes(response.status)) { throw new RetryError(`Failed with ${response.status}`) } return true } catch (error) { throw new RetryError(error.message) } } /** * Handle tracking custom event to Attentive. * @param {SegmentTrackEvent} event * @param {FunctionSettings} settings */ async function trackCustomEvent(event, settings) { const body = { type: event.event, properties: event.properties, externalEventId: event.messageId, occurredAt: event.originalTimestamp, user: { email: event.properties?.email || 'anonymous@chord.co' } } try { const response = await fetch( 'https://api.attentivemobile.com/v1/events/custom', { method: 'POST', headers: { Authorization: `Bearer ${settings.attentiveAccessToken}`, 'Content-Type': 'application/json' }, body: JSON.stringify(body) } ) if ([400, 401, 403, 404, 500].includes(response.status)) { throw new RetryError(`Failed with ${response.status}`) } return true } catch (error) { throw new RetryError(error.message) } } /** * Handle identify event * @param {SegmentIdentifyEvent} event * @param {FunctionSettings} settings */ async function onIdentify(event, settings) { // Learn more at https://segment.com/docs/connections/spec/identify/ throw new EventNotSupported('identify is not supported') } /** * Handle group event * @param {SegmentGroupEvent} event * @param {FunctionSettings} settings */ async function onGroup(event, settings) { // Learn more at https://segment.com/docs/connections/spec/group/ throw new EventNotSupported('group is not supported') } /** * Handle page event * @param {SegmentPageEvent} event * @param {FunctionSettings} settings */ async function onPage(event, settings) { // Learn more at https://segment.com/docs/connections/spec/page/ throw new EventNotSupported('page is not supported') } /** * Handle screen event * @param {SegmentScreenEvent} event * @param {FunctionSettings} settings */ async function onScreen(event, settings) { // Learn more at https://segment.com/docs/connections/spec/screen/ throw new EventNotSupported('screen is not supported') } /** * Handle alias event * @param {SegmentAliasEvent} event * @param {FunctionSettings} settings */ async function onAlias(event, settings) { // Learn more at https://segment.com/docs/connections/spec/alias/ throw new EventNotSupported('alias is not supported') } /** * Handle delete event * @param {SegmentDeleteEvent} event * @param {FunctionSettings} settings */ async function onDelete(event, settings) { // Learn more at https://segment.com/docs/partners/spec/#delete throw new EventNotSupported('delete is not supported') } // -------------------------------------------------- // Below lines are for tests. Do not copy to Segment. const RetryError = Error const EventNotSupported = Error module.exports = { onTrack, RetryError }