Skip to main content

Web SDK - Current (1.4.0)

Introduction

The Atomic Web SDK allows you to integrate an Atomic stream container into your web app or site, presenting cards from a stream to your customers.

The current stable release is 1.4.0.

Legacy versions

This documentation only applies to the Web SDK version 1.0.0 or later. For earlier versions of the Web SDK, see Web SDK (0.19.2 and older).

Browser support

The Atomic Web SDK supports the latest version of Chrome, Firefox, Edge (Chromium-based), Safari on macOS, Safari on iOS and Chrome on Android.

Boilerplate app

We currently do not have a boilerplate app for the Web SDK. Contact us if you are interested in this.

Installation

The current version of the Atomic Web SDK is 1.4.0, and is hosted on our CDN at https://downloads.atomic.io/web-sdk/release/1.4.0/sdk.js.

To integrate it, add the script as a source to your web page:

<html>
...
<body>
<script src="https://downloads.atomic.io/web-sdk/release/1.4.0/sdk.js"></script>
</body>
</html>
Update the Web SDK version

When Atomic releases a new version of the Web SDK, you will need to manually update your scripts with a url that references the download location of the latest version.

Content Security Policy

If your website enforces a content security policy (CSP) and is using any the following directives, you will need to add the resources corresponding to that directive to your CSP in order to use the Atomic Web SDK.

DirectiveRequired Resources
frame-srcblob:
connect-srchttps://*.client-api.atomic.io wss://*.client-api.atomic.io
style-src'self' 'unsafe-inline'
font-src'self' data: https://fonts.gstatic.com
script-src'self' https://downloads.atomic.io

Setup

Before you can display a stream container or single card, you will need to locate your API base URL, environment ID and API key.

API host, API keys and environment id

You must specify your SDK API base URL when configuring the Atomic SDK. This URL is found in the Atomic Workbench:

  1. In the Workbench, click on the cog icon in the bottom left and select 'Settings';
  2. On the screen that appears, click the 'SDK' tab. You'll find the API host details here, and can create API keys as required.
SDK API base URL

The SDK API base URL is different to the API base URL endpoint, which is also available under Configuration. The SDK API base URL ends with client-api.atomic.io.

The environment ID is shown at the top right of the Configuration screen.

Authenticating requests with a JWT

In order to authenticate requests that the SDK makes to the Atomic Platform the SDK requires that you supply an asynchronous callback which will return an authentication token (JWT) when requested. This is set by calling the setSessionDelegate method, supplying it a function which resolves to a promise that supplies an authentication token.

AtomicSDK.setSessionDelegate(() => {
return Promise.resolve('<authToken>')
})

Your callback will be invoked when the SDK requires a JSON Web Token (JWT), the token returned by your callback will be cached by the SDK and used for subsequent authenticated requests until expiry, after which the callback will be invoked once again to request a fresh token. The callback must return the token within 5 seconds, otherwise error handling will be triggered within the SDK. More information on the JWT structure is available in the Authentication section.

JWT Expiry interval

The expiry interval for a JWT cannot currently be configured in the Web SDK.

JWT Retry interval

An optional second parameter is available to set the retryInterval, this is the time in milliseconds that the SDK should wait before attempting a repeated request for a JWT from the session delegate in the event of a token request failing.

const retryInterval = 5000

AtomicSDK.setSessionDelegate(() => {
return Promise.resolve('<authToken>')
}, retryInterval)

WebSockets and HTTP API protocols

Available in SDK version 1.0.0 and above

If you wish to specify the protocol the SDK will use to communicate with the Atomic Platform when fetching cards this must be done by calling the setApiProtocol method, this must be done before calling initialise in order that the SDK knows which protocol to use when establishing a connection to the platform:

AtomicSDK.setApiProtocol('<communicationProtocol>')

The valid options for communicationProtocol are: "http" or "webSockets". If this method is not called the SDK will default to WebSockets for communication with the Atomic Platform.

Displaying a stream container

This section applies to all types of container. Containers can be created using the launch method (launcher view) , the embed method (standalone vertical and horizontal containers), or the singleCard method (single card view). Specifics and code examples for each type of container are explained in more detail in their dedicated sections.

Before displaying a stream container, you must initialize the SDK by calling the initialise method:

AtomicSDK.initialise('<apiHost>', '<apiKey>', '<environmentId>')

Stream container ID

First, you’ll need to locate your stream container ID.

Navigate to the Workbench, select Configuration > SDK > Stream containers and find the ID next to the stream container you are integrating.

Configuration options

Some configuration options are common for all types of container, other options are only available to a specific type of container. We mention the container type for each configuration option that is not available across all container types.

Style and presentation

