Coveo Online Search Guide

Updated: 2026-09-23 23:31 ET · Audited: pending · Work item: AB#2562

TLDR. Online search embeds Coveo's Atomic web components in the Blazor Hybrid webview. Atomic needs a short-lived search token that only a backend may mint, because minting needs a "Search - Impersonate" API key that must never ship in the app. This page lists what Coveo's official documentation and published npm packages state, with a link for each claim, and lists what they do not cover. Part 2 (sections 11-16) adds Microsoft, platform and community sources for the webview, the connectivity probe and the degraded-state UX. Three of its findings change the design: Microsoft advises against handing tokens to JavaScript, the webview origin cannot be settled from documentation, and no source documents a Coveo-specific reachability check.

Contents

How to read this guide

Every claim carries one of these labels:

LabelMeaning
DocsStated on a Coveo documentation page. The link is in the same row.
PackageRead directly from the published @coveo/atomic@3.61.4 or @coveo/headless@3.57.0 npm package (type definitions, custom-elements.json, source). It is what actually runs, and sometimes differs from the prose docs.
InferredDerived from a docs page or the package without an explicit statement. Verify before relying on it.
Scope: sections 1-10 (Part 1) record official Coveo sources only. Sections 11-16 (Part 2) record other sources and label each row by source type: MS docs (learn.microsoft.com), dotnet GitHub (a dotnet/maui issue or source file, dated), GitHub (another repository), Vendor docs (MDN, Apple, Android, web.dev), Community (forum, blog or Medium post) and Inferred. Neither part contains the app's own design decisions.

1. The big picture

  1. The app asks our backend for a search token. The backend holds a Coveo API key with the "Search - Impersonate" privilege.
  2. The backend calls Coveo's token endpoint and returns the token.
  3. The webview page calls initialize({ accessToken, organizationId, renewAccessToken }) on atomic-search-interface.
  4. Atomic sends queries and analytics events straight to Coveo with Authorization: Bearer <token>.
  5. When the token expires, Coveo answers HTTP 419 and Atomic calls renewAccessToken, which fetches a fresh token from our backend.
ClaimLabelSource
Search tokens are the recommended way to authenticate an interface. They can enforce hub, pipeline and filter, unlike a public API key. Docs Search token authentication (docs.coveo.com/en/1369)
Atomic and Headless renew a token by calling a renewAccessToken callback when the platform returns 419. The callback "returns a new access token, usually by fetching it from a backend service." Docs Search tokens (docs.coveo.com/56), Atomic usage
The Coveo IPX interface cannot renew tokens. Not relevant to Atomic. Docs docs.coveo.com/56

2. Minting a search token

Request

POST https://<ORG_ID>.org.coveo.com/rest/search/token?organizationId=<ORG_ID>
Authorization: Bearer <API key with "Search - Impersonate">
Content-Type: application/json
ItemDocumented valueLabelSource
Endpoint POST https://<ORG_ID>.org.coveo.com/rest/search/token. The page says: "To request a search token, make a POST request to https://<ORG_ID>.org.coveo.com/rest/search/token." Docs docs.coveo.com/56
Key privilege An authenticated search API key with the "Search - Impersonate" privilege. Anonymous keys cannot create tokens. The key must stay server-side. Docs docs.coveo.com/56, docs.coveo.com/en/1369
userIds[] (required) name is required (use "anonymous" for an unauthenticated user). provider is required (example: "Email Security Provider"). type is optional: User (default), Group, VirtualGroup or Unknown. Docs docs.coveo.com/56
searchHub Overrides the searchHub sent with the query and becomes originLevel1 in analytics. Docs docs.coveo.com/56
pipeline Takes precedence over other query-pipeline routing. Docs docs.coveo.com/56
filter A mandatory filter, merged with the query's constant expression using AND. Docs docs.coveo.com/56
Other body fields userDisplayName (used in analytics), userGroups[], dictionaryFieldContext and allowedDictionaryFieldKeys (mutually exclusive). Docs docs.coveo.com/56
validFor Milliseconds the token stays valid. Minimum 900,000 (15 minutes). Maximum and default 86,400,000 (24 hours). Docs docs.coveo.com/56
Response {"token": "<string>"} Docs docs.coveo.com/56
Unresolved. Two points in this table are not settled by Coveo's pages. (1) One web-search snippet shows the path as /rest/search/v2/token; only /rest/search/token appears on the fetched pages, and the OpenAPI spec at platform.cloud.coveo.com/docs returned 401 without credentials, so the path was not checked against it. (2) The docs give a 15-minute minimum for validFor but do not say whether a smaller value is rejected or clamped. Test both against the real organization before coding.

