Webviews embedded in the Product Detail Page (PDP) of Associate App receive context from the app at startup and can post messages back to trigger native app actions. This document describes exactly what data is available and how to use it.
Further reading
Adding webview customizations using external authentication — This guide covers setting up external identity providers and reading context in any Associate App webview.
Adding customized products to a cart — An end-to-end walkthrough of a product configurator webview using the Cart API.
Delivering context
When the app opens a webview, it adds a base64-encoded JSON payload to the URL as a fragment (#):
https://your-webview-url.com/page#<base64-encoded-JSON>Decode and parse it on the client side:
const raw = decodeURIComponent(window.location.hash.slice(1))
const context = JSON.parse(atob(raw))Important
Instead of accessing context via
window.NEWSTORE, use the latest mechanism of URL fragment injection and fragment-based decode method.
The context object has the following payload:
{
contextProps: {
formData: {
// --- Product fields ---
productId: string
variantGroupId?: string
sku?: string // deprecated, prefer externalIdentifiers.sku
externalIdentifiers?: {
sku?: string
gtin?: string
upc?: string
ean13?: string
jan?: string
isbn?: string
}
title?: string
brand?: string
caption?: string
description?: string
price?: number
markdownPrice?: number | null
currencyCode?: string
isAvailable?: boolean
isPreorder?: boolean
serializedInventory?: boolean
variationColorValue?: string
variationSizeValue?: string
variationSizeGender?: 'male' | 'female' | 'unisex'
variationSizeType?: string
variationSizeSystem?: string
variationAdditional1Name?: string
variationAdditional1Value?: string
variationAdditional2Name?: string
variationAdditional2Value?: string
variationAttributes?: {
variationColorValues?: string[]
variationSizeValues?: string[]
}
variations?: Array<{
productId?: string
isAvailable?: boolean
variationColorValue?: string
variationSizeValue?: string
price?: number
markdownPrice?: number | null
}>
images?: Array<{
url: string
isMain?: boolean
title?: string
altText?: string
identifier?: string
tags?: string[]
}>
extendedAttributes?: Array<{
name: string
value: string
}>
categories?: Array<{
path?: string[]
fullPath?: string
}>
keywords?: string[]
// --- Session fields (always present) ---
associateId: string // ID of the logged-in associate
storeId: string // ID of the current store
cartId: string // Active cart ID (empty string if no cart yet)
}
}
auth: {
accessToken: string // NewStore access token — use to call NewStore APIs
}
externalIdentities: Array<{
identityProvider: string // Name of the configured identity provider
identity: string // Auth token for that provider
}>
theme: object // App color, spacing, and typography tokens (mobileDesign)
dimensions: {
top: number // Safe area insets (device notch / home indicator)
bottom: number
left: number
right: number
}
enums: {
DocumentType: { // Print document type constants — use with the print message
exchangeReceipt: 'exchangeReceipt'
hangTag: 'hangTag'
giftReceipt: 'giftReceipt'
inStorePickupLabel: 'inStorePickupLabel'
invoice: 'invoice'
packingSlip: 'packingSlip'
returnLabel: 'returnLabel'
returnForm: 'returnForm'
returnReceipt: 'returnReceipt'
salesReceipt: 'salesReceipt'
shippingLabel: 'shippingLabel'
fiscalDocument: 'fiscalDocument'
transferPackingList: 'transferPackingList'
commercialInvoice: 'commercialInvoice'
reservationDocket: 'reservationDocket'
}
}
securityToken: string // One-time token generated per webview session
}Common field descriptions
Field | Where | Notes |
|---|---|---|
| Product | NewStore product ID of the currently viewed variant |
| Product | Preferred SKU field |
| Product | Custom key/value pairs from the product catalog |
| Product | Display price (may be incl. or excl. tax) |
| Session | Current associate's user ID |
| Session | Current store |
| Session | Active cart — use with the Cart API |
| Auth | NewStore token — include as |
| Auth | Third-party tokens if your integration uses an external identity provider |
Making a call to NewStore APIs
Use auth.accessToken to make authenticated calls to NewStore APIs.
Adding a product to the cart
Use the Cart Line Item API to add the current product (or any product) to the active cart. See the payload here.
const { auth, contextProps: { formData } } = context
const baseUrl = `https://<tenant>.p.newstore.net/v0/d`
const response = await fetch(`${baseUrl}/checkout/carts/${formData.cartId}/items`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${auth.accessToken}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
product_id: formData.productId,
fulfillment: 'IN_STORE_HANDOVER',
price: { source: 'INTERNAL', source_id: 'default' },
}),
})Adding an add-on to a cart item
To attach an add-on (for example, warranty information or an accessory) to a product already in the cart, use the Location header from the add-product response to target the parent item.
const parentLocation = response.headers.get('Location')
await fetch(`${parentLocation}/add-ons`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${auth.accessToken}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
product_id: '<addon-product-id>',
fulfillment: 'IN_STORE_HANDOVER',
price: { source: 'INTERNAL', source_id: '<pricebook-id>' },
}),
})Adding a standalone add-on service to the cart
For service products not attached to a parent item (for example, gift wrapping or insurance), use the Add-on Line Item API directly.
await fetch(`${baseUrl}/checkout/carts/${formData.cartId}/add_on_items`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${auth.accessToken}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ product_id: '<service-product-id>', quantity: 1 }),
})Posting messages back to the app
The webview can trigger native app actions via window.ReactNativeWebView.postMessage:
window.ReactNativeWebView.postMessage(JSON.stringify(message))Closing the webview
window.ReactNativeWebView.postMessage(JSON.stringify({ type: 'close' }))Trigger printing
Each resource must have a documentType (use a value from context.enums.DocumentType) and either a url or base64 payload:
const { enums: { DocumentType } } = context
window.ReactNativeWebView.postMessage(JSON.stringify({
type: 'print',
message: {
resources: [
{ documentType: DocumentType.salesReceipt, url: 'https://...' }
]
}
}))For base64-encoded documents (for example, generated PDFs), pass base64 instead of url:
window.ReactNativeWebView.postMessage(JSON.stringify({
type: 'print',
message: {
resources: [
{ documentType: DocumentType.salesReceipt, base64: '<base64-encoded-pdf>' }
]
}
}))Opening an external URL in the system browser
Important
The URL must start with
https://. Non-HTTPS URLs are ignored without returning an error.
window.ReactNativeWebView.postMessage(JSON.stringify({
type: 'openExternalUrl',
message: { url: 'https://...' }
}))Navigating to a product detail page
To navigate the associate to another product without leaving the app, use window.open with an Associate App deep link. The app intercepts com.newstore.associate-one:// URLs during navigation and routes them natively:
const productId = '1000721'
window.open(`com.newstore.associate-one://products/preview?productId=${productId}`)Note
The
openExternalUrlpostMessage handler only acceptshttps://URLs. Deep links likecom.newstore.associate-one://must go through navigation (window.open,window.location, or an anchor tag) so the app can intercept and handle them.
Product IDs are available in contextProps.formData.productId (current product) and in contextProps.formData.variations[].productId (all variants of the current product).
Reloading the cart in the app
After the webview modifies the cart, trigger Associate App to reload the cart view before closing. This ensures the associate sees an up-to-date cart immediately.
const { contextProps: { formData } } = context
window.open(`com.newstore.associate-one://cart/load?cartId=${formData.cartId}`)
window.ReactNativeWebView.postMessage(JSON.stringify({ type: 'close' }))Slots
Two slots are available on the PDP. Configure which slot the webview appears in via the Associate App configuration
Slot ID | Position |
|---|---|
| Above the action buttons list |
| Below the action buttons list |
Display modes
Webviews can be configured as:
Full-screen (default) — Opens as a new screen when the associate taps a button in the app
Inline — Rendered directly within the PDP scroll view. Set
meta.inline: truein configuration, along withmeta.height(pixels), and optionallymeta.scrollEnabled,meta.scrollXEnabled,meta.scrollYEnabled
Conditional rendering
A webview can be shown only when the product has a specific extended attribute. Set meta.requiresExtendedAttribute to the attribute name in the configuration. If the attribute is absent on the current product, the button or inline view is hidden automatically.
Example: full decode
function getWebViewContext() {
const hash = window.location.hash.slice(1)
if (!hash) return null
try {
return JSON.parse(atob(decodeURIComponent(hash)))
} catch {
return null
}
}
const context = getWebViewContext()
if (!context) throw new Error('No context — not running inside the Associate App')
const {
contextProps: { formData },
auth,
externalIdentities,
} = context
console.log('Product ID:', formData.productId)
console.log('SKU:', formData.externalIdentifiers?.sku)
console.log('Cart ID:', formData.cartId)
console.log('Associate:', formData.associateId)
console.log('Store:', formData.storeId)
console.log('Access token:', auth.accessToken)