A selection of UI elements can be customized within stream containers (does not apply to single card views). These are configured using the enabledUiElements property on a stream container configuration object:

  • cardListToast - defaults to true. Set to false to turn off toast messages on the card list.
  • toastConfig - an optional configuration object to customise the toast messages displayed by the SDK.
    • timeout: optionally supply a number that sets how long the toast message should be displayed for in milliseconds.
    • toastMessages: an optional object where you can set custom strings for the following properties: submittedCard, dismissedCard, snoozedCard & feedbackReceived. These will be displayed as the toast message for the respective card event.
  • cardListHeader - defaults to true. Set to false to disable the display of the title at the top of the card list.
  • customContainerHeader - can optionally supply a custom header to be displayed above the card feed when displaying a launch or embed type stream container.
    • scrollHeader: an optional boolean to control whether the custom header scrolls with the card feed, defaults to true.
    • headerElement: a string representing valid HTML to be rendered as the custom header. Styles to be applied to the header should be supplied inline on the HTML elements.
  • launcherButton - an optional configuration object for the button that toggles a launch type stream container. Accepts the following properties:
    • disabled: defaults to false. Set to true to prevent the launcher button from displaying on the page.
    • backgroundColor: a string value for a valid CSS color that will be used as the background color for the button.
    • openIconSrc: the source for the image tag displayed in the launcher button when it is in the closed state.
    • closeIconSrc: the source for the image tag displayed in the launcher button when it is in the open state.

The code snippet below shows how to initialize a launcher container type with a value for all of the enabledUiElements properties.

AtomicSDK.launch({
...
enabledUiElements: {
cardListToast: true,
toastConfig: {
timeout: 5000,
toastMessages: {
submittedCard: 'Custom submitted message',
dismissedCard: 'Custom dismissed message',
snoozedCard: 'Custom snoozed message',
feedbackReceived: 'Custom feedback message'
}
},
cardListHeader: true,
customContainerHeader: {
scrollHeader: true,
headerElement: `
<div style="padding: 10px;background-color: cyan;border-radius: 5px;">
<h1 style="color: grey;">Custom Header</h1>
</div>
`
}
launcherButton: {
disabled: false,
backgroundColor: '#00ffff',
openIconSrc: 'https://example.com/icon-open.svg',
closeIconSrc: 'https://example.com/icon-close.svg'
}
}
});

Functionality

  • onRuntimeVariablesRequested: an optional property that can be used on the configuration object to allow your app to resolve runtime variables. If this callback is not implemented, runtime variables will fall back to their default values, as defined in the Atomic Workbench.
  • runtimeVariableResolutionTimeout defaults to 5 seconds (5000 ms) if not provided.

Read more about runtime variables in the Runtime variables section.

CardListRefreshInterval

As of release 0.18.0, the Atomic Web SDK uses WebSockets to keep the card list up-to-date.

If a WebSocket connection cannot be established, or is not permitted, the SDK will revert to polling for new cards, which is the behaviour in SDK versions prior to 0.18.0. Also if the SDK has been configured to use HTTP for its communication protocol, via the setApiProtocol method, polling will be used to update the card list.

When the SDK reverts to polling, it will check for new cards every 15 seconds by default. You can customise how frequently this happens by specifying a value for the cardListRefreshInterval configuration option:

AtomicSDK.launch({
...
cardListRefreshInterval: 3000
});

Custom strings

You can customize the following strings used by the Web SDK, using the customStrings configuration object:

  • The title displayed at the top of the card list (cardListTitle);
  • The message displayed when the user has never received any cards before (awaitingFirstCard);
  • The message displayed when the user has seen at least one card in the container before, but has no cards to complete (allCardsCompleted);
  • The title to display for the card snooze functionality in the card overflow menu, and at the top of the card snooze screen (cardSnoozeTitle).
  • The text displayed next to the option to indicate that a card was useful (votingUsefulTitle);
  • The text displayed next to the option to indicate that a card was not useful (votingNotUsefulTitle);
  • The title displayed at the top of the screen presented when a user indicates that a card was not useful (votingFeedbackTitle).
  • The error message shown when the user does not have an internet connection (noInternetConnectionMessage).
  • The error message shown when the theme or card list cannot be loaded due to an API error (dataLoadFailedMessage).
  • The title of the button allowing the user to retry the failed request for the card list or theme (tryAgainTitle).

If you don't provide these custom strings, the SDK defaults will be used:

  • cardListTitle: "Cards"
  • awaitingFirstCard: "Cards will appear here when there's something to action."
  • allCardsCompleted: "All cards completed"
  • cardSnoozeTitle: "Remind me"
  • votingUsefulTitle: "This is useful"
  • votingNotUsefulTitle: "This isn't useful"
  • votingFeedbackTitle: "Send feedback"
  • noInternetConnectionMessage: "No internet connection"
  • dataLoadFailedMessage: "Couldn't load data"
  • tryAgainTitle: "Try again"
AtomicSDK.launch({
...
customStrings: {
cardListTitle: 'Things to do',
awaitingFirstCard: 'Cards will appear here soon',
allCardsCompleted: 'All cards completed',
cardSnoozeTitle: 'Snooze',
votingUsefulTitle: 'Positive feedback',
votingNotUsefulTitle: 'Negative feedback',
votingFeedbackTitle: 'Tell us more'
}
});

Displaying a custom header

The Web SDK supports displaying a custom header above your card feed for stream containers created using the launch or embed methods, it has no effect for singleCard stream containers.