Identity and permissions

ClaimLabelSource
"anonymous" is the documented name for an unauthenticated user. Docs docs.coveo.com/56
The identity in userIds must match an identity the source's permissions were indexed against, otherwise permission-trimmed results come back empty. Inferred Follows from the identity model on docs.coveo.com/56; not stated as a rule there.
Pipelines route on conditions such as "when $searchHub is X". Enforce searchHub in the token so every query from an interface reaches the right pipeline. Docs Query pipelines (docs.coveo.com/en/las95231)
An @source== expression is standard Coveo query syntax. No docs page shows it inside a token filter. Inferred No page found.

3. Initializing Atomic

await customElements.whenDefined('atomic-search-interface');
const searchInterface = document.querySelector('atomic-search-interface');
await searchInterface.initialize({
  accessToken: token,               // from our backend
  organizationId: '<ORG_ID>',
  renewAccessToken: () => fetchNewToken()  // returns a new token string
});
searchInterface.executeFirstSearch();
ClaimLabelSource
The documented usage pattern is whenDefined, then initialize, then executeFirstSearch, with accessToken and organizationId as the required options and renewAccessToken optional. Docs Atomic usage
initialize accepts: organizationId, accessToken, renewAccessToken, preprocessRequest, name, environment (prod by default; hipaa for HIPAA organizations; dev/stg are Coveo-internal), analytics{} and search{pipeline, searchHub, locale, timezone, authenticationProviders, proxyBaseUrl, ...}. Package @coveo/atomic 3.61.4 custom-elements.json and the bundled @coveo/headless 3.57.0 types
platformUrl is removed and organizationEndpoints must not be passed. Organization endpoints are now enforced automatically: "Initialize without this property." Docs Upgrading from v2 to v3

atomic-search-interface properties

Read from the 3.61.4 package. Set them as HTML attributes or as element properties.

AttributeType / defaultNotes
analyticsboolean, true"Whether analytics should be enabled." See section 4.
fields-to-includeJSON string array, []e.g. '["fieldA","fieldB"]'. Lives here, not on the result list, since v2.
search-hub, pipelinestringQuery routing.
languagestring, 'en'
language-assets-pathstring, './lang'"By default, this will be a relative URL pointing to ./lang." Matters for vendoring.
icon-assets-pathstring, './assets'Relative URL to ./assets by default. Matters for vendoring.
reflect-state-in-urlboolean, trueAlso disable-state-reflection-in-url, default false.
timezone, log-level, scroll-containerstringlog-level: trace, debug, info, warn, error, fatal, silent.

Methods: initialize, executeFirstSearch, scrollToTop, updateSearchHub, updatePipeline, toggleAnalytics, updateLanguage, updateIconAssetsPath, getBindings, and the readonly engine and i18n.

The component reference is a JavaScript-rendered Storybook page that could not be read as text: atomic-search-interface Storybook. The table above therefore comes from the package, not from that page.

4. Analytics

ClaimLabelSource
Disable analytics with <atomic-search-interface analytics="false"> or el.analytics = false. The package passes the value into the engine's analytics config as enabled, and toggleAnalytics() watches it. Package custom-elements.json
initialize({ analytics: { enabled: false } }) is type-valid. Which of the attribute or this option wins when both are set was not checked. Inferred Headless 3.57.0 config types.
Since v3 the documented default analytics mode is Event Protocol (next). "Only Coveo for Commerce supports EP at the moment. For all other implementations, set analyticsMode to legacy." Docs Upgrading from v2 to v3, Atomic analytics
In 3.61.4 the code falls back to legacy analytics when analyticsMode is unset, which contradicts the docs' "default is next". Set it explicitly and do not rely on either. Package Headless 3.57.0 getAnalyticsConfig.
atomic-result-link logs click events. A result template that omits it stops click logging. Docs Displaying results

5. Loading, pinning and vendoring Atomic

ClaimLabelSource
Load from the CDN with a pinned version, for example https://static.cloud.coveo.com/atomic/v3.61.3/atomic.esm.js (a type="module" script) and .../themes/coveo.css. Test newer releases before moving the pin in a customer-facing app. Subresource-integrity hashes are published. Docs Atomic usage, docs.coveo.com/en/qbb1t271
"https://static.cloud.coveo.com/atomic/latest/* resources will no longer be updated." The v1 path used by older samples is also outdated. Docs Upgrading from v1 to v2
Self-hosting: npm i @coveo/atomic@3.61.3. Entry points: @coveo/atomic, /loader, /themes, /assets, /lang. The npm bundle omits on-demand assets, so copy @coveo/atomic/lang/en.json, @coveo/atomic/assets/all.svg and @coveo/atomic/themes/coveo.css into the public directory. Docs Atomic usage
Headless is no longer bundled inside the npm package. Docs Upgrading from v1 to v2

