Skip to content

Troubleshoot an integration#

Use this page when Storyteller doesn't appear, doesn't load, or doesn't behave as expected. Find the first step that fails, and fix it before you check later steps.

Find your symptom#

What you see Start with
window.Storyteller is undefined, or your build can't find the package 1. Confirm that the SDK loaded
initialize rejects, or isInitialized stays false 2. Confirm initialization
The row or grid stays empty 3. Check an empty row or grid
Tiles appear, but a Story or Clip doesn't open or play 4. Check player requests
A view breaks or appears twice after a route change 5. Check page transitions
A callback or analytics event doesn't arrive 6. Check callbacks and analytics
A theme change has no effect 7. Check themes
Ads don't appear 8. Check ads

1. Confirm that the SDK loaded#

For a script integration, open the browser Network panel and find storyteller.min.js. The request must return JavaScript with a successful HTTP status.

Then check the browser global.

typeof window.Storyteller;

The result should be "object".

For an npm integration, check the build output for a missing package or CSS import. The application must include both imports from the npm installation guide.

2. Confirm initialization#

Call enableLogging() in your page code before you call initialize. The SDK then logs its warnings and request errors to the console.

Storyteller.sharedInstance.enableLogging();
await Storyteller.sharedInstance.initialize('demo-api-key');

Check the current state after the promise resolves.

console.log({
  isInitialized: Storyteller.sharedInstance.isInitialized,
  version: Storyteller.sharedInstance.version,
});

isInitialized should be true.

If initialize rejects, check the start of error.message. The SDK doesn't export these error classes, and error.name is always "Error".

Error message starts with Check
InvalidApiKeyError A request returned HTTP 401 or 404. Confirm that the key belongs to the intended Storyteller tenant.
NetworkError Inspect the settings request and the viewing-history request (GET /api/UserActivity/{userId}), their HTTP status, and the response body. Confirm that the settings response contains settings.
NetworkTimeoutError Check the network path, proxy, firewall, and request timeout.

With the default privacy options, initialize requests the user's viewing history from Storyteller and waits for it. If a proxy or allowlist sits between the browser and the Storyteller API, allow that request.

If the promise rejects with a text message instead of an Error, initialize was called without an API key.

3. Check an empty row or grid#

Confirm each item:

  • The container exists before you create the view.
  • Its ID is unique on the page.
  • The constructor receives the same ID.
  • The tenant has published content for the supplied Category or collection.
  • Page CSS does not hide the container or set its width to zero.

Set a delegate with an onDataLoadComplete callback, as shown in Check the result. If success is false and error.message starts with EmptyResponseError, the request worked but returned no Stories or Clips.

Remove optional Category IDs from a Story view to check the default Home list. Confirm that the Story is published in that list.

new Storyteller.StorytellerStoriesRowView('storyteller-stories-row');

If the row appears but its tiles have the wrong size, set a height on the row container. Without one, the SDK uses a default tile height.

4. Check player requests#

Open a Story or Clip and inspect failed Network requests.

The script build downloads the Story player, Clips player, Poll, Quiz, and caption files the first time a page needs them. These files load from the directory that served storyteller.min.js, and their names start with storyteller., such as storyteller.story-player.<hash>.min.js. Check these causes:

  • A file returns 404: if you host the SDK yourself, copy every file in the version's dist directory and keep the file names. See Host the SDK files.
  • The console reports a Content Security Policy violation: allow scripts from the SDK directory. See Content Security Policy.
  • A proxy or ad blocker blocks a file.

The npm build includes this code in its own JavaScript file, so these requests don't appear.

Record the first failed request and its HTTP status. Remove API keys, user IDs, and private query values before you share the request.

5. Check page transitions#

Destroy each view before a single-page application removes its container.

storyRow.destroy();

Destroy the old view before you create a new one in the same container. Two views on the page at the same time need different container IDs. Initialize the SDK once for the page, as shown in Use React or Next.js.

6. Check callbacks and analytics#

Check the global delegate (IStorytellerDelegate):

  • Set Storyteller.sharedInstance.delegate before you call initialize. The sdkInitialized event is sent during initialize.
  • Each assignment replaces all four global callbacks: onUserActivityOccurred, onShareButtonTapped, getAdConfig, and userNavigatedToApp. A callback you leave out stops working. Define all callbacks in one object, or spread the current delegate.
  • onUserActivityOccurred receives events only when enableUserActivityTracking is true. Ad events also need enableAdTracking.
  • Each eventTrackingOptions assignment replaces all options. An option you leave out returns to its default.
Storyteller.sharedInstance.delegate = {
  ...Storyteller.sharedInstance.delegate,
  getAdConfig: () => ({ slot: '/1234/your-ad-unit' }),
};

For a view delegate (IListViewDelegate), set delegate on the view object. A view starts loading while its constructor runs, so a delegate you assign after new doesn't receive the first onDataLoadStarted call. onDataLoadComplete still arrives.

See Handle delegates and callbacks, Integrate analytics, and Control privacy and tracking.

7. Check themes#

  • A theme in a view's configuration is merged over the global theme (Storyteller.sharedInstance.theme) for that view only.
  • Each initialize call resets the global theme to its defaults. Set the global theme after initialize resolves, and set it again after a later initialize call, such as a user change.
  • uiStyle selects the light or dark theme. With auto, the default, the view follows the user's color scheme, so set both theme.light and theme.dark.
  • Storyteller sets some values for your tenant or feed in the remote theme, such as caption styling and compact Clip action buttons. Your JavaScript theme doesn't change them. Ask Storyteller to change them.

Test one clearly visible property on a single view before you combine overrides. See Customize themes.

8. Check ads#

Ask Storyteller which ad source your tenant uses. Storyteller First Party Ads need no code. For Google Ad Manager ads, check these items:

  • The SDK calls getAdConfig on the global delegate. It must return an object with a slot for both Story and Clip requests. null means no ad.
  • Clip ad requests have no story field. They contain clip, nextClip, and collection. A callback that reads adRequestInfo.story without a check throws for Clips.
  • The ad unit in slot must serve 1x1 ads.
  • A later delegate assignment can remove getAdConfig. See step 6.
  • With enableAdTracking: false, ad requests don't include the current Story or Clip, so line items that target them might not match.

See Integrate ads.

Contact support#

Send Storyteller Support this information:

  • SDK version and installation method
  • Browser name and version
  • First error name and message
  • First failed request and HTTP status
  • Short steps that reproduce the issue

Remove API keys, user IDs, tenant data, and ad-targeting values from logs and screenshots.