The custom header is supplied as an HTML string to the customContainerHeader property of the customized UI elements. Styles should be applied inline to the HTML elements, do not attempt to reference classes or other styling from your host application stylesheets as these will not be applied.

Resizing standalone embeds to fit content

You can optionally choose to have standalone embeds resize to fit all of their content, so that they do not scroll. This allows you to embed a stream container inside of another scrolling container of your choice. This feature is enabled by setting the 3rd parameter of the AtomicSDK.embed method to true (by default, this value is false):

AtomicSDK.embed(document.querySelector('#embed'), {
...
onSizeChanged: (width, height) => {
console.log('Standalone embed changed size to', width, height)
}
}, true);

When enabled, the height of the iframe will be automatically updated to reflect its content when it changes. The onSizeChanged callback will also be triggered when the height changes, allowing you to adjust your UI as necessary.

Card minimum height

You can enforce a minimum height for the cards displayed in your stream container, if you'd prefer them to be large enough to display the card overflow menu without scrolling:

AtomicSDK.launch({
...
features: {
...
cardMinimumHeight: 250 // Replace 250 with your desired minimum height
}
});

The minimum height is specified in pixels.

Displaying a launcher

The Web SDK supports an additional implementation option - the launcher. This is implemented as a stream container that automatically resizes itself to accommodate its content, without growing beyond the bounds of the browser window. A trigger button is provided which allows you to open and close the stream container. This trigger button is positioned in the bottom right of your page by default. It can be re-positioned by using the .atomic-sdk-launcher-wrapper selector in the host app CSS. The visual appearance of the trigger button can be controlled using a combination of the .atomic-sdk-launcher-wrapper and .atomic-sdk-launcher selectors.

In addition, it is possible to control the size and position of the launcher container itself via the iframe.atomic-sdk-frame.launcher selector in the host app CSS.

The launcher is not supported in any of the other SDKs.

Embed with a launcher button

The code sample below shows how to use the AtomicSDK.launch(config) method, to create an instance of a stream container that is toggled by clicking the provided launcher button on screen.

<html>
...
<body>
<!-- Installation -->
<script src="https://downloads.atomic.io/web-sdk/release/1.4.0/sdk.js"></script>

<script>
AtomicSDK.initialise('<apiHost>', '<apiKey>', '<environmentId>')
AtomicSDK.setSessionDelegate(() => {
return Promise.resolve('<authToken>')
})

AtomicSDK.launch({
streamContainerId: '1234',
onCardCountChanged: count => {
console.log('Card count is now', count)
},
customStrings: {
cardListTitle: 'Things to do'
}
})
</script>
</body>
</html>

Opening and closing the launcher externally

Available in SDK version 0.17.0 and above

If you choose to embed an Atomic stream container in the launcher mode (using AtomicSDK.launch), you can open or close the stream container from another trigger, such as a button or link, instead of using the launcher button in the bottom right of the screen. If required you can disable the built-in launcher button using the enabledUiElements property of the customized UI elements.

Call the setOpen method on the stream container instance to open or close the stream container:

let instance = AtomicSDK.launch({
...
});

instance.setOpen(true);

Note: This method has no effect when embedding using the standalone option (AtomicSDK.embed) or single card view (AtomicSDK.singleCard).

Displaying a single card

Use AtomicSDK.singleCard(element, config) to create an instance of a stream container that displays a single card, without any surrounding UI. The card is embedded inside of the specified element. Any subviews open inside a separate frame.

When displaying a single card (using the AtomicSDK.singleCard method), the top most card in the given stream container is shown. The iframe that renders the single card automatically adjusts to the height of the card - this is set directly on the iframe's style property. When the card is actioned, dismissed or snoozed, and there are no other cards in the stream container, the card is removed, and the single card view collapses to a height of 0.

When a new card arrives, the single card view will resize to fit that card.

You can respond to changes in the height of the single card view using:

  1. CSS classes on the single card view. If the single card view is displaying a card, it has a class of has-card. The frame itself always has a class of single-card.
  2. Setting the onSizeChanged callback, on the configuration object that is passed to the stream container when calling AtomicSDK.singleCard. This callback is triggered when the size of the single card view changes, and you can use this to perform additional actions such as animating the card in or out, or removing it from the page.
AtomicSDK.singleCard(document.querySelector('#embed'), {
onSizeChanged: (width, height) => {
console.log(`The single card view now has a height of ${height}.`)
}
})

When displaying a single card view, all card subviews, full image/video views, and the snooze selection screen all display inside a modal iframe alongside the card. You can position this modal wherever you like on your page. It can be targeted using the class modal-subview, and when the modal iframe is displaying a subview, it has a class of has-subview.

The iframe generated by the singleCard method can be styled just like any other DOM element with CSS.

<html>
...
<body>
<!--Installation-->
<script src="https://downloads.atomic.io/web-sdk/release/1.4.0/sdk.js"></script>

<script>
AtomicSDK.initialise('<apiHost>', '<apiKey>', '<environmentId>')
AtomicSDK.setSessionDelegate(() => {
return Promise.resolve('<authToken>')
})

