JavaScript SDK
JavaScript client for calling API integration.
Using perselioReady
perselioReadyperselioReady is the recommended way to run your code once the Perselio SDK is fully initialized and ready to use.
It works safely in all situations:
- before the SDK script is loaded,
- while it is loading,
- and after it is already initialized.
Your callback will always be executed exactly once, with the Perselio public API passed as an argument.
Bootstrap Snippet
Place this snippet before loading the Perselio SDK:
<script>
window.perselioReady =
window.perselioReady ||
function (cb) {
(window._perselioReady = window._perselioReady || []).push(cb);
};
</script>This creates a lightweight stub that queues callbacks until the SDK is ready.
Registering a Callback
You can now safely register a callback anywhere on the page:
window.perselioReady(async function (perselio) {
const result = await perselio.client.recommendation.getRecommendation({
scenario: {
scenarioId: 'example_scenario',
itemId: 'ITEM_123',
},
filters: [{ filterId: 'availability-filter', available: true }],
includeFields: ['url', 'itemId', 'name'],
limit: 3,
});
console.log(result);
});When the SDK is ready, your callback receives the perselio API object and can immediately start making requests.
Example response:
{
"recommendationId": "abc12345-0000-0000-0000-000000000000",
"items": [
{
"itemId": "ITEM_A",
"name": "Sample Product A",
"url": "https://example.com/product-a"
},
{
"itemId": "ITEM_B",
"name": "Sample Product B",
"url": "https://example.com/product-b"
},
{
"itemId": "ITEM_C",
"name": "Sample Product C",
"url": "https://example.com/product-c"
}
],
"totalItemsCount": 42
}Automatic Identification & Deduplication
Every recommendation request sent through the Perselio SDK is automatically enriched with identification data. You do not need to provide these values manually.
The SDK injects:
zoeId– anonymous browser identifieruserId– known user identifier (if available)pageInstanceId– unique identifier of the current page instance, used for deduplication
These identifiers allow Perselio to:
- personalize results consistently across pages and sessions,
- avoid returning duplicate items within a single recommendation response,
- correlate requests for analytics and optimization.
You can focus purely on describing what you want to recommend; Perselio handles who the recommendation is for.
Marking Rendered Recommendations
When you render recommendation widgets yourself (instead of using Perselio-managed widgets), the Perselio analytics collector has no way to tell that the displayed items came from a Perselio recommendation API. A lightweight DOM contract solves this: mark the rendered block with data attributes so impressions and interactions can be attributed to Perselio recommendations.
Use this contract when you call a Perselio recommendation API and render the resulting UI on your own pages.
HTML attributes
Add the attributes to the element that wraps the recommended items:
<div
data-per-recommender="homepage-carousel"
data-per-recommendation-id="abc12345-0000-0000-0000-000000000000"
>
<!-- recommended products rendered by you -->
</div>data-per-recommender— required. Marks a DOM area as a tenant-rendered Perselio recommendation surface. The value is a display name describing the placement, for examplehomepage-carousel,product-detail-similar, orcart-upsell. It is used to label the surface in analytics dashboards (e.g. Superset).data-per-recommendation-id— optional but recommended. When present, it must contain therecommendationIdreturned by the recommendation API response. This links the rendered impression to the exact API response.
Passing the recommendation ID from the API response
The recommendation API returns a recommendationId. Carry it into the rendered markup:
window.perselioReady(async function (perselio) {
const result = await perselio.client.recommendation.getRecommendation({
scenario: { scenarioId: 'recommended_for_you' },
includeFields: ['url', 'itemId', 'name'],
limit: 4,
});
const container = document.querySelector('#homepage-recos');
container.setAttribute('data-per-recommender', 'homepage-carousel');
container.setAttribute('data-per-recommendation-id', result.recommendationId);
// render result.items inside `container` …
});What Perselio tracks from marked blocks
- Impressions — when a marked recommendation surface becomes visible.
- Interactions — clicks and other interactions on items inside a marked surface.
If data-per-recommendation-id is present, analytics is linked to the exact recommendation API response. If it is missing, events are still classified as Perselio recommendation interactions, but with weaker attribution.
Item-level markup (e.g. per-product or per-position attributes) is not required. Only the wrapping recommendation surface needs to be marked.
Validation checklist
- The wrapper element carries
data-per-recommenderwith a descriptive value. data-per-recommendation-idis set from the API responserecommendationId(recommended).- The attributes are present on the element that wraps the recommended items, not on the individual items.
- The recommendation surface is marked before it becomes visible to the user.
Scenarios & Parameters
The scenario object defines what type of recommendation you are requesting and which contextual parameters should be used.
Each scenario represents a distinct recommendation strategy and accepts a specific set of parameters. The most common fields are:
itemId– contextual item (e.g. the product currently viewed)cartItemsIds– list of item IDs currently in the cartcategoryId– category context
Example scenarios (non-exhaustive):
quick_picks
quick_picksFast, context-aware picks for the current item.
{
scenarioId: 'quick_picks';
itemId: string;
cartItemsIds?: string[] | null;
categoryId?: string | null;
}recommended_for_you
recommended_for_youPersonalized recommendations for the current user, optionally contextualized by page state.
{
scenarioId: 'recommended_for_you';
itemId?: string | null;
cartItemsIds?: string[] | null;
categoryId?: string | null;
}accessories
accessoriesAccessory or complementary items for a specific product.
{
scenarioId: 'accessories';
itemId: string;
cartItemsIds?: string[] | null;
categoryId?: string | null;
}pre_cart
pre_cartRecommendations triggered when an item is added to the cart.
{
scenarioId: 'pre_cart';
itemId: string;
cartItemsIds?: string[] | null;
categoryId?: string | null;
}The complete and authoritative specification is available here:
- API reference: https://docs.perselio.com/reference/getrecommendation
- Conceptual overview: https://docs.perselio.com/docs/reco-widgets
These documents describe:
- all supported scenario types,
- required and optional parameters for each scenario,
- available filters and their semantics,
- response structure and pagination behavior.
Always consult the reference when introducing a new scenario type to ensure that your request matches the expected schema.
Guarantees
- Your callback is never lost, even if registered before the SDK loads.
- If the SDK is already initialized, the callback runs immediately.
- Errors inside your callback do not affect the SDK or the page.
- Multiple callbacks can be registered independently.
This pattern is ideal for embedding Perselio on third-party sites where script load order cannot be guaranteed.
GTM integration
If GTM/dataLayer integration is enabled for the SDK setup, Perselio can push a perselio.ready event to window.dataLayer after initialization.
This lets you consume Perselio identification values directly in GTM (for example in custom variables, tags, or triggers).
Example payload:
{
"event": "perselio.ready",
"perselio": {
"identification": {
"zoeId": "<ZOE_ID>",
"userId": "<USER_ID>",
"pageInstanceId": "<PAGE_INSTANCE_ID>"
}
}
}Notes:
- The event is optional and depends on integration configuration.
userIdmay be missing or empty for anonymous users.
Updated about 1 month ago

