The SDK reports what users do in Stories, Clips, Polls, Quizzes, and ads
through the onUserActivityOccurred callback. This page shows how to receive
these events and forward them to your analytics tool, what the startup event
contains, and how to add placement context. The event pages list every event
and its fields.
Add an onUserActivityOccurred callback to Storyteller.sharedInstance.delegate
before you call initialize, so you also receive the
startup event. The callback receives the event type and
an object with the event's fields.
Replace analytics.track with the call your analytics tool uses. To handle one
event type, compare type with a Storyteller.ActivityType value, for example
Storyteller.ActivityType.openedStory. In TypeScript, the delegate type is
IStorytellerDelegate.
Assigning Storyteller.sharedInstance.delegate replaces all four global
callbacks: onUserActivityOccurred, onShareButtonTapped, getAdConfig, and
userNavigatedToApp. Define all your callbacks in one object, or spread the
current delegate:
The SDK calls onUserActivityOccurred only when enableUserActivityTracking
is true, which is the default. Ad events also need enableAdTracking. When
enableFullVideoAnalytics is false, content IDs and titles are null. See
Control privacy and tracking for these options.
The SDK sends sdkInitialized (Storyteller.ActivityType.sdkInitialized) when
an initialize call gets the result of the settings request for your tenant:
initializationSucceeded is true when the settings load. Later
initialize calls after a successful one don't send the event again.
initializationSucceeded is false when the settings request fails. The
initialize promise then rejects.
initialize rejects without sending sdkInitialized when the API key is
missing, when the SDK can't save the user ID, or when the request for the
user's viewing history fails. With the default privacy options, the SDK waits
for the viewing history before the settings, so an invalid API key or a network
outage usually fails that request first. Handle startup failures in the
catch block of initialize, not with this event.
Set the delegate before you call initialize to receive this event.
The tracking options in effect. enablePersonalization and enableStorytellerTracking are false when enableFunctionalCookies is false. The event doesn't include enableFunctionalCookies or disabledFunctionalFeatures.
appId
The page origin and path, for example https://www.example.com/news, without the query string or hash. null during server rendering.
deviceType
Phone, Tablet, TV, or Desktop.
deviceBrand, deviceModel
Detected from the browser's user agent. 'none' when unknown.
operatingSystem, osVersion
Detected from the browser's user agent. 'none' when unknown.
screenResolution
The browser viewport size as <width>x<height> in CSS pixels. null during server rendering.
The callback runs when enableUserActivityTracking is enabled. Storyteller
server delivery also follows enableFunctionalCookies and
enableStorytellerTracking. See Control privacy and tracking
for these settings.
Use context to record where on your site an event came from, such as the
page and module. context?: unknown contains host-defined attribution data.
The SDK does not prescribe its shape. It returns the configured value in
UserActivityData.context for events that it can attribute to the view and to
content opened from that view.
You can provide context through the configuration for:
The callback is delivered only when enableUserActivityTracking is enabled.
It omits context when the configured value is undefined. Explicit values
such as null, false, 0, and an empty string remain in the callback.
If a Story or Clip opens related content from an SDK action, the related player
events keep the source placement context. This applies to child Stories, Story
categories, Clips, and Clip collections. A direct hash URL or deep link has no
source placement, so the SDK uses the destination view's configured context or
omits the field.
The SDK returns context only to the delegate in the same browser client. It
does not add context to Storyteller analytics API requests. Your application
owns the value, its storage, and its transfer to any analytics provider. Keep
credentials and personal data out of this field.
The user tapped the background to dismiss the Story (on desktop)
closeButtonTapped
The user tapped close to dismiss the Story
swipedDown
The user swiped down to dismiss the Story
swipedFinalStory
The user swiped the final Story to dismiss it
swipedFirstStory
The user swiped the first Story to dismiss it
skippedFinalPage
The user tapped to skip the final Page of the final Story
backTapped
The user tapped the browser back button to dismiss the Story view
backButtonTapped
The user tapped the back button to dismiss the Clips player
completedFinalPage
The user completed the final Page of the final Story
instanceMethod
The player was dismissed programmatically using the dismissPlayer method
escapeKeyPressed
The user pressed the Esc key to dismiss the Story
windowUnload
The user navigated away by closing the page or entering a new URL in the browser bar
{"slug": "analytics", "page_title": "Integrate Analytics", "page_url": "Analytics/", "canonical_url": "/web/Analytics/", "markdown": "# Integrate analytics\n\n<!-- markdownlint-disable MD033 -->\n<span id=\"analytics-on-the-web-sdk\"><\/span>\n<!-- markdownlint-enable MD033 -->\n\nThe SDK reports what users do in Stories, Clips, Polls, Quizzes, and ads\nthrough the `onUserActivityOccurred` callback. This page shows how to receive\nthese events and forward them to your analytics tool, what the startup event\ncontains, and how to add placement context. The event pages list every event\nand its fields.\n\n## Receive events {#receive-events}\n\nAdd an `onUserActivityOccurred` callback to `Storyteller.sharedInstance.delegate`\nbefore you call `initialize`, so you also receive the\n[startup event](#sdk-initialization). The callback receives the event type and\nan object with the event's fields.\n\n```javascript\nStoryteller.sharedInstance.delegate = {\n onUserActivityOccurred: (type, data) => {\n analytics.track(type, data);\n },\n};\n\nawait Storyteller.sharedInstance.initialize('demo-api-key');\n```\n\nReplace `analytics.track` with the call your analytics tool uses. To handle one\nevent type, compare `type` with a `Storyteller.ActivityType` value, for example\n`Storyteller.ActivityType.openedStory`. In TypeScript, the delegate type is\n`IStorytellerDelegate`.\n\nAssigning `Storyteller.sharedInstance.delegate` replaces all four global\ncallbacks: `onUserActivityOccurred`, `onShareButtonTapped`, `getAdConfig`, and\n`userNavigatedToApp`. Define all your callbacks in one object, or spread the\ncurrent delegate:\n\n```javascript\nStoryteller.sharedInstance.delegate = {\n ...Storyteller.sharedInstance.delegate,\n onUserActivityOccurred: (type, data) => {\n analytics.track(type, data);\n },\n};\n```\n\nThe SDK calls `onUserActivityOccurred` only when `enableUserActivityTracking`\nis `true`, which is the default. Ad events also need `enableAdTracking`. When\n`enableFullVideoAnalytics` is `false`, content IDs and titles are `null`. See\n[Control privacy and tracking](PrivacyAndTracking.md) for these options.\n\nThe Storyteller Web Showcase handles these events in\n[`onUserActivityOccurred`](https://github.com/getstoryteller/storyteller-showcase-web/blob/11.0.0/nextjs/src/components/contexts/storytellerSdkDelegate.ts#L60).\n[Handle global callbacks](StorytellerDelegate.md) describes the other\ncallbacks on the delegate.\n\n## Event types\n\nThe SDK sends these kinds of events:\n\n- [SDK initialization](#sdk-initialization)\n- [Story Events](analytics/StoryEvents.md)\n- [Poll Events](analytics/PollEvents.md)\n- [Quiz Events](analytics/QuizEvents.md)\n- [Clip Events](analytics/ClipEvents.md)\n- [Ad Events](analytics/AdEvents.md)\n\nEach event page lists:\n\n- the events of that kind\n- when each event is recorded\n- the fields sent with each event\n\n## SDK initialization\n\nThe SDK sends `sdkInitialized` (`Storyteller.ActivityType.sdkInitialized`) when\nan `initialize` call gets the result of the settings request for your tenant:\n\n- `initializationSucceeded` is `true` when the settings load. Later\n `initialize` calls after a successful one don't send the event again.\n- `initializationSucceeded` is `false` when the settings request fails. The\n `initialize` promise then rejects.\n\n`initialize` rejects without sending `sdkInitialized` when the API key is\nmissing, when the SDK can't save the user ID, or when the request for the\nuser's viewing history fails. With the default privacy options, the SDK waits\nfor the viewing history before the settings, so an invalid API key or a network\noutage usually fails that request first. Handle startup failures in the\n`catch` block of `initialize`, not with this event.\n\nSet the delegate before you call `initialize` to receive this event.\n\n```javascript\nStoryteller.sharedInstance.delegate = {\n onUserActivityOccurred: (type, data) => {\n if (type === Storyteller.ActivityType.sdkInitialized) {\n console.log(data.initializationSucceeded);\n }\n },\n};\n```\n\nThe event contains the following properties:\n\n| Property | Value |\n| --- | --- |\n| `initializationSucceeded` | `true` or `false`. |\n| `enableAdTracking`, `enableFullVideoAnalytics`, `enablePersonalization`, `enableRemoteViewingStore`, `enableStorytellerTracking`, `enableUserActivityTracking` | The tracking options in effect. `enablePersonalization` and `enableStorytellerTracking` are `false` when `enableFunctionalCookies` is `false`. The event doesn't include `enableFunctionalCookies` or `disabledFunctionalFeatures`. |\n| `appId` | The page origin and path, for example `https://www.example.com/news`, without the query string or hash. `null` during server rendering. |\n| `deviceType` | `Phone`, `Tablet`, `TV`, or `Desktop`. |\n| `deviceBrand`, `deviceModel` | Detected from the browser's user agent. `'none'` when unknown. |\n| `operatingSystem`, `osVersion` | Detected from the browser's user agent. `'none'` when unknown. |\n| `screenResolution` | The browser viewport size as `<width>x<height>` in CSS pixels. `null` during server rendering. |\n\nThe callback runs when `enableUserActivityTracking` is enabled. Storyteller\nserver delivery also follows `enableFunctionalCookies` and\n`enableStorytellerTracking`. See [Control privacy and tracking](PrivacyAndTracking.md)\nfor these settings.\n\n<!-- markdownlint-disable MD033 -->\n<span id=\"integration-context\"><\/span>\n<!-- markdownlint-enable MD033 -->\n\n## Add placement context to events {#context}\n\nUse `context` to record where on your site an event came from, such as the\npage and module. `context?: unknown` contains host-defined attribution data.\nThe SDK does not prescribe its shape. It returns the configured value in\n`UserActivityData.context` for events that it can attribute to the view and to\ncontent opened from that view.\n\nYou can provide context through the configuration for:\n\n- `StorytellerStoriesRowView`\n- `StorytellerStoriesGridView`\n- `StorytellerClipsRowView`\n- `StorytellerClipsGridView`\n- `StorytellerClipsPlayerView`\n- `StorytellerEmbeddedClipsPlayerView`\n\n```typescript\nconst storiesRow = new Storyteller.StorytellerStoriesRowView('stories-row');\nconst analyticsContext = {\n location: 'home',\n module: 'top-stories',\n sortOrder: 10,\n};\n\nstoriesRow.configuration = {\n context: analyticsContext,\n};\n\nStoryteller.sharedInstance.delegate = {\n onUserActivityOccurred: (type, data) => {\n console.log(type, data.context);\n },\n};\n```\n\nYou can replace the value while the view is mounted. Reassign the\n`configuration` object with the new value:\n\n```javascript\nstoriesRow.configuration = {\n context: {\n location: 'sports',\n module: 'latest-stories',\n },\n};\n```\n\nThe callback is delivered only when `enableUserActivityTracking` is enabled.\nIt omits `context` when the configured value is `undefined`. Explicit values\nsuch as `null`, `false`, `0`, and an empty string remain in the callback.\n\nIf a Story or Clip opens related content from an SDK action, the related player\nevents keep the source placement context. This applies to child Stories, Story\ncategories, Clips, and Clip collections. A direct hash URL or deep link has no\nsource placement, so the SDK uses the destination view's configured context or\nomits the field.\n\nThe SDK returns context only to the delegate in the same browser client. It\ndoes not add context to Storyteller analytics API requests. Your application\nowns the value, its storage, and its transfer to any analytics provider. Keep\ncredentials and personal data out of this field.\n\n## Event data\n\n### OpenedReason\n\nThe action which the user took to open the Story:\n\n| Value | Description |\n| ------------------- | ------------------------------------------------------------------------ |\n| `storyListTap` | The user tapped the Story in the list |\n| `deepLink` | The user navigated directly to a Story URL |\n| `swipe` | The user swiped left or right to change the Story |\n| `automaticPlayback` | The previous Page finished, and the player moved on to the next one |\n| `tap` | The user tapped to navigate |\n\nor Clip:\n\n| Value | Description |\n| ----------------- | --------------------------------------------------- |\n| `clipListTap` | The user tapped the Clip in the list |\n| `categoryListTap` | The user tapped a Clip Category label |\n| `categoryBackTap` | The user tapped the back button in a Clip Category |\n| `deepLink` | The user navigated directly to a Clip URL |\n| `swipe` | The user swiped to the next or previous Clip |\n\n### DismissedReason\n\nThe reason the Story or Clip was dismissed:\n\n| Value | Description |\n| -------------------- | ------------------------------------------------------------------------------------ |\n| `backgroundTapped` | The user tapped the background to dismiss the Story (on desktop) |\n| `closeButtonTapped` | The user tapped close to dismiss the Story |\n| `swipedDown` | The user swiped down to dismiss the Story |\n| `swipedFinalStory` | The user swiped the final Story to dismiss it |\n| `swipedFirstStory` | The user swiped the first Story to dismiss it |\n| `skippedFinalPage` | The user tapped to skip the final Page of the final Story |\n| `backTapped` | The user tapped the browser back button to dismiss the Story view |\n| `backButtonTapped` | The user tapped the back button to dismiss the Clips player |\n| `completedFinalPage` | The user completed the final Page of the final Story |\n| `instanceMethod` | The player was dismissed programmatically using the `dismissPlayer` method |\n| `escapeKeyPressed` | The user pressed the `Esc` key to dismiss the Story |\n| `windowUnload` | The user navigated away by closing the page or entering a new URL in the browser bar |\n", "copy_markdown_include_header": false, "base_path": "", "ai_dir": "ai", "missing_payload_behavior": "empty"}