AtomicSDK.singleCard(document.querySelector('#embed'), {
streamContainerId: '1234',
onCardCountChanged: count => {
console.log('Card count is now', count)
},
customStrings: {
cardListTitle: 'Things to do'
}
})
</script>
</body>
</html>

Displaying a vertical stream container

This code sample shows how to use the AtomicSDK.embed(element, config, autosize) method to create an instance of a stream container, embedded as an iframe inside of the specified element.

The iframe generated by the embed method can be styled just like any other DOM element with CSS.

<html>
...
<body>
<!--Installation-->
<script src="https://downloads.atomic.io/web-sdk/release/1.4.0/sdk.js"></script>

<script>
AtomicSDK.initialise('<apiHost>', '<apiKey>', '<environmentId>')
AtomicSDK.setSessionDelegate(() => {
return Promise.resolve('<authToken>')
})

AtomicSDK.embed(document.querySelector('#embed'), {
streamContainerId: '1234',
onCardCountChanged: count => {
console.log('Card count is now', count)
},
customStrings: {
cardListTitle: 'Things to do'
}
})
</script>
</body>
</html>

Displaying a horizontal stream container

The Web SDK also supports displaying stream containers created with embed as a horizontally orientated stream of cards. In this horizontal view the cards are rendered from left to right.

When creating a stream container with the embed method, pass a configuration object which contains a HorizontalContainerConfig object within the features property:

AtomicSDK.embed({
streamContainerId: "1234",
...
features: {
horizontalContainerConfig: {
enabled: true,
cardWidth: 400,
emptyStyle: "standard",
headerAlignment: "center",
scrollMode: "snap",
lastCardAlignment: "left"
}
}
})

The iframe generated by the embed methods can be styled just like any other DOM element with CSS.

If a stream container is specified to be horizontal by setting enabled to true on the HorizontalContainerConfig object, at a minimum you must also supply a cardWidth property. Without this the SDK will throw an exception for your stream container.

Configuration object

This object allows you to configure the horizontal stream container via the following properties:

  • enabled: A boolean flag that instructs the SDK to display this stream container in horizontal layout.
  • cardWidth: The width of each card in the stream container. All cards in the container will have this same width and it must be assigned explicitly.
  • emptyStyle: The style of the empty state (when there are no cards) of the container. Possible values are:
    • standard: Default value. The stream container displays a no-card user interface.
    • shrink: The stream container shrinks out of view.
  • headerAlignment: The alignment of the card list title in the horizontal stream container header. Possible values are:
    • center: Default value. The title is aligned in the middle of the header.
    • left: The title is aligned to the left of the header.
  • scrollMode: The scrolling behaviour of the stream container. Possible values are:
    • snap: Default value. The stream container snaps between cards when scrolling.
    • free: The container scrolls freely.
  • lastCardAlignment: The alignment of the card when there is only one present in the stream container. Possible values are:
    • left: Default value. The last card is aligned to the left of the container.
    • center: The last card is aligned in the middle of the container.

Closing a stream container

To stop a stream container, and remove it from your web page, call the stop method on the previously created instance:

let instance = AtomicSDK.embed(document.querySelector('#embed'), {
...
})

instance.stop()

Handling user logout

The SDK provides a method for clearing state when a user logs out, so that a new user can log in. This method sends any pending analytics events to the Atomic Platform. Calling this method will also invalidate the JWT cached by the SDK, as it is expected that you will update the token returned by the authentication callback to return a JWT valid for the new user who is logged in next.

await AtomicSDK.logout()

Customizing the first time loading experience

When a stream container with a given ID is launched for the first time on a user's device, the SDK loads the theme and caches it in the browser for future use. On subsequent launches of the same stream container, the cached theme is used and the theme is updated in the background, for the next launch. Note that this first time loading screen is not presented in single card view - if a single card view fails to load, it collapses to a height of 0.

The SDK supports some basic properties to style the first time load screen, which displays a loading spinner in the center of the container. If the theme fails to load for the first time, an error message is displayed with a 'Try again' button. One of two error messages are possible - 'Couldn't load data' or 'No internet connection'.

First time loading screen colors are customized using the following SDK configuration properties:

  • backgroundColor: the background of the first time loading screen. Defaults to #FFFFFF.
  • textColor: the color to use for the error message shown when the theme fails to load. Defaults to rgba(0,0,0,0.5).
  • loadingSpinnerColor: the color to use for the loading spinner on the first time loading screen. Defaults to #000000.
  • buttonTextColor: the color to use for the 'Try again' button, shown when the theme fails to load. Defaults to #000000.
AtomicSDK.launch({
...
firstLoadStyles: {
backgroundColor: '#FFFFFF',
textColor: '#000000',
loadingSpinnerColor: '#000000',
buttonTextColor: '#000000'
}
});

Dark mode

Available in SDK version 0.18.0 and above

Stream containers in the Atomic Web SDK support dark mode. You can configure an optional dark theme for your stream container in the Atomic Workbench.