6. Hosts the app must reach

PurposeHost and pathLabelSource
Search API https://<ORG_ID>.org.coveo.com/rest/search/v2 Docs Package Organization endpoints (docs.coveo.com/en/mcc80216)
Analytics https://<ORG_ID>.analytics.org.coveo.com/rest/ua (docs); the package builds .../rest/organizations/<org>/events/v1 Docs Package docs.coveo.com/en/mcc80216
Token creation (called by our backend, not the app) https://<ORG_ID>.org.coveo.com/rest/search/token Docs docs.coveo.com/56
Script, styles, fonts and icons (CDN build only) static.cloud.coveo.com Inferred From the CDN URLs on Atomic usage. A vendored build does not need it.
Auth header on queries Authorization: Bearer <accessToken> Package Headless 3.57.0 search request builder.

HIPAA organizations use an orghipaa host and environment: 'hipaa'. The docs also say: "When migrating to organization endpoints, make sure to update your Content Security Policy (CSP)." No host list is published for that CSP.

7. Result templates

ClaimLabelSource
<atomic-result-template><template>...</template></atomic-result-template> must be a direct child of atomic-result-list. Docs Displaying results, atomic-result-template reference
Several templates can coexist. Pick one with must-match-<field> and must-not-match-<field>. A template with no conditions is the fallback. Docs Displaying results
Inline <style> and ::part() selectors are supported inside a template. Result sections adapt to mobile widths. Docs Displaying results
A standalone search box redirects using its redirection-url property. The destination page needs an atomic-result-list with an atomic-result-template. Docs Standalone search box

8. Upgrading a v1 sample page to v3

The web reference implementation was written against v1. Carry these changes forward.

ChangeSource
Pin a versioned CDN path; the v1 and latest paths are not maintained.v1 to v2
fields-to-include was removed from atomic-result-list; set it on atomic-search-interface as a JSON array.v1 to v2
Comma-separated array attributes on atomic-facet, atomic-category-facet and atomic-search-interface became JSON arrays.v1 to v2
Facets serialize into the URL as f-country= rather than f[country]=.v1 to v2
The image result-list attribute became image-size.v1 to v2
Removed: enable-duration on atomic-query-summary; target on atomic-result-link and atomic-result-printable-uri.v1 to v2
Init options: platformUrl removed; do not pass organizationEndpoints; proxy options are now search.proxyBaseUrl and analytics.proxyBaseUrl.v2 to v3
The search box supports only its textarea input.v2 to v3
Removed components: atomic-hosted-page, atomic-simple-builder, atomic-load-more-children-results; gridCellLinkTarget removed from atomic-result-list.v2 to v3

9. What the documentation does not cover

None of these were found in Coveo's official docs or packages. Each needs a test in the app's webview or a different kind of source.

GapWhat was checked
Running Atomic inside WKWebView or Android WebView, including from a non-http origin such as the one Blazor Hybrid serves from.No official guidance or documented limitation found. No Blazor guidance either; Coveo documents Angular and Vue wrappers only.
Content Security Policy host list (connect-src, script-src).One sentence saying to update the CSP; no list. The hosts in section 6 come from the package code.
Origin or CORS restrictions on search tokens and API keys.The token and authentication pages mention no allowed-origins setting.
A lightweight health or ping endpoint for a reachability probe.status.cloud.coveo.com is a human-readable page. A search snippet mentioned /api/status/maestro, unverified and not documented as a public endpoint.
Behavior when validFor is below 900,000 ms.See the warning in section 2.
The exact token path if /rest/search/v2/token is the current one.See the warning in section 2.

10. How the web reference implementation differs

The DNN reference (ALPA.CoveoForDNN, cloned outside this repository) and the removed mobile client (commit 4ef1aa37, removed in 05cf8865) diverge from the documentation in these places.

