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.
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.
typeofwindow.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.
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.
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.
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.
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.
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.
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.
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.
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.
Remove API keys, user IDs, tenant data, and ad-targeting values from logs and
screenshots.
{"slug": "getting-started-troubleshooting", "page_title": "Troubleshoot an Integration", "page_url": "getting-started/troubleshooting/", "canonical_url": "/web/getting-started/troubleshooting/", "markdown": "# Troubleshoot an integration\n\n<!-- markdownlint-disable MD033 -->\n<span id=\"troubleshoot-a-web-integration\"><\/span>\n\nUse this page when Storyteller doesn't appear, doesn't load, or doesn't behave\nas expected. Find the first step that fails, and fix it before you check later\nsteps.\n\n## Find your symptom {#find-your-symptom}\n\n| What you see | Start with |\n| --- | --- |\n| `window.Storyteller` is `undefined`, or your build can't find the package | [1. Confirm that the SDK loaded](#1-confirm-that-the-sdk-loaded) |\n| `initialize` rejects, or `isInitialized` stays `false` | [2. Confirm initialization](#2-confirm-initialization) |\n| The row or grid stays empty | [3. Check an empty row or grid](#3-check-an-empty-row-or-grid) |\n| Tiles appear, but a Story or Clip doesn't open or play | [4. Check player requests](#4-check-player-requests) |\n| A view breaks or appears twice after a route change | [5. Check page transitions](#5-check-page-transitions) |\n| A callback or analytics event doesn't arrive | [6. Check callbacks and analytics](#6-check-callbacks-and-analytics) |\n| A theme change has no effect | [7. Check themes](#7-check-themes) |\n| Ads don't appear | [8. Check ads](#8-check-ads) |\n\n## 1. Confirm that the SDK loaded\n\nFor a script integration, open the browser Network panel and find\n`storyteller.min.js`. The request must return JavaScript with a successful HTTP\nstatus.\n\nThen check the browser global.\n\n```javascript\ntypeof window.Storyteller;\n```\n\nThe result should be `\"object\"`.\n\nFor an npm integration, check the build output for a missing package or CSS\nimport. The application must include both imports from the\n[npm installation guide](npm.md).\n\n## 2. Confirm initialization\n\nCall `enableLogging()` in your page code before you call `initialize`. The SDK\nthen logs its warnings and request errors to the console.\n\n```javascript\nStoryteller.sharedInstance.enableLogging();\nawait Storyteller.sharedInstance.initialize('demo-api-key');\n```\n\nCheck the current state after the promise resolves.\n\n```javascript\nconsole.log({\n isInitialized: Storyteller.sharedInstance.isInitialized,\n version: Storyteller.sharedInstance.version,\n});\n```\n\n`isInitialized` should be `true`.\n\nIf `initialize` rejects, check the start of `error.message`. The SDK doesn't\nexport these error classes, and `error.name` is always `\"Error\"`.\n\n| Error message starts with | Check |\n| --- | --- |\n| `InvalidApiKeyError` | A request returned HTTP 401 or 404. Confirm that the key belongs to the intended Storyteller tenant. |\n| `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. |\n| `NetworkTimeoutError` | Check the network path, proxy, firewall, and request timeout. |\n\nWith the default privacy options, `initialize` requests the user's viewing\nhistory from Storyteller and waits for it. If a proxy or allowlist sits between\nthe browser and the Storyteller API, allow that request.\n\nIf the promise rejects with a text message instead of an `Error`, `initialize`\nwas called without an API key.\n\n## 3. Check an empty row or grid\n\nConfirm each item:\n\n- The container exists before you create the view.\n- Its ID is unique on the page.\n- The constructor receives the same ID.\n- The tenant has published content for the supplied Category or collection.\n- Page CSS does not hide the container or set its width to zero.\n\nSet a delegate with an `onDataLoadComplete` callback, as shown in\n[Check the result](../Quickstart.md#check-the-result). If `success` is `false`\nand `error.message` starts with `EmptyResponseError`, the request worked but\nreturned no Stories or Clips.\n\nRemove optional Category IDs from a Story view to check the default Home list.\nConfirm that the Story is published in that list.\n\n```javascript\nnew Storyteller.StorytellerStoriesRowView('storyteller-stories-row');\n```\n\nIf the row appears but its tiles have the wrong size, set a height on the row\ncontainer. Without one, the SDK uses a default tile height.\n\n## 4. Check player requests\n\nOpen a Story or Clip and inspect failed Network requests.\n\nThe script build downloads the Story player, Clips player, Poll, Quiz, and\ncaption files the first time a page needs them. These files load from the\ndirectory that served `storyteller.min.js`, and their names start with\n`storyteller.`, such as `storyteller.story-player.<hash>.min.js`. Check these\ncauses:\n\n- A file returns 404: if you host the SDK yourself, copy every file in the\n version's `dist` directory and keep the file names. See\n [Host the SDK files](script.md#host-the-sdk-files).\n- The console reports a Content Security Policy violation: allow scripts from\n the SDK directory. See\n [Content Security Policy](script.md#content-security-policy).\n- A proxy or ad blocker blocks a file.\n\nThe npm build includes this code in its own JavaScript file, so these requests\ndon't appear.\n\nRecord the first failed request and its HTTP status. Remove API keys, user IDs,\nand private query values before you share the request.\n\n## 5. Check page transitions\n\nDestroy each view before a single-page application removes its container.\n\n```javascript\nstoryRow.destroy();\n```\n\nDestroy the old view before you create a new one in the same container. Two\nviews on the page at the same time need different container IDs. Initialize\nthe SDK once for the page, as shown in\n[Use React or Next.js](react-nextjs.md#initialize-the-sdk-once).\n\n## 6. Check callbacks and analytics\n\nCheck the global delegate (`IStorytellerDelegate`):\n\n- Set `Storyteller.sharedInstance.delegate` before you call `initialize`. The\n `sdkInitialized` event is sent during `initialize`.\n- Each assignment replaces all four global callbacks: `onUserActivityOccurred`,\n `onShareButtonTapped`, `getAdConfig`, and `userNavigatedToApp`. A callback\n you leave out stops working. Define all callbacks in one object, or spread\n the current delegate.\n- `onUserActivityOccurred` receives events only when `enableUserActivityTracking`\n is `true`. Ad events also need `enableAdTracking`.\n- Each `eventTrackingOptions` assignment replaces all options. An option you\n leave out returns to its default.\n\n```javascript\nStoryteller.sharedInstance.delegate = {\n ...Storyteller.sharedInstance.delegate,\n getAdConfig: () => ({ slot: '/1234/your-ad-unit' }),\n};\n```\n\nFor a view delegate (`IListViewDelegate`), set `delegate` on the view object. A\nview starts loading while its constructor runs, so a delegate you assign after\n`new` doesn't receive the first `onDataLoadStarted` call. `onDataLoadComplete`\nstill arrives.\n\nSee [Handle delegates and callbacks](../delegates/index.md),\n[Integrate analytics](../Analytics.md), and\n[Control privacy and tracking](../PrivacyAndTracking.md).\n\n## 7. Check themes\n\n- A theme in a view's `configuration` is merged over the global theme\n (`Storyteller.sharedInstance.theme`) for that view only.\n- Each `initialize` call resets the global theme to its defaults. Set the\n global theme after `initialize` resolves, and set it again after a later\n `initialize` call, such as a user change.\n- `uiStyle` selects the light or dark theme. With `auto`, the default, the view\n follows the user's color scheme, so set both `theme.light` and `theme.dark`.\n- Storyteller sets some values for your tenant or feed in the remote theme,\n such as [caption styling](../Themes.md#closed-captions) and\n [compact Clip action buttons](../Themes.md#compact-clip-action-buttons).\n Your JavaScript theme doesn't change them. Ask Storyteller to change them.\n\nTest one clearly visible property on a single view before you combine\noverrides. See [Customize themes](../Themes.md).\n\n## 8. Check ads\n\nAsk Storyteller which ad source your tenant uses. Storyteller First Party Ads\nneed no code. For Google Ad Manager ads, check these items:\n\n- The SDK calls `getAdConfig` on the global delegate. It must return an object\n with a `slot` for both Story and Clip requests. `null` means no ad.\n- Clip ad requests have no `story` field. They contain `clip`, `nextClip`, and\n `collection`. A callback that reads `adRequestInfo.story` without a check\n throws for Clips.\n- The ad unit in `slot` must serve 1x1 ads.\n- A later delegate assignment can remove `getAdConfig`. See\n [step 6](#6-check-callbacks-and-analytics).\n- With `enableAdTracking: false`, ad requests don't include the current Story\n or Clip, so line items that target them might not match.\n\nSee [Integrate ads](../Ads.md).\n\n## Contact support\n\nSend [Storyteller Support](mailto:[email protected]) this information:\n\n- SDK version and installation method\n- Browser name and version\n- First error name and message\n- First failed request and HTTP status\n- Short steps that reproduce the issue\n\nRemove API keys, user IDs, tenant data, and ad-targeting values from logs and\nscreenshots.\n\n<!-- markdownlint-enable MD033 -->\n", "copy_markdown_include_header": false, "base_path": "", "ai_dir": "ai", "missing_payload_behavior": "empty"}