The interface style (interfaceStyle) property determines which theme is rendered:

  • automatic: If the user's device is currently set to light mode, the stream container will use the light (default) theme. If the user's device is currently set to dark mode, the stream container will use the dark theme (or fallback to the light theme if this has not been configured). If the stream container does not have a dark theme configured, the light theme will always be used.
  • light: The stream container will always render in light mode, regardless of the device setting.
  • dark: The stream container will always render in dark mode, regardless of the device setting.

To change the interface style, set the corresponding value for the interfaceStyle property on the configuration object when creating the stream container.

Filtering cards

Stream containers (vertical or horizontal) and single card containers can have one or more filters applied. These filters determine which cards are displayed.

When you have created a stream container, the stream container instance that is returned has a streamFilters property which can be used to set filters to be applied to that stream container. Each stream filter consists of both a filter value and an operator, to set a stream filter you need to call the desired filter value function from the streamFilters object, and chain off from that the desired filter operator. After setting the stream filters call the apply function:

const instance = AtomicSDK.launch({
...
})

// this will set a card priority stream filter with the greaterThan operator
instance.streamFilters.addCardPriorityFilter().greaterThan(3)
instance.streamFilters.apply()

Multiple stream filters can be applied, the snippet below shows how you would set filters to only show cards with a card priority greater than 5 & created after 15th February 2020, for a launcher type container. The apply function needs to be called just once and must be called after you have set all the filters you wish to apply:

const instance = AtomicSDK.launch({
...
})

instance.streamFilters.addCardPriorityFilter().greaterThan(5)
instance.streamFilters.addCardCreatedFilter().greaterThan('2020-02-15T00:00:00.000Z')
instance.streamFilters.apply()

Filter values

The filter value is used to filter cards in a stream container. The table below summarises the different card attributes that can be filtered on, as well as the permitted data type for that filter and the filter operators that can be applied to it.

Card attributeDescriptionFilter functionValue typePermitted operators
PriorityCard priority defined in Workbench, Card -> DeliverystreamFilters.addCardPriorityFilter()number between 1 & 10 inclusiveequals
notEqualTo
greaterThan
greaterThanOrEqualTo
lessThan
lessThanOrEqualTo
in
notIn
between
Card template IDThe template ID of a card, see below for how to get itstreamFilters.addCardTemplateIdFilter()stringequals
notEqualTo
in
notIn
Card template nameThe template name of a cardstreamFilters.addCardTemplateNameFilter()stringequals
notEqualTo
in
notIn
Card template created dateThe date time when a card template is createdstreamFilters.addCardCreatedFilter()ISO date stringequals
notEqualTo
greaterThan
greaterThanOrEqualTo
lessThan
lessThanOrEqualTo
Custom variableThe variables defined for a card in Workbench, Card -> VariablesstreamFilters.addVariableFilter()multipleequals
notEqualTo
greaterThan
greaterThanOrEqualTo
lessThan
lessThanOrEqualTo
in
notIn
between

Note: It's important to specify the right value type when referencing custom variables for filter value. There are five types of variables in the Workbench, currently four are supported: String, Number, Date and Boolean.

How to get the card template ID

On the card editing page, click on the ID part of the overflow menu at the upper-right corner.

Card template ID

Filter operators

The filter operator is the operational logic applied to a filter. The table below summarises the available operators as well as the value types each will accept. Note that depending on which filter value you are filtering on the available value types may be further narrowed.

OperatorDescriptionSupported value types
equalsEqual to the filter valuenumber
string
iso date string
boolean
null
notEqualToNot equal to the filter valuenumber
string
iso date string
boolean
null
greaterThanGreater than the filter valueiso date string
number
greaterThanOrEqualToGreater than or equal to the filter valueiso date string
number
lessThanLess than the filter valueiso date string
number
lessThanOrEqualToLess than or equal to the filter valueiso date string
number
inIn the set of filter values suppliednumber[]
string[]
notInNot in the set of filter values suppliednumber[]
string[]
betweenIn the range bound by the two values supplied. Will only accept an array containing two numbers e.g. [2, 8] will match values between 2 and 8 inclusive.number[]
Passing correct value type to an operator

Each operator supports different value types. For example, the operator lessThan only supports an iso date string or a number. So passing any other value types will raise an exception.

Removing filters

Having applied filters to a stream container you have the ability to clear them at a later stage if required. To clear the filters you should call the clearFilters function on the on the streamFilters property for the relevant stream container instance. For example:

const instance = AtomicSDK.launch({
...
})

// applying filters to your stream container instance
instance.streamFilters.addCardPriorityFilter().greaterThan(5)
instance.streamFilters.addCardCreatedFilter().greaterThan('2020-02-15T00:00:00.000Z')
instance.streamFilters.apply()

// at some later stage in order to clear the filters you should trigger
instance.streamFilters.clearFilters()

In the Atomic Workbench, you can create a link button or submit button with a custom action payload. When such a button is tapped, the appropriate callback, onLinkButtonPressed or onSubmitButtonPressed is triggered, allowing you to perform an action in your web app based on that payload.