ItemReference / removed clientDocumentation
validFor60,000 ms (reference default and removed client)Minimum 900,000 ms
Token endpointConfigurable URL in the reference; platform.cloud.coveo.com/rest/search/v2/token in the removed client<ORG_ID>.org.coveo.com/rest/search/token
Atomic versionatomic/v1 CDN pathPinned atomic/v3.61.x
Where the key livesServer-side in the reference; shipped in the app in the removed clientMust stay server-side
Analytics modeNot setSet legacy explicitly
Result renderingsearch.html has only a search box, no result listA results page needs atomic-result-list plus a template

11. Microsoft: BlazorWebView, CSP and token hand-off

Conflict with the Coveo token design. Microsoft's Blazor Hybrid security guidance says: "Avoid passing the tokens to the document context (JavaScript)." Its preferred alternative is to give the library a temporary token, intercept the outgoing request in native code, swap in the real token, and confirm the destination is valid. Atomic's renewAccessToken is a JavaScript callback that holds the token. The Coveo search token is short-lived and permission-scoped, not a long-lived credential, so whether the guidance applies is a design decision for the team. Sources: hybrid security, security considerations.
TopicFindingLabelSource
Content host on .NET 10 The default host is now 0.0.0.1; 0.0.0.0 "no longer works" (empty rectangle). The legacy switch is AppContext.SetSwitch("BlazorWebView.AppHostAddressAlways0000", true). The routing page's sample still tests Url.Host != "0.0.0.0", which is stale. MS docs BlazorWebView, routing
Origin per platform iOS: app://<host>/ (the iOS handler builds AppOrigin that way; WKWebView cannot intercept http/https, so a scheme handler serves local files). Android: https://<host>/. The exact .NET 10 value per platform is not documented. dotnet GitHub Inferred iOS handler source, issue 4003 (opened 2022-01-08), issue 24363 (opened 2024-08-21, fixed in 9.0.0-rc.2)
Cross-origin fetch to third-party https hosts No Microsoft doc covers it. The WebView enforces CORS. Issue 4003 reports failed preflights for credentialed CORS on iOS while Android worked; no resolution is visible. Whether Access-Control-Allow-Origin: * works from an app:// origin is unconfirmed. dotnet GitHub Inferred issue 4003
ES modules and custom elements from wwwroot Supported. Everything under wwwroot resolves relative to the host page, and modules are imported with ./ paths. MS docs static files, JS from .NET
Scripts from a third-party CDN No Microsoft doc says it fails. Microsoft advises avoiding third-party origins where possible and vendoring into wwwroot; if a CDN is unavoidable, use TLS, CSP and Subresource Integrity. MS docs security considerations
Content Security Policy Add <meta http-equiv="Content-Security-Policy" content="..."> just inside <head> of wwwroot/index.html. Meta tags do not support frame-ancestors, report-to, report-uri or sandbox. The sample uses connect-src 'self' http: ws: wss:; Coveo's hosts (section 6) must be added. MS docs Blazor CSP
CSP on Android A CSP img-src data: http: https: did not show https images on Android (opened 2023-05-26; no resolution visible). dotnet GitHub issue 15299
Links and external navigation A link is internal only when host and scheme match the app origin. Everything else, and target="_blank", opens in the device handler. UrlLoading outcomes: OpenExternally, OpenInWebView, CancelLoad. Microsoft warns against OpenInWebView for external URLs unless fully trusted. MS docs routing
Request interception BlazorWebView.WebResourceRequested lets native code rewrite headers per host or answer a request itself (Handled = true plus SetResponse). It runs synchronously on the WebView thread. Whether it sees Coveo's fetch calls on both platforms is not documented. MS docs Inferred BlazorWebView
JS module and .NET callback Import with JS.InvokeAsync<IJSObjectReference>("import", "./x.js") in OnAfterRenderAsync(firstRender) and dispose it. Pass a DotNetObjectReference; JS calls invokeMethodAsync('Name') on a [JSInvokable] method. Dispose the reference or it leaks. A renewAccessToken that calls helper.invokeMethodAsync('GetFreshToken') is assembled from these two pages, not shown by either. MS docs Inferred JS from .NET, .NET from JS
Static asset caching Local static content is served with no-store; the iOS handler sets no-cache, max-age=0, must-revalidate, no-store. StaticContentCacheControlProvider appears only under the .NET MAUI 11 moniker. So on .NET 10 every file of a vendored bundle goes through the managed handler on each load. Fewer, larger files should help (inferred; no bundle-size guidance found). dotnet GitHub MS docs Inferred iOS handler source, BlazorWebView

12. Connectivity and the reachability probe

