Real-time Personalization 2.0 (Client-side) empowers web and marketing teams to deliver instant, highly tailored experiences directly from the browser. This modern data engine enables your website or CMS to personalize content dynamically for each visitor, instantly reflecting the latest customer profile attributes, behaviors, and audience segment memberships.
Unlike traditional server-side personalization—which routes every request through an intermediary backend—client-side Real-time Personalization 2.0 allows JavaScript running in the user’s browser to securely fetch personalization payloads from Treasure Data’s API, eliminating extra network hops and reducing latency. This approach unlocks rapid UI updates and enables powerful in-page personalization scenarios—such as showing targeted offers, product recommendations, or loyalty banners as soon as the user lands or interacts with your site.
With the client-side edition, all API calls originate from the web browser and are served from CORS-enabled endpoints using public tokens, with built-in safeguards to ensure that only non-sensitive (non-PII) data is ever delivered to the front end. This guide focuses exclusively on browser-based integration, giving clear step-by-step instructions for enabling client-side personalization safely—including walkthroughs on token configuration, attribute sensitivity controls, UI setup, and best practices for privacy and compliance.

You may also explore our separate documentation for server-side integrations, but this guide is designed for developers, data engineers, and marketers who want to power direct, real-time personalization in the browser—supporting modern commerce, content, and engagement experiences on the web.
Through this step-by-step guide, you’ll learn how to build and implement client-side Real-time Personalization 2.0 use cases on your web application, from event tracking and attribute setup to audience segmentation, personalization design, and secure in-page integration.
Client-side real-time personalization enables web applications to deliver fully dynamic, personalized experiences directly from the user’s browser. This section explains how to safely and effectively send event data from browser JavaScript to Treasure Data’s platform for real-time audience evaluation and personalized payload delivery—while maintaining best practices in privacy, compliance, and data architecture.
In a client-side setup, events such as page views, clicks, signups, or product interactions are captured by browser JavaScript running on your site. These events are then transmitted directly to Treasure Data’s Personalization API via secure, CORS-enabled endpoints. No intermediary server is required, minimizing latency and unlocking “instant” UI updates for web personalization use cases.
Event Examples: page views, item clicks, cart additions, conversions, custom engagement milestones.
Typical Workflow:
Capture relevant events with custom JavaScript, a tag manager, or TD’s JS SDK (once updated for M2).
Package each event with relevant identifiers (e.g., anonymous ID, td_client_id), context (URL, path), and any non-sensitive attributes needed for personalization.
Do not send sensitive PII or confidential business logic directly from the browser.
All event data submitted client-side should be strictly non-sensitive. For sensitive data, use a server-side ingestion path instead.
Safe fields: anonymous user IDs, high-level behavior (e.g., td_path, product category)
Unsafe fields: email address, phone number, raw personal identifiers, or confidential business logic
There are two main event ingestion methods:
Personalization API (Client-side focus)
Use case:
Send an event and receive personalization offers instantly, in a single HTTP POST request from the browser.
Used for real-time, dynamic content updates on page load or user interaction.
Response:
- Contains only non-sensitive attributes/segments. If any offer contains sensitive data (per attribute sensitivity in setup), it is replaced with {} in the response.
Endpoint:
Public, CORS-enabled URL (e.g., /public/{db}/{table})
Requires a public type token in the WP13n-Token header.
Security Considerations:
- Only use public tokens in browser code. These have no IP whitelist and must be created as “public” at the service level. Private tokens will generate an error in the browser logs and will not return an offer.
Ingest API
Use case:
Submit events via backend/server for storage and later segmentation.
Does not return a personalization payload.
When to use: For sensitive or regulated data that should not transit the browser, or to capture raw logs for batch analysis.
A client-side “fetch” example (assuming future JS SDK support, or use with window.fetch):
fetch('https://us01.p13n.in.treasuredata.com/public/<YOUR_DB>/<YOUR_TABLE>', {
method: 'POST',
headers: {
'Content-Type': 'application/vnd.treasuredata.v1+json',
'WP13n-Token': '<ACCOUNT_ID>/<REACTOR_ID>/<PUBLIC_TOKEN>',
'Authorization':'TD1 <WRITE API KEY>'
},
body: JSON.stringify({
td_client_id: '1234-5678-9012-3456',
td_url: window.location.href,
td_path: window.location.pathname,
// ... additional non-sensitive event fields
})
})
.then(res => res.json())
.then(data => {
// data.offers: personalized sections
}
); Notes:
Do not include: Private tokens in browser-side requests for any reason.
Validate: Token must be public, origin must be allowed, and only non-sensitive data will be returned in response.
API endpoints validate both the Origin header and the token’s public/private status.
With a valid public token and valid Origin, API responds with CORS headers and the offer payload.
With an invalid token, private token, or invalid Origin, response is 4xx and no CORS headers are sent.
Client-side endpoints only support public tokens; attempts to use private tokens from the browser will fail.
As with client-side setups, each behavioral event should be mapped to a clear, separate table supporting downstream “parent segments” for real-time audience logic.
Parent segment and table definitions must be set up in advance within TD Console's UI.
All mapping, updating, and event configuration for client-side events is managed within the UI—no backend required for standard integrations.
Only publish non-sensitive data from browser JavaScript
Always use CORS-enabled public endpoints and public tokens
Map each behavioral event type to an appropriate table for clear audience segmentation
For any data that requires privacy, rules, or access control: use server-side ingestion, not the browser
| Option | Source | Personalization Response | Token Type | Endpoint Path | Use Case |
|---|---|---|---|---|---|
| Personalization API | browser JS | Yes (real-time) | Public Only | /public/db/table | Real-time browser UX personalization |
| Ingest API | backend | No (store only) | Private | /records | Sensitive, server-logged, compliance data |
Configuring client-side Real-Time Personalization 2.0 in Treasure Data’s UI introduces a distinct set of requirements and workflows, focused on ensuring browser security, privacy compliance, robust governance, and seamless end-to-end enablement. This section outlines the full user experience and system constraints for creating and managing client-side personalizations.
- In order to enable client-side (browser-based) integration, your account must have both the global Real-Time Personalization 2.0 feature flag and the M2 client-side feature flag activated (e.g., eng-lc-realtime-personalization-m2-1 for service/tokens and eng-lc-realtime-personalization-m2-2 for attribute-level PII sensitivity configuration). Without these flags, UI options for public services and sensitive attribute marking will not be visible.
Create a Parent Segment - Start by creating or selecting a Parent Segment in Audience Studio—this segment forms the basis for your personalization logic.
Create New Personalization Service (Public for Client-side) - Navigate to the "Personalization Configuration" for your segment. - Click "Create new personalized service." - In the modal, you are prompted to choose a “Service Type”: - Public (publishing) for client-side use. - Private for server-side only. - Critical: The type (public/private) is immutable—you cannot change it after service creation. Choose carefully based on your intended integration pattern.
Name, Describe, and Validate - Enter a unique name (max 100 characters) and optionally a description. - Duplicate names or names exceeding the character limit will throw UI validation errors: “Name has already been taken,” “Name is too long (maximum is 100 characters),” etc. - Required fields must be completed, or the UI will block creation and show helpful error labeling.
Add Tokens - After creating the public service, add one or more tokens for browser use. - Each token must also have a unique name (with similar validation). - For public services and tokens: - No Allowed IPs (IP whitelisting) can be set. Attempts to provide allowed IPs will fail with a validation error: “Allowed ips must not be set when the parent service is public”. - These tokens can be safely embedded in client JavaScript. - For private services, IP whitelisting is available.
Token Format and Limits - Each API token is in the format: [ACCOUNT_INSTANCE_ID]/[REACTOR_INSTANCE_ID]/[RT_PERSONALIZATION_TOKEN] - Limits: Up to 50 tokens per service, 200 per parent segment.
Public tokens are the only tokens that the browser can use. Private tokens are strictly backend/server-only.
Once created, public/private status cannot be changed.
UI restricts editing of service type post-creation (edit modal disables this field).
Attempting to add or edit tokens in violation of these constraints triggers explicit UI/API errors.
Manage tokens for each public service in the side panel.
Tokens can be deleted and re-created within allowed limits.
If a user’s session expires, viewing tokens triggers a password/SAML/SSO prompt before secret visibility will be re-granted (for security).
Ability to create/view/edit public services or mark attributes as sensitive depends on feature flag rollout and account/user permissions.
Users without sufficient privileges see descriptive errors and are blocked from configuration actions: “You do not have permission to perform this action.”
UI includes real-time form validation for all fields—no blank names, no duplicates, strict character limits, and clear feedback for validation failures.
Attempting to perform actions not permitted by the system design yields exact error messages.
For import and attribute management, see "Defining Events and Attributes" (next section) for per-attribute sensitivity and further compliance controls.
| Task | Public Service/Token | Private Service/Token |
|---|---|---|
| Service Type Editable? | No | No |
| Allowed IPs (token) | Not permitted | Permitted |
| Token Use | Browser JS only | Backend/server only |
| Delete/Add tokens | Allowed, within limit | Allowed, within limit |
| Maximum tokens/service | 50 | 50 |
| Validation: Name/Description | Enforced | Enforced |
| Session Expiry Behavior | SSO/Password prompt | SSO/Password prompt |
Use clear naming conventions to distinguish between public (client) and private (server) services.
Never attempt to reuse a token or service for both environments; maintain strict separation.
Educate your teams and downstream integrators on the immutability of these configurations to avoid orchestration and rollout issues.
Leverage built-in UI validations for error-free setup.
After you set up your client-side Real-Time Personalization service, the next step is to define which browser events to capture and configure the set of real-time attributes that will drive your in-page personalization logic. This process is similar in spirit to the server-side approach but introduces strict privacy, UI, and governance controls to ensure non-sensitive, browser-safe operations.
In the Real-Time Configuration section, you will select or register tables that represent the behavioral events sent from your website or web app. Common event examples for client-side personalization include:
Page views (e.g., homepage, category, product)
Clicks (product details, add-to-cart, banners)
Website signups or logins (as long as no PII is exposed)
Custom actions (e.g., completed video, downloaded asset)
To define a new event:
Click “Create new event” in the Events area of the configuration UI.
Choose the relevant data table that is used to store that event stream.
Give the event a descriptive name for downstream reference (e.g., “product_page_view”).
(Optional) Filter events: You may define additional filters—such as by URL path or query (e.g., td_path regex: ^/retail/./product/.)—to only include specific event types for personalization.
Best Practices: - Organize each event type in a clear, separate table to enable granular audience segmentation and easier troubleshooting. - If you are reusing batch tables for real-time, ensure no sensitive identifiers are sent from the browser.
A core difference for the client-side product is the explicit requirement to classify the sensitivity for Single, List, and Imported attributes at creation (or during follow-on editing). Only non-sensitive attributes are ever returned in API payloads to the browser.
Single: Stores the most recent value (string or numeric) for each visitor. Useful for tracking last viewed product, current page, or most recent category. Mark as Non-Sensitive only if it cannot reveal private information (e.g., avoid PII like emails or phone numbers).
List: Maintains a bounded array (up to 100 items) for each visitor (e.g., recent products viewed, categories viewed). Each item expires after 60 days. If the data in the list could be sensitive (e.g., user IDs, emails), mark as Sensitive; otherwise, Non-Sensitive.
Counter: Increments a numeric counter for event frequency (e.g., number of visits in the last 7 days). Counters are always considered Non-Sensitive and cannot be flagged as Sensitive in the UI.
Imported Batch: For batch attributes imported from offline or back-office sources (such as loyalty tier, batch segment membership). You must set the sensitivity flag as appropriate. Only Non-Sensitive imported attributes are returned to browser clients via the Personalization API.
Non-Sensitive: If all referenced attributes in a “payload section” are Non-Sensitive, they may be returned to the client.
Sensitive: If any attribute in a personalization payload section is Sensitive, the section is redacted in the API response ({} is returned) for any client-side (public token) request.
UI Enforcement: The attribute creation/edit form will require explicit selection of Sensitivity.
Review and Audit: The UI flags which attributes are Sensitive and which are safe for client use. Double-check attribute lists before go-live.
Single Attributes
- Track only the latest value for a property (e.g., “last_category_viewed”).
- Avoid Single attributes that could leak PII (never store email, phone, or other identifiers you would not want exposed to front-end code).
- Naming tip: Use clear, non-colliding names to avoid confusion with batch or server-side attributes.
List Attributes
Designed for session or recency use cases (e.g., “recent_products_viewed”).
Store string or numeric arrays only.
Remember: Properties (like price or URL) can be mapped as arrays, preserving entire lists, but only “flattened” for aggregations where string is the primary field.
If list items reference any sensitive data, the whole attribute must be marked as Sensitive.
To indicate the number of sensitive aggregations, use the format x/y Sensitive. For example, if you specify 1/5 Sensitive, it means that 1 out of the 5 aggregations is sensitive. If only the 4 non-sensitive aggregations are included in the payload, the response will contain those 4 attributes in the offers.
Counter Attributes
Count or sum event occurrences (e.g., “page_views_last_7_days”).
Must be Non-Sensitive; provides limited risk as they expose only aggregate behavior.
Supports sliding window (rolling) and total/cumulative options with fixed maximum durations.
Imported Batch Attributes
Added to real-time payloads only if included in the parent segment.
Must be explicitly configured and have their sensitivity set at import.
Not updated via real-time browser events; refresh only when batch segment re-runs.
Removing an imported batch attribute from the parent segment without updating RT config causes errors; fix this by re-adding, rerunning the parent, or creating a dummy entity if needed.
Sensitivity First: Always assume the browser API can be inspected by the end user. Never mark any attribute as Non-Sensitive if it contains or could infer PII or confidential business logic.
Naming Discipline: Prepend or suffix “rt” or “client” to client-side attributes for traceability.
Window Size Planning: Especially for lists and counters, pick durations that balance personalization value with security/compliance.
End-to-End Testing: Use the UI and API preview to verify only intended non-sensitive fields are exposed in the browser response.
Change Management: Any attribute’s sensitivity can be updated (where supported) if requirements change, but corrections require API/UI edits and may cause temporary section redactions if misconfigured.
Avoid Collisions: Carefully distinguish client-side vs. batch/server-side attributes to prevent confusion in Audience Studio or API payloads.
| Attribute Type | Sensitivity Required? | Client-side Exposure | Notes |
|---|---|---|---|
| Single | Yes | Non-Sensitive only | Last value per profile |
| List | Yes | Non-Sensitive only | Array, 100 max, 60-day expiration |
| Counter | Always Non-Sensitive | Non-Sensitive only | Count/aggregate only |
| Imported Batch | Yes | Non-Sensitive only | Reference, not updated via RT browser events |
Profile unification—commonly referred to as ID Stitching—ensures that all browser-driven and batch events relating to a customer are consolidated into a single, unified profile. This section details how to configure stitching for client-side integrations.
In client-side personalization, customers may interact with your website from multiple devices or browsers—sometimes anonymously, sometimes after authentication. Unifying these touchpoints provides the basis for delivering relevant, real-time personalized experiences and accurate audience segmentation, even as users switch contexts.
ID stitching connects identifiers found in events (for example: anonymous browser IDs, first-party cookies, or, where permitted, non-sensitive customer IDs) so that all browsing behavior, segment membership, and contextual attributes are resolved to a single customer profile.
- Select Appropriate Identifiers for the Browser
Only use IDs that are non-sensitive and safe to expose client-side. Common examples:
td_client_id (anonymized, system-assigned)
First-party browser or session cookies (where not PII)
Site-specific visitor IDs
Do not use emails, hashed PII, or raw user information in browser events or as stitching keys for client-side personalization.
- Define ID Stitching Keys in the Real-Time Configuration UI
In the “ID Stitching Keys” section, add the non-sensitive client-side identifiers you intend to stitch on.
Optionally, configure regular expressions to filter or format incoming IDs for standardization.
Advanced: Mark keys as “workflow only” if they should be used exclusively for batch/staging, not real-time browser events.
- Set the Primary Key
After defining eligible keys, select a unique, persistent, and stable identifier as the primary key for stitching.
This key must be present in all (or nearly all) client events, and must not change unexpectedly.
Example: td_client_id serves well if set for every browser session/user.
The unification system will merge profiles by assigning the oldest primary key as the canonical profile, consolidating events and attributes accordingly.
- Save and Validate the Configuration
Once stitching keys and the primary key are configured, save and relaunch the profile unification workflow as prompted.
Caveat: Changing the primary key after activation requires reprocessing of profiles and may lead to temporary segmentation gaps.
ALL identifiers used for client-side stitching should be “non-sensitive”—never include, transmit, or stitch on emails, phone numbers, addresses, or any direct/hashed PII from the browser.
Review local legislation (GDPR, CPRA, etc.) and your privacy policy to ensure customer consent mechanisms are honored for any cross-device/user stitching.
Temporarily-issued, session-only, or device-scoped identifiers are recommended for most client-side flows.
Plan ahead for cross-device users: If you want to enable identity resolution (e.g., anonymous user who later logs in), ensure any browser identifier maps cleanly to a first-party, non-sensitive key that can later be associated with an authenticated profile (in compliance with your privacy policy).
Audit your identifier fields: Before go-live, double-check that no field referenced as a stitching key is, or could be derived from, PII.
Filtering test/bad values: Use filtering regex or value exclusions to omit identifiers used for bot traffic, tests, or invalid sessions, maintaining a clean stitched population.
Example:
If a user browses anonymously with td_client_id=a123 and later logs in under a system-generated user ID (but never exposes their email in events), both sessions can be stitched and unified under the oldest known identifier if you have reliable mapping through non-sensitive keys.
Up to 200 stitching keys allowed per parent segment.
Each profile must always resolve to a single, unique, non-PII primary key within the segment.
Changing primary key post-deployment requires a re-launch of profile stitching for consistency.
| Step | Client-side Guidance |
|---|---|
| Allowed ID Types | Non-sensitive browser IDs, anonymous tokens, non-PII user IDs |
| Prohibited ID Types | Emails, phone numbers, hashed PII, any sensitive attributes |
| Config UI Behaviors | Explicit sensitivity warnings; non-editable after activation; validation in UI |
| Max Stitching Keys | 200 |
| Key Assignment | Choose unique & stable; avoid changing after go-live |
| Merging Logic | System designates oldest ID as canonical profile |
After your event tables and real-time attributes are configured—and sensitivity has been set for each attribute—the next step is to design and launch client-ready personalization logic in Audience Studio. This phase dictates how the right offers, content, or experiences are served to each web visitor via safe, real-time API responses. For the client-side product, every workflow is optimized to maximize privacy, ensure non-sensitive payload delivery, and provide UI indicators to help you audit exposure risk.
Access the Parent Segment and Start a New Personalization - In Audience Studio, select your designated parent segment. - Click “Create” and select “Personalization.” Enter an intuitive name and optional description for future reference.
Define Criteria and Payload for Each Section - Open the new personalization in the Personalization Canvas. - Add one or more “sections.” Each section has: - Criteria: Rules that determine when this personalization fires (e.g., “is_new_visitor = true”). - Payload: The actual data/offers sent to the browser when criteria match—built from batch segments and real-time attributes you’ve configured.
Attribute Sensitivity Drives Payload Visibility - For client-side endpoints, only sections containing exclusively non-sensitive attributes will return payload data to the browser. - If ANY attribute (single, list, or imported batch) in the section is marked Sensitive, the entire section will be redacted: API returns {} for that section. - The UI displays visual cues (e.g., shield or lock icons) to warn when a section’s output will be blanked for browser/public token requests. Always use these cues to verify which offers are actually publishable to web users.
UI and Workflow Tips for Privacy and Compliance - The section builder automatically checks attribute sensitivity and updates visual feedback in real time. - You can use aliases for returned fields and add audience/batch segments, but these must be configured as non-sensitive if you want them exposed client-side. - Payload size should stay under 10 KB (and ideally fewer than 20 attributes per section) to meet response SLAs and front-end snappiness. - Re-run the parent segment workflow after changing any batch segments, imported attributes, or sensitivity labels to guarantee users receive the latest output.
Redaction Logic Enforcement - The redaction pattern is strict: if a browser sends a personalization request using a public token, any offer section referencing a sensitive attribute is always redacted—even if the rest of the payload is non-sensitive. - Example: If the “Recommended Coupon” section references a sensitive imported batch attribute, offers["Recommended Coupon"] will equal {} in the client response.
Plan Personalization Logic Around Exposure: Write criteria and payloads so that offers meant to be shown publicly never reference sensitive fields.
Preview Mode: Use the UI’s “Preview” or “Test” function to confirm which sections/attributes will be visible to browsers.
Documentation and Handoffs: Annotate payload field names and use in-app descriptions or documentation to clarify which sections are client-safe for downstream engineers or product managers.
Suppose you configure two offer sections:
Welcome Banner
Payload: { "welcome_message": "Hello, new user!" }
All attributes: non-sensitive
Exposed to client-side API responses.
Loyalty Discount
Payload: { "discount_code": "LOYAL-15", "membership_tier": batch attribute (Sensitive) }
Contains at least one sensitive attribute
Redacted; API returns empty object for this section.
| Section Name | Attributes Used | Any Sensitive? | Client API Result |
|---|---|---|---|
| Welcome Banner | welcome_message (non-sensitive) | No | Returns: { "welcome_message": ... } |
| Loyalty Discount | discount_code, membership_tier | Yes | Returns: {} (section redacted) |
Audit all payload sections before go-live.
Update documentation so marketing/content teams know which offers can be public.
Avoid including unnecessary attributes in a section if there’s any chance of sensitivity confusion.
Use visual indicators and UI warnings—never ignore a locked/redacted status if the goal is public exposure.
This section provides a practical guide for integrating client-side Real-Time Personalization 2.0 via browser JavaScript, highlighting how to safely and efficiently fetch personalization offers in real time for in-page experiences. It addresses the requirements for public tokens, CORS-enabled endpoints, request/response design patterns, and underscores the privacy and security differences from server-side implementations.
Client-side integration uses secure, CORS-enabled endpoints designed for direct calls from browser JavaScript. All requests must use a public RT Personalization token, never a private or server-side token.
Example: Browser-side Fetch Request
https://us01.p13n.in.treasuredata.com/public/<YOUR_DB_NAME>/<YOUR_TABLE_NAME> Notes:
Region-specific domains and “/public/” path must be used for client/browser calls.
<YOUR_DB_NAME>is your streaming event database.<YOUR_TABLE_NAME>is the table with your real-time events.
fetch('https://us01.p13n.in.treasuredata.com/public/my_shop_db/event_table', {
method: 'POST',
headers: {
'Content-Type': 'application/vnd.treasuredata.v1+json',
'WP13n-Token': '12345/3/PUBLIC_TOKEN_ABC',
'Authorization': 'TD1 <WRITE API KEY>'
},
body: JSON.stringify({
td_client_id: '1986b2a4-3957-4863-be2c-7ef36a14afee',
td_url: window.location.href,
td_path: window.location.pathname,
product_name: 'women’s-tank-top',
product_category: 'women',
product_list: ['women’s-running-shoes', 'kids’-hoodie', 'women’s-tank-top'],
category_list: ['women', 'kids']
// ... any other non-sensitive fields you’ve configured
})
})
.then(response => response.json())
.then(data => {
// Handle personalization offers here, e.g., update UI sections
console.log('Personalization Offers:', data.offers);
}); Example: Browser-side Fetch Request
fetch('https://us01.p13n.in.treasuredata.com/public/my_shop_db/event_table', {
method: 'POST',
headers: {
'Content-Type': 'application/vnd.treasuredata.v1+json',
'WP13n-Token': '12345/3/PUBLIC_TOKEN_ABC',
'Authorization': 'TD1 <WRITE API KEY>'
},
body: JSON.stringify({
td_client_id: '1986b2a4-3957-4863-be2c-7ef36a14afee',
td_url: window.location.href,
td_path: window.location.pathname,
product_name: 'women’s-tank-top',
product_category: 'women',
product_list: ['women’s-running-shoes', 'kids’-hoodie', 'women’s-tank-top'],
category_list: ['women', 'kids']
// ... any other non-sensitive fields you’ve configured
})
})
.then(response => response.json())
.then(data => {
// Handle personalization offers here, e.g., update UI sections
console.log('Personalization Offers:', data.offers);
}); Never embed or expose private RT tokens or TD API keys in frontend/browser code. Only use tokens intended for public (publishing) use.
CORS headers are issued only if:
The request uses a valid, active public token.
The Origin header matches allowed browser origins (per TD configuration).
Attempts to use private tokens or incorrect endpoints in browser JS will return a 4xx error with no CORS headers, causing the request to fail in the browser.
If the request uses a valid token but the payload references any attributes marked "Sensitive", those sections will be blank (see payload examples below).
Example Request (JSON):
{
"td_client_id": "42a508e2-d9b1-4baa-9eb2-6c3fb8bd5e16",
"td_url": "https://treasuredemos.com/retail/shop/women",
"td_path": "/retail/shop/women",
"product_name": "women’s-tank-top",
"product_category": "women",
"product_list": [
"women’s-running-shoes",
"kids’-hoodie",
"women’s-tank-top"
],
"category_list": [
"women",
"kids"
]
} Example Successful Response (only non-sensitive attributes)
{
"offers": {
"Welcome Banner": {
"attributes": {
"welcome_message": "Welcome to our website! Enjoy your shopping!"
}
},
"Silver rewards just for you!": {
"attributes": {
"first_name": "John",
"total_purchase": 28700,
"items_purchased": [],
"order_summary": "Here is your order summary!",
"thank_you_message": "Thank you for shopping with us!",
"promotions_message": "Enjoy your 15% discount for your next purchase!"
}
}
}
} Example Response When Sensitive Attributes Are Present
{
"offers": {
"Welcome Banner": {
"attributes": {
"welcome_message": "Hello, new user!"
}
},
"Loyalty Discount": {
} // This section references a sensitive attribute and is redacted
}
} Notes:
The client only receives data in sections where all attributes are non-sensitive.
This strict redaction ensures PII or protected data is never sent to browsers.
Note that if any offer section includes at least one attribute marked as Sensitive (per attribute setup in the UI), that section is redacted.
| Aspect | Client-side API Call | Server-side API Call |
|---|---|---|
| Endpoint | /public/{db}/{table} | /{db}/{table} (no /public) |
| Token Type | Public only (publishing) | Private or public (configurable) |
| Additional Auth | API keys in browser | API key in server header |
| CORS | Required and enforced; blocks on error | Not used/required |
| Sensitive Attributes | Redacted; {} for affected sections | Always included if authorized |
| IP Whitelisting | Prohibited for public/browser tokens | Supported for private/server tokens |
403/401/No CORS?
Double-check that you are using a valid public token for the right personalization service.
Make sure the Origin is allowed and the endpoint path includes /public/.
Empty/blank sections in response?
- Verify attribute sensitivity in the Audience Studio UI; only non-sensitive attributes are returned for the browser.
Handling Future SDK Support:
Until the official TD JS SDK is updated, use the native fetch/XHR pattern described above for browser calls.