The callback is passed an object, containing the payload that was defined in the Workbench for that button, as well as the stream container ID and card instance ID that triggered the button.

AtomicSDK.launch({
...
streamContainerId: "1234",
onLinkButtonPressed: (data) => {
if(data.streamContainerId === "1234" &&
data.cardInstanceId === "abcd-1234" &&
data.actionPayload.screen === 'home') {
navigateToHomeScreen()
}
},
onSubmitButtonPressed: (data) => {
if(data.streamContainerId === "1234" &&
data.cardInstanceId === "abcd-1234" &&
data.actionPayload.screen === 'home') {
navigateToHomeScreen()
}
}
});

Customizing toast messages for card events

You can customize any of the toast messages used when dismissing, completing, snoozing and placing feedback on a card. This is configurable for each stream container. You simply supply a string for each custom message. If you do not supply a string, the defaults will be used.

Read the Style and presentation section to understand how to do this using the toastConfig configuration object. That section also has a code example.

Card snoozing

The Atomic SDKs provide the ability to snooze a card from a stream container or single card view. Snooze functionality is exposed through the card’s action buttons, overflow menu and the quick actions menu (exposed by swiping a card to the left, on iOS and Android).

Tapping on the snooze option from either location brings up the snooze date and time selection screen. The user selects a date and time in the future until which the card will be snoozed. Snoozing a card will result in the card disappearing from the user’s card list or single card view, and reappearing again at the selected date and time. A user can snooze a card more than once.

You can customize the title of the snooze functionality, as displayed in a card’s overflow menu and in the title of the card snooze screen. The default title, if none is specified, is Remind me.

When configuring a stream container, specify a value for cardSnoozeTitle, within the customStrings object, to customize the title for the card snooze functionality:

AtomicSDK.launch({
customStrings: {
cardSnoozeTitle: 'Snooze'
}
})

Card voting

The Atomic SDKs support card voting, which allows you to gauge user sentiment towards the cards you send. When integrating the SDKs, you can choose to enable options for customers to indicate whether a card was useful to the user or not, accessible when they tap on the overflow button in the top right of a card.

If the user indicates that the card was useful, a corresponding analytics event is sent for that card (card-voted-up).

If they indicate that the card was not useful, they are presented with a secondary screen where they can choose to provide further feedback. The available reasons for why a card wasn’t useful are:

  • It’s not relevant;
  • I see this too often;
  • Something else.

If they select "Something else", a free-form input is presented, where the user can provide additional feedback. The free form input is limited to 280 characters. After tapping "Submit", an analytics event containing this feedback is sent (card-voted-down).

You can customize the titles that are displayed for these actions, as well as the title displayed on the secondary feedback screen. By default these are:

  • Thumbs up - "This is useful";
  • Thumbs down - "This isn’t useful";
  • Secondary screen title - "Send feedback".

Card voting is disabled by default. You can enable positive card voting ("This is useful"), negative card voting ("This isn’t useful"), or both:

AtomicSDK.launch({
...
features: {
cardVoting: {
canVoteUseful: true, // Whether the user can vote that a card is useful.
canVoteNotUseful: true // Whether the user can vote that a card is not useful.
}
}
})

You can also customize the titles for the card voting options, and the title displayed at the top of the feedback screen, presented when a user indicates the card wasn’t useful:

AtomicSDK.launch({
...
customStrings: {
votingUsefulTitle: 'Positive feedback',
votingNotUsefulTitle: 'Negative feedback',
votingFeedbackTitle: 'Tell us more'
}
})

Responding to card events

The SDK allows you to perform custom actions in response to events occurring on a card, such as when a user:

  • submits (or fails to submit) a card;
  • dismisses (or fails to dismiss) a card;
  • snoozes (or fails to snooze) a card;
  • indicates a card is useful (when card voting is enabled);
  • indicates a card is not useful (when card voting is enabled).

To be notified when these happen, assign an onCardEvent callback when creating your stream container:

AtomicSDK.launch({
...
// Callback notified when card events occur.
onCardEvent: (event) => {
console.log(`Card event occurred: ${event.type}`)
}
...
});

The identifier for the event is available in the type property, and will be one of the following:

  • submitted
  • submit-failed
  • dismissed
  • dismiss-failed
  • snoozed
  • snooze-failed
  • voted-useful
  • voted-not-useful

Sending custom events

A custom event can be used in the Workbench to create segments for card targeting. For more details of custom events, see Custom Events.

You can send custom events directly to the Atomic Platform for the logged in user, via the sendCustomEvent method, passing it an object with an eventName and optionally properties where you can add additional data for your event.

The event will be created for the user defined by the authentication token returned in the session delegate. As such, you cannot specify target user IDs using this method.

AtomicSDK.sendCustomEvent({
eventName: 'myCustomEvent',
properties: {
action: 'updated-profile'
}
}).catch((error) => {
// An error is thrown if something prevents the custom event from being sent to the Platform
})

Push notifications

Push notifications are currently not supported in the Web SDK.

Retrieving card count

Use user metrics