TopicFindingLabelSource
MAUI Connectivity limit NetworkAccess.Internet "can only guarantee that a connection is available." The docs' own example is Wi-Fi with a router that has no upstream. Values: Internet, ConstrainedInternet (captive portal), Local, None, Unknown. How the captive portal is detected per platform is not on Learn. MS docs Connectivity (page last updated 2023-11-29)
Known platform issues Android 14 with targetSdk 34: a ConnectivityChanged handler threw (RECEIVER_EXPORTED). Also a report that NetworkAccess == Internet did not work. iOS implementation move to NWPathMonitor was planned; status not confirmed. Fix status of these was not checked. dotnet GitHub 17861, 19949, 27351, 2574
Android network state NET_CAPABILITY_VALIDATED means the system probed and found public internet access. A captive-portal network has INTERNET and CAPTIVE_PORTAL but not VALIDATED. Capabilities can change at any time. Vendor docs Reading network state
OS captive-portal probes Apple probes captive.apple.com/hotspot-detect.html and expects a tiny page containing "Success". Android probes connectivitycheck.gstatic.com/generate_204 and expects an empty 204. Both are OS-internal; an app cannot reuse them as its own check. Community Inferred Apple discussions, Mullvad help
navigator.onLine "Inherently unreliable": true can mean a LAN only or a virtual adapter. MDN says to provide hints, not to disable features. Vendor docs MDN
HttpClient.Timeout Default 100 s; cannot change after the first request (InvalidOperationException). Use a CancellationTokenSource for a per-request limit; the shorter of the two wins. A DNS lookup can take up to 15 s, so a timeout below that may not be honored promptly. MS docs HttpClient.Timeout
Standard resilience handler defaults Total timeout 30 s; 3 retries, exponential with jitter, 2 s base; attempt timeout 10 s; circuit breaker at 10% failure ratio, minimum throughput 100, 30 s sampling, 5 s break. Retry can be disabled for unsafe verbs with DisableForUnsafeHttpMethods(). Polly throws TimeoutRejectedException, not TimeoutException. Add only one resilience handler per client. MS docs HTTP resilience
Client lifetime Use a singleton with PooledConnectionLifetime, or IHttpClientFactory. MS docs HttpClient guidelines
Client-side health probe No Microsoft guidance found. A bounded check is new CancellationTokenSource(TimeSpan.FromSeconds(3)) plus SendAsync(HEAD, ResponseHeadersRead, token), catching OperationCanceledException, on a client without the retry and circuit-breaker pipeline. Built from the Timeout page's advice; not a documented pattern. Inferred n/a
Bounded fetch in the page AbortSignal.timeout(ms) aborts with a TimeoutError and works as fetch(url, {signal}). Baseline since April 2024. Vendor docs MDN
Both the Connectivity page and the platform docs point to the same conclusion: the OS flag is a hint, and only a real request with a short timeout proves reachability. No source documents a probe against Coveo itself. The remaining candidate is a first-party endpoint that we own, for example the token-mint endpoint.

13. Platform and web standards: origin, CORS, modules, CSP

TopicFindingLabelSource
WKWebView origin A file:// page sends Origin: null. A custom scheme such as app://localhost sends that scheme. WKURLSchemeHandler serves custom schemes only; it cannot override http or https. Community Vendor docs Medium post, WKURLSchemeHandler
CORS from a custom scheme Ordinary CORS: the third party must return Access-Control-Allow-Origin for the page's origin and answer preflight. Third parties often do not allowlist null or app://. Workarounds are a native proxy through the scheme handler or a vendor allowlist. A WebKit change touches CORS for custom schemes registered as CORS-enabled. Community Inferred Apple forums, Medium post, WebKit PR 72963
Android origin WebViewAssetLoader serves assets from https://appassets.androidplatform.net/assets/..., giving a real https origin with normal same-origin and CORS rules. Third parties would have to allow that origin (inferred). Vendor docs Inferred WebViewAssetLoader
ES modules Module scripts are same-origin CORS fetches, need a JavaScript MIME type, and do not work from file://. Vendor docs MDN modules
Custom elements Autonomous custom elements v1 are widely supported. Safari does not support customized built-ins (is=). Minimum iOS and Android WebView versions for Shadow DOM, modules and ES2020: not found. Vendor docs MDN custom elements
Android WebView updates WebView updates through Google Play, separately from the OS. Devices that cannot update are the risk. Community Chromium docs
CSP directives For own-origin script plus two third-party https hosts: connect-src governs fetch, XHR, WebSocket and EventSource; also script-src, style-src, font-src, img-src and worker-src. MDN confirms the directive names and host-list syntax but not what Atomic needs. Whether Atomic needs 'unsafe-inline' styles or blob workers is inferred. Verify with the console's CSP violation reports. Vendor docs Inferred MDN CSP
iOS App Transport Security Defaults are HTTPS, TLS 1.2 or later and forward secrecy. An https third-party host with standard TLS needs no Info.plist change. Whether ATS treats the app:// scheme specially, and how NSAllowsArbitraryLoadsInWebContent applies, is unverified. Vendor docs Inferred NSAppTransportSecurity
Android cleartext and permissions Apps targeting API 28 or later default to cleartextTrafficPermitted="false". https to third parties needs no network security config. The manifest needs the INTERNET permission. Android WebView mixed-content behavior was not researched. Vendor docs Network security config

