Move your web app from @stringboot/web-sdk 2.x to 3.0
This upgrade is required. The endpoints Web SDK 2.x uses now answer 426 Upgrade Required. Sites running 2.x keep showing what they cached but receive no further updates until you deploy 3.0.1 or later.
Pass your App’s Client Token (sb_...) as apiToken. Create one in the dashboard (see API Tokens). The token now travels in the URL path, not in an X-API-Token or Authorization header. A Figma Plugin Token, or a revoked or expired token, gets 401 invalid_token.
This is the change most likely to affect your code. With a Catalog stored from an earlier visit, initialize() now resolves as soon as that Catalog is applied; the /languages and version checks finish in the background. On a first visit it still waits for the download.If your code assumes “initialize() resolved” means “synced with the server”, wait for the start-up checks explicitly:
await StringBoot.initialize({ apiToken: 'sb_YOUR_CLIENT_TOKEN' });await StringBoot.waitForStartupSync(); // never rejects
Errors found after start-up, such as a rejected token, arrive through onSyncError. In React, useStringBoot().error reports them too.
const off = StringBoot.onSyncError((error) => { if (error.code === 'INVALID_TOKEN') showTokenBanner();});
Every request carries a Device-ID, generated and stored by the SDK. Pass deviceId only to use your own.
FAQs
Come with the Catalog. Remove StringBoot.FAQ.initialize(...); it’s accepted but does nothing once the SDK is initialized.
Experiments
Bucketed in the browser with the same function the server used. 2.x didn’t send a Device-ID, so web users get a new one and may land in a different variant once; pass your previous user id as deviceId if you need continuity. onExperimentsAssigned still works and is now called with {} when experiments stop. Add onExposure to report exposures.
Periodic checks
New: every 60 seconds by default (refreshInterval), paused while the tab is hidden.
Fallback
A key missing from the selected language falls back to the App’s default language before ??key??.
Escapes
\n, \t, \r, \", \' and \\ in string values are unescaped, as on mobile. Use white-space: pre-line to show line breaks.
Language codes
Matched exactly as listed in the dashboard (for example pt-BR), no longer cut to two letters. ActiveLanguage gains nativeName and direction.
React
useString and useStrings render the cached value on their first render instead of briefly showing ??key??.
Code that needs fresh server data waits for waitForStartupSync()
Errors after start-up are handled with onSyncError (or useStringBoot().error)
Analytics code handles an empty assignments object
StringBoot.FAQ.initialize(...) calls are removed
A first visit shows your strings, and an edit in the dashboard appears within about two minutes
{"docsConfig":{"theme":"mint","$schema":"https://mintlify.com/docs.json","name":"Stringboot","colors":{"primary":"#FE5D05","light":"#FE5D05","dark":"#FE5D05"},"logo":{"light":"https://mintcdn.com/axtrix/hVBwPPEDUAlpzqlF/logo/light.svg?fit=max\u0026auto=format\u0026n=hVBwPPEDUAlpzqlF\u0026q=85\u0026s=1fb4c7ebf229f835a8b67213caff81dd","dark":"https://mintcdn.com/axtrix/hVBwPPEDUAlpzqlF/logo/dark.svg?fit=max\u0026auto=format\u0026n=hVBwPPEDUAlpzqlF\u0026q=85\u0026s=eedb5363d16f1357f3e46720e33181c5"},"favicon":"https://mintcdn.com/axtrix/o6XopbE98ax70pkd/favicon.svg?fit=max\u0026auto=format\u0026n=o6XopbE98ax70pkd\u0026q=85\u0026s=1dfced41372bb6d16ecb343d32fe5618","navbar":{"links":[{"href":"https://dashboard.stringboot.com/tokens","label":"Get API Key"}],"primary":{"type":"button","label":"Signup","href":"https://dashboard.stringboot.com"}},"footer":{"socials":{"github":"https://github.com/Stringboot-SDK","linkedin":"https://linkedin.com/company/stringboot"}},"contextual":{"options":["copy","view","chatgpt","claude","perplexity","mcp","cursor","vscode"],"display":"header"},"styling":{"latex":true},"navigation":{"global":{"anchors":[{"anchor":"Support","icon":"envelope","href":"mailto:developer@stringboot.com"}]},"pages":[]}},"deployment":{"deploymentMetadataValue":{"subdomain":"axtrix","hasAudioNarration":false,"actualSubdomain":"axtrix","customDomains":["docs.stringboot.com"],"gitSource":{"type":"github","owner":"rajanndube","repo":"stringboot-integration-docs","deployBranch":"main","contentDirectory":"","isPrivate":true,"mountPath":"","label":""},"entitlements":{},"buildId":"6af0740981c47cb9967d022e","clientVersion":"0.0.4087","searchFilterCounts":[{"language":"default","tag":"Documentation","count":37},{"language":"default","tag":"Web SDK","count":10},{"language":"default","tag":"Dashboard","count":9},{"language":"default","tag":"Android SDK","count":7},{"language":"default","tag":"iOS SDK","count":7},{"language":"default","tag":"Cookbook","count":4},{"language":"default","tag":"Getting Started","count":4},{"language":"default","tag":"Recipes","count":3},{"language":"default","tag":"Overview","count":1}]},"assistantConfig":{"enableAskAiButton":false,"enableStarterQuestions":false,"enableAskAiSearchBar":true},"basePath":"","hasChatPermissions":false,"hasWebMcpPermissions":false,"toggles":[{"name":"kill-isr","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"agent-mintlify-slack","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"agent-integrations-settings","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"rbac-expansion","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automations-pr-grouping","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"custom-prefix","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"analytics-v7","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"user-flows-analytics","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"no-publish-flow","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-onboarding","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"llms-txt-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"snapshot-serving-live","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"stripTemperatureMiddleware","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"support-platform-pylon-zendesk","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"snapshot-serving","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"instant-rollback","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"granular-notifications-server","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"granular-notifications","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automations-fable","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"fixed-ai-action-pricing","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automation-resolve-merge-conflict","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"scoped-publishing","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"mintql","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"page-level-analytics","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"editor-version-history-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"billing-page-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"full-page-search","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workspace-projects","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"assistant-v5","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"fork-pr-previews","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"revalidation-jwt","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-sso-scim","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"hobby-abuse-scan","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"dashboard-inbox","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-signup","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"turbopuffer-dual-write","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-enabled","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"approve-review-flow","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"editor-metadata","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"sso-setup-deadline-banner","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"turbopuffer-serve","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"live-agents","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"comment-mode","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false}],"googleFontsInlined":false},"customCss":[],"page":{"pagePath":"web-sdk/upgrading","slug":"/web-sdk/upgrading","pageMetadata":{"title":"Migrating from 2.x","description":"Move your web app from @stringboot/web-sdk 2.x to 3.0","icon":"arrow-up","href":"/web-sdk/upgrading"},"description":{"compiledSource":"\"use strict\";\nconst {jsx: _jsx} = arguments[0];\nconst {useMDXComponents: _provideComponents} = arguments[0];\nfunction _createMdxContent(props) {\n const _components = {\n p: \"p\",\n ..._provideComponents(),\n ...props.components\n };\n return _jsx(_components.p, {\n children: \"Move your web app from @stringboot/web-sdk 2.x to 3.0\"\n });\n}\nfunction MDXContent(props = {}) {\n const {wrapper: MDXLayout} = {\n ..._provideComponents(),\n ...props.components\n };\n return MDXLayout ? _jsx(MDXLayout, {\n ...props,\n children: _jsx(_createMdxContent, {\n ...props\n })\n }) : _createMdxContent(props);\n}\nreturn {\n default: MDXContent\n};\n","frontmatter":{},"scope":{}},"pageType":"default","mdx":{"mdxSource":{"compiledSource":"\"use strict\";const{Fragment:_Fragment,jsx:_jsx,jsxs:_jsxs}=arguments[0];const{useMDXComponents:_provideComponents}=arguments[0];function _createMdxContent(props){const _components={a:`a`,code:`code`,hr:`hr`,input:`input`,li:`li`,p:`p`,pre:`pre`,span:`span`,strong:`strong`,tbody:`tbody`,td:`td`,th:`th`,thead:`thead`,tr:`tr`,ul:`ul`,..._provideComponents(),...props.components},{CodeBlock,Heading,Table,Warning}=_components;if(!CodeBlock)_missingMdxReference(`CodeBlock`,true);if(!Heading)_missingMdxReference(`Heading`,true);if(!Table)_missingMdxReference(`Table`,true);if(!Warning)_missingMdxReference(`Warning`,true);return _jsxs(_Fragment,{children:[_jsx(_components.hr,{}),`\n`,_jsx(Warning,{children:_jsxs(_components.p,{children:[_jsx(_components.strong,{children:`This upgrade is required.`}),` The endpoints Web SDK 2.x uses now answer `,_jsx(_components.code,{children:`426 Upgrade Required`}),`. Sites running 2.x keep showing what they cached but receive no further updates until you deploy 3.0.1 or later.`]})}),`\n`,_jsx(Heading,{level:`2`,id:`1-update-the-package`,children:`1. Update the package`}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`1`,language:`shellscript`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`shellscript`,children:_jsxs(_components.code,{language:`shellscript`,numberOfLines:`1`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#DCDCAA`},children:`npm`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` install`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` @stringboot/web-sdk@^3.0.1`})]}),`\n`]})})}),`\n`,_jsx(Heading,{level:`2`,id:`2-use-a-client-token`,children:`2. Use a Client Token`}),`\n`,_jsxs(_components.p,{children:[`Pass your App’s `,_jsx(_components.strong,{children:`Client Token`}),` (`,_jsx(_components.code,{children:`sb_...`}),`) as `,_jsx(_components.code,{children:`apiToken`}),`. Create one in the dashboard (see `,_jsx(_components.a,{href:`/dashboard-guides/api-tokens`,children:`API Tokens`}),`). The token now travels in the URL path, not in an `,_jsx(_components.code,{children:`X-API-Token`}),` or `,_jsx(_components.code,{children:`Authorization`}),` header. A Figma Plugin Token, or a revoked or expired token, gets `,_jsx(_components.code,{children:`401 invalid_token`}),`.`]}),`\n`,_jsx(Heading,{level:`2`,id:`3-review-the-behaviour-changes`,children:`3. Review the behaviour changes`}),`\n`,_jsxs(Heading,{level:`3`,id:`initialize-resolves-earlier`,children:[_jsx(_components.code,{children:`initialize()`}),` resolves earlier`]}),`\n`,_jsxs(_components.p,{children:[`This is the change most likely to affect your code. With a Catalog stored from an earlier visit, `,_jsx(_components.code,{children:`initialize()`}),` now resolves `,_jsx(_components.strong,{children:`as soon as that Catalog is applied`}),`; the `,_jsx(_components.code,{children:`/languages`}),` and version checks finish in the background. On a first visit it still waits for the download.`]}),`\n`,_jsxs(_components.p,{children:[`If your code assumes “`,_jsx(_components.code,{children:`initialize()`}),` resolved” means “synced with the server”, wait for the start-up checks explicitly:`]}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`2`,language:`javascript`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`javascript`,children:_jsxs(_components.code,{language:`javascript`,numberOfLines:`2`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#C586C0`},children:`await`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:` StringBoot`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`.`}),_jsx(_components.span,{style:{color:`#8250DF`,\"--shiki-dark\":`#DCDCAA`},children:`initialize`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`({ `}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`apiToken:`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` 'sb_YOUR_CLIENT_TOKEN'`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` });`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#C586C0`},children:`await`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:` StringBoot`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`.`}),_jsx(_components.span,{style:{color:`#8250DF`,\"--shiki-dark\":`#DCDCAA`},children:`waitForStartupSync`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`(); `}),_jsx(_components.span,{style:{color:`#6E7781`,\"--shiki-dark\":`#6A9955`},children:`// never rejects`})]}),`\n`]})})}),`\n`,_jsxs(_components.p,{children:[`Errors found after start-up, such as a rejected token, arrive through `,_jsx(_components.code,{children:`onSyncError`}),`. In React, `,_jsx(_components.code,{children:`useStringBoot().error`}),` reports them too.`]}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`3`,language:`javascript`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`javascript`,children:_jsxs(_components.code,{language:`javascript`,numberOfLines:`3`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#569CD6`},children:`const`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#4FC1FF`},children:` off`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:` =`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:` StringBoot`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`.`}),_jsx(_components.span,{style:{color:`#8250DF`,\"--shiki-dark\":`#DCDCAA`},children:`onSyncError`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`((`}),_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#9CDCFE`},children:`error`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`) `}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#569CD6`},children:`=>`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` {`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#C586C0`},children:` if`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` (`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`error`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`.`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`code`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:` ===`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` 'INVALID_TOKEN'`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`) `}),_jsx(_components.span,{style:{color:`#8250DF`,\"--shiki-dark\":`#DCDCAA`},children:`showTokenBanner`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`();`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`});`})}),`\n`]})})}),`\n`,_jsx(Heading,{level:`3`,id:`other-changes`,children:`Other changes`}),`\n`,_jsxs(Table,{children:[_jsx(_components.thead,{children:_jsxs(_components.tr,{children:[_jsx(_components.th,{style:{textAlign:`left`},children:`Area`}),_jsx(_components.th,{style:{textAlign:`left`},children:`What changed`})]})}),_jsxs(_components.tbody,{children:[_jsxs(_components.tr,{children:[_jsx(_components.td,{style:{textAlign:`left`},children:_jsx(_components.strong,{children:`Device-ID`})}),_jsxs(_components.td,{style:{textAlign:`left`},children:[`Every request carries a `,_jsx(_components.code,{children:`Device-ID`}),`, generated and stored by the SDK. Pass `,_jsx(_components.code,{children:`deviceId`}),` only to use your own.`]})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{style:{textAlign:`left`},children:_jsx(_components.strong,{children:`FAQs`})}),_jsxs(_components.td,{style:{textAlign:`left`},children:[`Come with the Catalog. Remove `,_jsx(_components.code,{children:`StringBoot.FAQ.initialize(...)`}),`; it’s accepted but does nothing once the SDK is initialized.`]})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{style:{textAlign:`left`},children:_jsx(_components.strong,{children:`Experiments`})}),_jsxs(_components.td,{style:{textAlign:`left`},children:[`Bucketed in the browser with the same function the server used. 2.x didn’t send a Device-ID, so web users get a new one and may land in a different variant once; pass your previous user id as `,_jsx(_components.code,{children:`deviceId`}),` if you need continuity. `,_jsx(_components.code,{children:`onExperimentsAssigned`}),` still works and is now called with `,_jsx(_components.code,{children:`{}`}),` when experiments stop. Add `,_jsx(_components.code,{children:`onExposure`}),` to report exposures.`]})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{style:{textAlign:`left`},children:_jsx(_components.strong,{children:`Periodic checks`})}),_jsxs(_components.td,{style:{textAlign:`left`},children:[`New: every 60 seconds by default (`,_jsx(_components.code,{children:`refreshInterval`}),`), paused while the tab is hidden.`]})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{style:{textAlign:`left`},children:_jsx(_components.strong,{children:`Fallback`})}),_jsxs(_components.td,{style:{textAlign:`left`},children:[`A key missing from the selected language falls back to the App’s default language before `,_jsx(_components.code,{children:`??key??`}),`.`]})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{style:{textAlign:`left`},children:_jsx(_components.strong,{children:`Escapes`})}),_jsxs(_components.td,{style:{textAlign:`left`},children:[_jsx(_components.code,{children:`\\\\n`}),`, `,_jsx(_components.code,{children:`\\\\t`}),`, `,_jsx(_components.code,{children:`\\\\r`}),`, `,_jsx(_components.code,{children:`\\\\\"`}),`, `,_jsx(_components.code,{children:`\\\\'`}),` and `,_jsx(_components.code,{children:`\\\\\\\\`}),` in string values are unescaped, as on mobile. Use `,_jsx(_components.code,{children:`white-space: pre-line`}),` to show line breaks.`]})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{style:{textAlign:`left`},children:_jsx(_components.strong,{children:`Language codes`})}),_jsxs(_components.td,{style:{textAlign:`left`},children:[`Matched exactly as listed in the dashboard (for example `,_jsx(_components.code,{children:`pt-BR`}),`), no longer cut to two letters. `,_jsx(_components.code,{children:`ActiveLanguage`}),` gains `,_jsx(_components.code,{children:`nativeName`}),` and `,_jsx(_components.code,{children:`direction`}),`.`]})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{style:{textAlign:`left`},children:_jsx(_components.strong,{children:`React`})}),_jsxs(_components.td,{style:{textAlign:`left`},children:[_jsx(_components.code,{children:`useString`}),` and `,_jsx(_components.code,{children:`useStrings`}),` render the cached value on their first render instead of briefly showing `,_jsx(_components.code,{children:`??key??`}),`.`]})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{style:{textAlign:`left`},children:_jsx(_components.strong,{children:`Integrity checks`})}),_jsxs(_components.td,{style:{textAlign:`left`},children:[_jsx(_components.code,{children:`enableIntegrityCheck`}),` is accepted and ignored.`]})]})]})]}),`\n`,_jsx(Heading,{level:`3`,id:`removed-types`,children:`Removed types`}),`\n`,_jsxs(_components.p,{children:[_jsx(_components.code,{children:`MetaResponse`}),`, `,_jsx(_components.code,{children:`DeltaResponse`}),`, `,_jsx(_components.code,{children:`CatalogResponse`}),`, `,_jsx(_components.code,{children:`ApiResponse`}),`, `,_jsx(_components.code,{children:`SyncMetadata`}),`, `,_jsx(_components.code,{children:`CachedString`}),`, `,_jsx(_components.code,{children:`FAQMetaResponse`}),`, `,_jsx(_components.code,{children:`FAQDeltaResponse`}),` and `,_jsx(_components.code,{children:`FAQCatalogResponse`}),`. Use `,_jsx(_components.code,{children:`Catalog`}),`, `,_jsx(_components.code,{children:`LanguagesResponse`}),` and `,_jsx(_components.code,{children:`CurrentVersionResponse`}),` instead.`]}),`\n`,_jsx(Heading,{level:`2`,id:`what-happens-to-returning-visitors`,children:`What happens to returning visitors`}),`\n`,_jsx(_components.p,{children:`On the first start, 3.0 deletes the data 2.x stored in the browser and downloads the strings once.`}),`\n`,_jsx(Heading,{level:`2`,id:`checklist`,children:`Checklist`}),`\n`,_jsxs(_components.ul,{className:`contains-task-list`,children:[`\n`,_jsxs(_components.li,{className:`task-list-item`,children:[_jsx(_components.input,{type:`checkbox`,disabled:true}),` `,_jsx(_components.code,{children:`@stringboot/web-sdk`}),` is `,_jsx(_components.code,{children:`3.0.1`}),` or later`]}),`\n`,_jsxs(_components.li,{className:`task-list-item`,children:[_jsx(_components.input,{type:`checkbox`,disabled:true}),` `,_jsx(_components.code,{children:`apiToken`}),` is a Client Token starting with `,_jsx(_components.code,{children:`sb_`})]}),`\n`,_jsxs(_components.li,{className:`task-list-item`,children:[_jsx(_components.input,{type:`checkbox`,disabled:true}),` `,`Code that needs fresh server data waits for `,_jsx(_components.code,{children:`waitForStartupSync()`})]}),`\n`,_jsxs(_components.li,{className:`task-list-item`,children:[_jsx(_components.input,{type:`checkbox`,disabled:true}),` `,`Errors after start-up are handled with `,_jsx(_components.code,{children:`onSyncError`}),` (or `,_jsx(_components.code,{children:`useStringBoot().error`}),`)`]}),`\n`,_jsxs(_components.li,{className:`task-list-item`,children:[_jsx(_components.input,{type:`checkbox`,disabled:true}),` `,`Analytics code handles an empty assignments object`]}),`\n`,_jsxs(_components.li,{className:`task-list-item`,children:[_jsx(_components.input,{type:`checkbox`,disabled:true}),` `,_jsx(_components.code,{children:`StringBoot.FAQ.initialize(...)`}),` calls are removed`]}),`\n`,_jsxs(_components.li,{className:`task-list-item`,children:[_jsx(_components.input,{type:`checkbox`,disabled:true}),` `,`A first visit shows your strings, and an edit in the dashboard appears within about two minutes`]}),`\n`]})]})}function MDXContent(props={}){const{wrapper:MDXLayout}={..._provideComponents(),...props.components};return MDXLayout?_jsx(MDXLayout,{...props,children:_jsx(_createMdxContent,{...props})}):_createMdxContent(props)}return{default:MDXContent};function _missingMdxReference(id,component){throw new Error(`Expected `+(component?`component`:`object`)+\" `\"+id+\"` to be defined: you likely forgot to import, pass, or provide it.\")}","frontmatter":{},"scope":{"config":{},"pageMetadata":{"title":"Migrating from 2.x","description":"Move your web app from @stringboot/web-sdk 2.x to 3.0","icon":"arrow-up","href":"/web-sdk/upgrading"}}},"mdxSourceWithNoJs":null},"mdxExtracts":{"tableOfContents":[{"title":"1. Update the package","slug":"1-update-the-package","depth":2,"children":[]},{"title":"2. Use a Client Token","slug":"2-use-a-client-token","depth":2,"children":[]},{"title":"3. Review the behaviour changes","slug":"3-review-the-behaviour-changes","depth":2,"children":[{"title":"initialize() resolves earlier","slug":"initialize-resolves-earlier","depth":3,"children":[]},{"title":"Other changes","slug":"other-changes","depth":3,"children":[]},{"title":"Removed types","slug":"removed-types","depth":3,"children":[]}]},{"title":"What happens to returning visitors","slug":"what-happens-to-returning-visitors","depth":2,"children":[]},{"title":"Checklist","slug":"checklist","depth":2,"children":[]}],"codeExamples":{}},"jsLinks":[],"subdomain":"axtrix","siteName":"Stringboot","title":"Migrating from 2.x - Stringboot","navMaps":{"firstHrefInVersion":{},"firstHrefInLanguage":{}},"lastModified":"2026-11-08T12:58:35.230Z","originalFileLocation":"web-sdk/upgrading.mdx"},"headHtml":"\u003cscript data-mint-head>(function(){var d=document.documentElement,p=null;if(!p){try{p=localStorage.getItem(\"isDarkMode\")}catch(e){}if(p==='true')p='dark';else if(p==='false')p='light';if(p!=='light'\u0026\u0026p!=='dark'\u0026\u0026p!=='system')p=\"system\"}var r=p==='system'?(matchMedia(\"(prefers-color-scheme: dark)\").matches?'dark':'light'):p;d.classList.remove(r==='dark'?'light':'dark');d.classList.add(r);d.setAttribute(\"data-theme-preference\",p)})();\u003c/script>\u003cmeta data-mint-head name=\"description\" content=\"Move your web app from @stringboot/web-sdk 2.x to 3.0\">\u003cmeta data-mint-head name=\"application-name\" content=\"Stringboot\">\u003cmeta data-mint-head name=\"generator\" content=\"Mintlify\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"192x192\" href=\"/mintlify-assets/_mintlify/favicons/axtrix/69p3cWdK10hgwsZv/_generated/favicon/android-chrome-192x192.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"apple-touch-icon\" type=\"image/png\" sizes=\"180x180\" href=\"/mintlify-assets/_mintlify/favicons/axtrix/69p3cWdK10hgwsZv/_generated/favicon/apple-touch-icon.png\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"16x16\" href=\"/mintlify-assets/_mintlify/favicons/axtrix/69p3cWdK10hgwsZv/_generated/favicon/favicon-16x16.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"32x32\" href=\"/mintlify-assets/_mintlify/favicons/axtrix/69p3cWdK10hgwsZv/_generated/favicon/favicon-32x32.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"shortcut icon\" type=\"image/x-icon\" href=\"/mintlify-assets/_mintlify/favicons/axtrix/69p3cWdK10hgwsZv/_generated/favicon/favicon.ico\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"192x192\" href=\"/mintlify-assets/_mintlify/favicons/axtrix/69p3cWdK10hgwsZv/_generated/favicon-dark/android-chrome-192x192.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"16x16\" href=\"/mintlify-assets/_mintlify/favicons/axtrix/69p3cWdK10hgwsZv/_generated/favicon-dark/favicon-16x16.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"32x32\" href=\"/mintlify-assets/_mintlify/favicons/axtrix/69p3cWdK10hgwsZv/_generated/favicon-dark/favicon-32x32.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"shortcut icon\" type=\"image/x-icon\" href=\"/mintlify-assets/_mintlify/favicons/axtrix/69p3cWdK10hgwsZv/_generated/favicon-dark/favicon.ico\" media=\"(prefers-color-scheme: dark)\">\u003cmeta data-mint-head property=\"og:title\" content=\"Migrating from 2.x - Stringboot\">\u003cmeta data-mint-head property=\"og:description\" content=\"Move your web app from @stringboot/web-sdk 2.x to 3.0\">\u003cmeta data-mint-head property=\"og:site_name\" content=\"Stringboot\">\u003cmeta data-mint-head property=\"og:url\" content=\"https://docs.stringboot.com/web-sdk/upgrading\">\u003cmeta data-mint-head property=\"og:type\" content=\"website\">\u003cmeta data-mint-head property=\"og:image\" content=\"https://axtrix.mintlify.site/_mintlify/api/og/v2?division=Web+SDK\u0026amp;title=Migrating+from+2.x\u0026amp;description=Move+your+web+app+from+%40stringboot%2Fweb-sdk+2.x+to+3.0\u0026amp;theme=618367e953640250b01e8887\u0026amp;signature=e05d7e963037b72a254751f92dd553d0d5a952781ed3c014692bdc78772a71f7\">\u003cmeta data-mint-head property=\"og:image:width\" content=\"1200\">\u003cmeta data-mint-head property=\"og:image:height\" content=\"630\">\u003cmeta data-mint-head name=\"twitter:card\" content=\"summary_large_image\">\u003cmeta data-mint-head name=\"twitter:title\" content=\"Migrating from 2.x - Stringboot\">\u003cmeta data-mint-head name=\"twitter:description\" content=\"Move your web app from @stringboot/web-sdk 2.x to 3.0\">\u003cmeta data-mint-head name=\"twitter:image\" content=\"https://axtrix.mintlify.site/_mintlify/api/og/v2?division=Web+SDK\u0026amp;title=Migrating+from+2.x\u0026amp;description=Move+your+web+app+from+%40stringboot%2Fweb-sdk+2.x+to+3.0\u0026amp;theme=618367e953640250b01e8887\u0026amp;signature=e05d7e963037b72a254751f92dd553d0d5a952781ed3c014692bdc78772a71f7\">\u003cmeta data-mint-head name=\"twitter:image:width\" content=\"1200\">\u003cmeta data-mint-head name=\"twitter:image:height\" content=\"630\">\u003cmeta data-mint-head name=\"msapplication-config\" content=\"/mintlify-assets/_mintlify/favicons/axtrix/69p3cWdK10hgwsZv/_generated/favicon/browserconfig.xml\">\u003cmeta data-mint-head name=\"apple-mobile-web-app-title\" content=\"Stringboot\">\u003cmeta data-mint-head name=\"msapplication-TileColor\" content=\"#FE5D05\">\u003clink data-mint-head rel=\"canonical\" href=\"https://docs.stringboot.com/web-sdk/upgrading\">\u003clink data-mint-head rel=\"alternate\" type=\"application/xml\" href=\"/sitemap.xml\">\u003clink data-mint-head rel=\"alternate\" type=\"text/markdown\" href=\"/web-sdk/upgrading.md\">\u003cscript data-mint-head type=\"application/ld+json\">{\"@context\":\"https://schema.org\",\"@graph\":[{\"@type\":\"Organization\",\"@id\":\"https://docs.stringboot.com/#organization\",\"name\":\"Stringboot\",\"url\":\"https://docs.stringboot.com\",\"logo\":{\"@type\":\"ImageObject\",\"url\":\"https://mintcdn.com/axtrix/hVBwPPEDUAlpzqlF/logo/light.svg?fit=max\u0026auto=format\u0026n=hVBwPPEDUAlpzqlF\u0026q=85\u0026s=1fb4c7ebf229f835a8b67213caff81dd\"}},{\"@type\":\"WebSite\",\"@id\":\"https://docs.stringboot.com#website\",\"name\":\"Stringboot\",\"url\":\"https://docs.stringboot.com\",\"publisher\":{\"@id\":\"https://docs.stringboot.com/#organization\"}},{\"@type\":\"WebPage\",\"@id\":\"https://docs.stringboot.com/web-sdk/upgrading#webpage\",\"url\":\"https://docs.stringboot.com/web-sdk/upgrading\",\"name\":\"Migrating from 2.x\",\"description\":\"Move your web app from @stringboot/web-sdk 2.x to 3.0\",\"dateModified\":\"2026-11-08T12:58:35.230Z\",\"isPartOf\":{\"@id\":\"https://docs.stringboot.com#website\"},\"breadcrumb\":{\"@id\":\"https://docs.stringboot.com/web-sdk/upgrading#breadcrumb\"}},{\"@type\":\"BreadcrumbList\",\"@id\":\"https://docs.stringboot.com/web-sdk/upgrading#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Web SDK\",\"item\":\"https://docs.stringboot.com/web-sdk/index\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Migrating from 2.x\",\"item\":\"https://docs.stringboot.com/web-sdk/upgrading\"}]},{\"@type\":[\"Article\",\"TechArticle\"],\"@id\":\"https://docs.stringboot.com/web-sdk/upgrading#article\",\"headline\":\"Migrating from 2.x\",\"name\":\"Migrating from 2.x\",\"description\":\"Move your web app from @stringboot/web-sdk 2.x to 3.0\",\"url\":\"https://docs.stringboot.com/web-sdk/upgrading\",\"mainEntityOfPage\":{\"@id\":\"https://docs.stringboot.com/web-sdk/upgrading#webpage\"},\"dateModified\":\"2026-11-08T12:58:35.230Z\",\"publisher\":{\"@id\":\"https://docs.stringboot.com/#organization\"},\"isPartOf\":{\"@id\":\"https://docs.stringboot.com#website\"}}]}\u003c/script>\u003cscript data-mint-head type=\"application/ld+json\">{\"@context\":\"https://schema.org\",\"@type\":\"WebSite\",\"name\":\"Stringboot\",\"creator\":{\"@type\":\"Organization\",\"name\":\"Mintlify\",\"url\":\"https://mintlify.com\"}}\u003c/script>","siteName":"Stringboot","nav":{"global":{"anchors":[{"anchor":"Support","icon":"envelope","href":"mailto:developer@stringboot.com"}]},"tabs":[{"tab":"Documentation","icon":"book","groups":[{"group":"Getting Started","pages":[{"title":"Introduction","icon":"house","href":""},{"title":"Quickstart","icon":"rocket","href":"/quickstart"},{"title":"Core Concepts","icon":"layer-group","href":"/core-concepts"},{"title":"FAQ","icon":"question","href":"/faq"}]},{"group":"Android SDK","pages":[{"title":"Overview","icon":"android","href":"/android-sdk/index"},{"title":"Installation","icon":"download","href":"/android-sdk/installation"},{"title":"Upgrading from 1.x","icon":"arrow-up","href":"/android-sdk/upgrading"},{"title":"Basic Usage","icon":"code","href":"/android-sdk/usage"},{"title":"A/B Testing","icon":"flask","href":"/android-sdk/ab-testing"},{"title":"FAQ Provider","icon":"circle-question","href":"/android-sdk/faq-provider"},{"title":"Troubleshooting","icon":"wrench","href":"/android-sdk/troubleshooting"}]},{"group":"iOS SDK","pages":[{"title":"Overview","icon":"apple","href":"/ios-sdk/index"},{"title":"Installation","icon":"download","href":"/ios-sdk/installation"},{"title":"Migrating from 2.x","icon":"arrow-up","href":"/ios-sdk/upgrading"},{"title":"Basic Usage","icon":"code","href":"/ios-sdk/usage"},{"title":"A/B Testing","icon":"flask","href":"/ios-sdk/ab-testing"},{"title":"FAQ Provider","icon":"circle-question","href":"/ios-sdk/faq-provider"},{"title":"Troubleshooting","icon":"wrench","href":"/ios-sdk/troubleshooting"}]},{"group":"Web SDK","pages":[{"title":"Overview","icon":"js","href":"/web-sdk/index"},{"title":"Quick Start","description":"Install the Stringboot Web SDK 3.0, initialize it with your Client Token and show your first string","icon":"bolt","href":"/web-sdk/quickstart"},{"title":"Migrating from 2.x","icon":"arrow-up","href":"/web-sdk/upgrading"},{"title":"Vanilla JS","description":"Use the Stringboot Web SDK with plain JavaScript or TypeScript","icon":"js","href":"/web-sdk/vanilla-js"},{"title":"React","icon":"react","href":"/web-sdk/react"},{"title":"Vue.js","icon":"vuejs","href":"/web-sdk/vue"},{"title":"Next.js","icon":"server","href":"/web-sdk/nextjs"},{"title":"FAQ Provider","icon":"circle-question","href":"/web-sdk/faq-provider"},{"title":"Advanced Usage","icon":"layer-group","href":"/web-sdk/advanced"},{"title":"Troubleshooting","icon":"bug","href":"/web-sdk/troubleshooting"}]},{"group":"Dashboard","pages":[{"title":"Dashboard Overview","icon":"gauge","href":"/dashboard-guides/dashboard-overview"},{"title":"Authentication","icon":"lock","href":"/dashboard-guides/authentication"},{"title":"Applications","icon":"window-maximize","href":"/dashboard-guides/applications"},{"title":"Strings","icon":"font","href":"/dashboard-guides/strings"},{"title":"Languages","icon":"language","href":"/dashboard-guides/languages"},{"title":"Experiments","icon":"flask","href":"/dashboard-guides/experiments"},{"title":"FAQs","icon":"circle-question","href":"/dashboard-guides/faqs"},{"title":"API Tokens","icon":"key","href":"/dashboard-guides/api-tokens"},{"title":"Settings","icon":"gear","href":"/dashboard-guides/settings"}]}]},{"tab":"Cookbook","icon":"book-open","pages":[{"title":"Cookbook","href":"/cookbook"}]}]},"basePath":"","title":"Migrating from 2.x - Stringboot","buildId":"dpl_FWZhTb2vab28gFGFH4ojka6qEznQ","deploymentId":"dpl_FWZhTb2vab28gFGFH4ojka6qEznQ","dynamics":[],"chunks":[]}