As of Web SDK version 0.17.0, it is recommended that you use user metrics to retrieve the card count instead. See the next section for more information.

You can retrieve the total number of cards within a stream container, without creating a container in your UI, by calling the AtomicSDK.requestCardCount method, passing a stream container ID:

AtomicSDK.requestCardCount('<containerId>')
.then(result => {
console.log('Card count is now', result.totalCards)
})
.catch(e => {
console.error(e)
})

Alternatively, when creating a stream container, you can supply a callback that will be triggered when the card count changes in that container. This will occur when a card is dismissed, completed or the number of cards in the card list changes. The callback will be called with two parameters:

  • visibleCount: total number of cards visible in the container (read and unread, excluding cards that are not visible because of a filter)
  • totalCount: total number of cards available in the stream (including cards that are not visible because of a filter)

The callback is specified as a configuration option to the launch and embed methods:

AtomicSDK.launch({
...
onCardCountChanged: (visibleCount, totalCount) => {
console.log('Card count is now', {
visibleCards: visibleCount,
totalCards: totalCount
});
}
});

Retrieving the count of active and unseen cards

Available in SDK version 0.17.0 and above

The Atomic Web SDK exposes an object known as user metrics. These metrics include:

  • The number of cards available to the user across all stream containers;
  • The number of cards that haven't been seen across all stream containers;
  • The number of cards available to the user in a specific stream container (equivalent to the card count functionality in the previous section);
  • The number of cards not yet seen by the user in a specific stream container.

These metrics allow you to display badges in your UI that indicate how many cards are available to the user but not yet viewed, or the total number of cards in a given stream container.

AtomicSDK.requestUserMetrics()
.then(metrics => {
console.log('User metrics returned:', {
totalCards: metrics.totalCards(),
unseenCards: metrics.unseenCards(),
totalCardsInContainer: metrics.totalCardsForStreamContainer(
'<streamContainerId>'
),
unseenCardsInContainer: metrics.unseenCardsForStreamContainer(
'<streamContainerId>'
)
})
})
.catch(err => {
console.error(err)
})

Runtime variables

Runtime variables are resolved in the SDK at runtime, rather than from an event payload when the card is assembled. Runtime variables are defined in the Atomic Workbench.

The SDK will ask the host app to resolve runtime variables when a list of cards is loaded (and at least one card has a runtime variable), or when new cards arrive (and at least one card has a runtime variable).

Runtime variables are resolved by your app via the onRuntimeVariablesRequested property, specified on the configuration object passed to the stream container. If this callback is not implemented, runtime variables will fall back to their default values, as defined in the Atomic Workbench.

This callback, when triggered by the SDK, provides you with:

  • An array of objects representing the cards in the list with runtime variables. Each card object contains:
    • The event name that triggered the card’s creation;
    • The lifecycle identifier associated with the card;
    • A Map representing the runtime variables on the particular card.
  • A callback, that must be called by the host app, with the resolved cards, once all variables are resolved.

If a variable is not resolved, that variable will use its default value, as defined in the Atomic Workbench.

If you do not call the provided callback before the runtimeVariableResolutionTimeout elapses (defined on the configuration object passed to the stream container), the default values for all runtime variables will be used. Calling the provided callback more than once has no effect.

runtimeVariableResolutionTimeout defaults to 5 seconds (5000 ms) if not provided.

AtomicSDK.launch({
...
// Maximum amount of time that runtime variable resolution can take (in milliseconds)
runtimeVariableResolutionTimeout: 8000,
// Callback that resolves runtime variables
onRuntimeVariablesRequested: (cards, callback) => {
const date = new Date()

cards.forEach(function(card) {
card.runtimeVariables.set('dateShort', date.toDateString())
card.runtimeVariables.set('dateLong', date.toString())
card.runtimeVariables.set('name', 'User Name')
})

callback(cards)
}
...
});
Runtime variables only resolve to string values

Runtime variables can currently only be resolved to string values.

You can also manually update runtime variables at any time by calling updateVariables on the stream container instance:

const instance = AtomicSDK.launch({...});
instance.updateVariables();

Accessibility

Accessibility attributes, such as appropriate titles and ARIA attributes, are available as of SDK release 0.13.0.

Alternate text

As of SDK 0.19.1, alternate text is supported on all image and video components. This alternate text is supplied by you when authoring a card, and is used to describe the image or video itself. Alternate text forms part of a description that is passed to the system screen reader (when enabled).

The following description is used for each image or video format:

FormatText supplied to screen reader
BannerAlternate text
InlineAlternate text
TextLabel is used (also defined in the Workbench), as this component does not render an image thumbnail
ThumbnailAlternate text, label and description

Focus rings

The Atomic Web SDK allows you to customize the focus ring used to highlight components when a user tabs through a stream container or single card view. The focus ring is rendered as a solid outline around the active component, and only appears when the user tabs between components using their keyboard.

To customize the focus ring:

  1. Open the Atomic Workbench.
  2. Navigate to the Theme Editor (Configuration > SDK > Container themes).
  3. Select a theme and then choose Accessibility > Focus ring.