14. Coveo community and GitHub

Searches found no Coveo-specific WebView, Capacitor, Cordova, CORS or offline material. Only docs.coveo.com pages and one coveo/ui-kit pull request were read; community.coveo.com and StackOverflow returned nothing. Treat "not found" as "not found by these searches".

TopicFindingLabelSource
Nonce-based CSP Atomic's loader exposes setNonce. From a search snippet; the page was not read. Docs (snippet) Atomic docs
Modifying requests preprocessRequest(request, clientOrigin, metadata) can modify requests before they reach Coveo. The page says nothing about the Origin header. Using it to work around a custom-scheme origin is unverified. Docs Inferred Modify requests and responses
Token expiry errors An expired search token gives the Search API a 419 (ExpiredTokenException). The Usage Analytics API gives 400 InvalidToken. renewAccessToken must return a Promise of a token string and is called automatically on 419. Docs Search tokens
renewAccessToken behavior A merged coveo/ui-kit pull request says it renews proactively on expiry and reactively on an unauthorized response, with no process-global state. That is the server-side-rendering path, not the webview case. GitHub (Coveo maintainer PR) ui-kit PR 8505 (September 2026)
Anonymous keys An anonymous API key gets a 403 when minting a token. The name anonymous sets anonymous=true on analytics events. Docs Search tokens
Analytics off Atomic v3 no longer honors doNotTrack (v2 did). The coveo_visitorId cookie is used for tracking. Whether it is still written with analytics off is not stated. Disable before initializing if consent is required. Docs Coveo UA in Atomic
Network-failure display atomic-query-error handles fatal errors when querying. It links to documentation for a known error and shows the JSON for an unknown one. What it renders when the network is down is unconfirmed. Server errors documented: 429 (back off) and 503 with Retry-After. Docs (partial) atomic-query-error, rate limits
Community threads Two threads on "invalid access token" and "provided token is not a valid token" exist. Not opened. Community (unread) thread 1, thread 2

15. Degraded-state UX

GuidanceLabelSource
Show an unobtrusive, persistent offline indicator. Use a "cloud off" icon for unavailable features. Explain offline behavior to users.Vendor docs (Material 1, old)Material offline states
Show cached data first and update when the network responds (cache-then-network). Serve the cached copy while fetching an update (stale-while-revalidate). Fall back to a generic "unavailable while offline" state when both fail.Vendor docsweb.dev offline cookbook
Prefer non-intrusive status messages over modal alerts; keep errors visible while the user fixes them. The Apple HIG guidance was not verified directly; the Nielsen Norman page is general error-message advice, not offline handling.CommunityNN/g error messages

16. Open questions only a device test can answer

No source settles these. Test each on an iOS simulator and an Android emulator created for the run.

#QuestionHow to check
1What is location.origin on each platform at .NET 10 (app://0.0.0.1, localhost, or another)?Read it through cdp Runtime evaluate "location.origin".
2Does <org>.org.coveo.com accept that origin, including the preflight, for search and analytics calls?Load Atomic in the webview and watch the network calls and console.
3Does WebResourceRequested see Coveo's fetch calls on both platforms (needed for a temporary-token swap)?Register a handler that logs request hosts.
4What does atomic-query-error render when the network is down mid-session?Toggle connectivity after the first search.
5What happens with validFor below 900,000 ms?Mint a token with 60,000 against the real organization.
6Which token path is current: /rest/search/token or /rest/search/v2/token?Call both from the backend against the real organization.
7Does Atomic need 'unsafe-inline' styles, blob workers or other CSP allowances?Apply the CSP and read the violation reports.
8How long does a vendored bundle take to load through the managed handler with no caching?Time the first paint of the search page.

Part 2 sources (sections 11-15) are linked in each row's Source column.