The color of this focus border is customized using the colors.border.focus property in your theme.

There are two options you can customize for the focus ring color:

  • Feed: refers to the screen displaying the card list or single card;
  • Subview: all other screens in the SDK.

SDK Analytics

Change to default behaviour

In Web SDK versions prior to 0.17.0, the default behaviour was to send analytics for resolved runtime variables. As of release 0.17.0, this behaviour has changed to default to not sending these analytics. Therefore, when upgrading to release 0.17.0, you must explicitly enable this feature to use it.

If you use runtime variables on a card, you can optionally choose to send the resolved values of any runtime variables back to the Atomic Platform as an analytics event. This per-card analytics event - runtime-vars-updated - contains the values of runtime variables rendered in the card and seen by the end user. Therefore, you should not enable this feature if your runtime variables contain sensitive data that you do not wish to store on the Atomic Platform.

To enable this feature, set the features.runtimeVariableAnalytics flag on your configuration object to true:

AtomicSDK.launch({
...
features: {
runtimeVariableAnalytics: true
}
...
})

Updating user data

The SDK allows you to update profile & preference data for the logged in user via the updateUser method.

This method accepts one parameter, a user update object, representing the profile & preference details that you wish to update for the logged in user. This is the user as identified by the auth token provided by the authentication callback.

The user update object has two optional properties, profile & preferences, each of which has a number of optional properties that may be updated for the user.

Profile fields

The following optional profile fields can be supplied to update the data for the user. Any fields which have not been supplied will remain unmodified after the user update. Further custom fields can be supplied, however these must first be defined in the workbench as described in the Custom fields section of the documentation.

  • external_id: An optional string that can be used as an identifier for the user.
  • name: An optional string.
  • phone: An optional string.
  • city: An optional string.
  • country: An optional string.
  • region: An optional string.

Preference fields

The following optional preference fields can be supplied to update the data for the user. Again, any fields which have not been supplied will remain unmodified after the user update.

  • notificationsEnabled: An optional boolean to determine whether notifications are enabled.

  • notifications: An optional object that defines the notification time preferences of the user for different days of the week, as well as a default value that will take precedence if a day does not have notification preferences defined for it. Only the following keys: mon, tue, wed, thu, fri, sat, sun, default, will be accepted for this object. If any other value is provided the SDK will display a warning and the notification object will be skipped when updating the user data.

    Each day accepts an array of notification time periods, these are periods during which notifications are allowed. If an empty array is provided notifications will be disabled for that day. The following example would enable notifications between 8am - 5:30pm & 7pm - 10pm:

    [{
    from: {hours: 8, minutes: 0},
    to: {hours: 17: minutes: 30}
    }, {
    from: {hours: 19, minutes: 0},
    to: {hours: 22, minutes: 0}
    }]

    hours a 24h value that must be between 0 & 23 inclusive, minutes a value between 0 & 59 inclusive.

An example of a user update submitted using the updateUser method:

const userUpdateObject = {
profile: {
// profile fields to be updated:
external_id: '123',
name: 'User Name',
email: 'email@example.com',
phone: '(+64)210001234',
city: 'Wellington',
country: 'New Zealand',
region: 'Wellington',
// any further custom fields that have already been defined in the Workbench:
myCustomField: 'My custom value'
},
preferences: {
// preference fields to be updated
notificationsEnabled: true,
notifications: {
default: [{from: {hours: 8, minutes: 0}, to: {hours: 17, minutes: 45}}],
sat: [],
sun: []
}
}
}

AtomicSDK.updateUser(userUpdateObject)

Utility methods

Debug logging

Enable debug logging to view verbose logs of activity within the SDK, output to the browser console. Debug logging is disabled by default, and should not be enabled in release builds.

AtomicSDK.enableDebugMode(level)

The level parameter is a number that indicates the verbosity of the logs exposed:

  • Level 0: Default, no logs exposed
  • Level 1: Operations and transactions are exposed
  • Level 2: Operations, transactions and its details are exposed, plus level 1.
  • Level 3: Internal developer logs, plus level 2

Error handling

The SDK allows you to set a callback via the AtomicSDK.onError property. This passes javascript errors that may occur in the SDK.

AtomicSDK.onError = function (error) {
// handle the reported error as required
console.error('An error occured in the Atomic SDK: ', error)
}

The callback you set will receive errors that occur within the stream containers you have created. If you do not set this callback, errors will instead be logged to the browser console.

Errors resulting from communication between the SDK & the Atomic platform, such as authentication & network errors, will be logged via the debug logger at the level of verbosity you have chosen. These logs can be observed in the browser console and will be a string consisting of the error name and error description.

Setting the version of the client app

The SDK provides a method AtomicSDK.setClientAppVersion for setting the current version of your app. This app version is attached to generated analytics events to make it easy to track issues between app versions and to get insight into version usage.

Version strings have a maximum length of 128 characters, if you supply a longer string it will be trimmed to that length.

The following example sets the client app version to Version 2.3.1.

AtomicSDK.setClientAppVersion('Version 2.3.1')