Implement Personalized Campaigns
How to implement Product Recommendations, Dynamic Bundles and Onsite Content Personalization.
If you have custom requirements like customer group pricing/visibility or a highly complex product card, we recommend using one of the Nosto APIs to only retrieve the core product data via JSON and get prices and visibility from your platform instead of sending it to Nosto.
If you only have a complex product card but are using a Shopify theme, you can consider using our dynamic product cards
Prerequisites
Good to know before you start
Every Nosto account comes with a set of default product recommendation campaigns and "placements" (empty
<div/>elements).You can see the mapping of campaigns and placements in the Nosto Admin UI: Product Experience Cloud -> Recommendations.
These are sorted into the different page types like homepage (e.g.
#nosto-frontpage-1), PLP, PDP, SERP, 404 page as well as general layout areas like the mini-cart drawer or search overlay/autocomplete.
Placements need to be set up in your store templates. On Shopify and Shopware, you can use our content blocks. For assistance in setting up placements on your store, please reach out to your Nosto POC or Nosto's support team.
Nosto campaigns need to be injected into the placements - automatically or manually, depending on your tech stack and implementation method.
Nosto offers you several helper methods to inject campaign into the DOM, you'll find details at the end of this page.
Templates for RECs campaigns can be hosted and maintained in Nosto or built within your own code base (API approach, recommended for headless and SPAs when using a custom code setup).
Depending on your implementation method and tech stack, different options to attribute clicks from Nosto campaigns are available (it might need a few lines of custom code, you'll find details below per implementation method).
Please note: If you have the Nosto preview enabled, attribution/references will not show in the Nosto debug toolbar.
OCP and RECs campaigns are always associated with exactly one placement.
The placements are also used for A/B testing, e.g. testing campaign A vs. campaign B inside of placement
#nosto-productpage-1.Requesting campaigns via GraphQL is limited (no A/B testing, no dynamic filtering).
How it works
After the Nosto script is loaded on a page, you can send a request to Nosto and will receive the campaigns for this specific page.
Your request to Nosto needs to include certain data like the current page type, what's on the page (e.g. product data, the current category or search term), what's in the cart, customer details if the customer is logged in and what placements are on the page.
You'll see this
ev1request in your network tab and will monitor it extensively while implementing Nosto.
The Nosto response includes mostly the recommendation campaigns but also meta data like the number of pages visited in the current session, a session ID, a customer ID and more.
OCP campaigns are always returned as raw HTML.
RECs/Bundles campaigns can be returned as raw HTML or JSON (JSONResult with [JSONProduct]).
Depending on your tech stack and templating method, the campaigns get automatically injected into the page (conventional) or need to be explicitly rendered (advanced).
Interactions with Nosto campaigns (like clicking on a product, selecting a variant/color swatch or clicking on a banner) need a certain attribution that always follows the same pattern: "This event X (page/product/variant/… has been viewed/selected) after an interaction with the campaign Y (on page Z (optional)).":
Product ID 8 was viewed after a click in RECs campaign
nosto-pdp-topon the PDP with product ID 4.Product ID 6 was viewed after a click (quick view modal or PDP redirect) in RECs campaign
nosto-frontpage-mid.
Example Nosto response:
Implementation Methods
Since OCP campaigns always return HTML content, this guide only compares product recommendations (RECs and Bundles). (Example response and type reference above.)
Client: Automatic Injection with Nosto Autoloading
This method is the fastest and works best for conventional builds where the templates are built within the Nosto backend with Apache Velocity. This approach is not suitable for SPAs since interactions trigger a full page load.
By default, the Nosto autoloader is enabled and content will be automatically injected into the templates on the page.
Attribution is automatically handled by Nosto as it knows which HTML template was used in what campaign.
If you are on Shopify, we recommend to evaluate our dynamic product cards which allow you to re-use your existing product cards.
You can make use of several Nosto-variables inside of your template.
You will find a full reference and examples in the Nosto backend when you're building your template.
Client: JS API: createRecommendationRequest()
createRecommendationRequest()In case you want more control about the campaign loading, you can disable autoloading and request the campaigns yourself. This approach is also suitable if you only want to request the product data in JSON per campaign and build the templates yourself. This approach is not suitable for SPAs or headless frontends, please see Session API: defaultSession() below.
The campaigns can return
HTML(default, for templates hosted at Nosto) orJSON, depending on how you build the request.By default, the request does not know anything about the current page, placements on the current page, logged in customer, cart content etc. and you have two options of passing that data:
Including the HTML tagging with
{includeTagging: true}Setting the data manually via JS, e.g.
setPageType("product").setProducts([product_id: "4"])In most cases it will be sufficient to only include the page tagging since it reads the current product, cart content etc. and add a
.setPlacements(api.placements.getPlacements())call.Advanced cases where you need to explicitly set data occur when e.g. a variant has been selected on a PDP or if products should be filtered by a certain tag (e.g. for cannabis state-specific regulation or for vehicle-specific parts).
You can overwrite parts of the page tagging and filter products in a recommendation using dynamic filtering.
Attribution is automatically handled by Nosto when using the default
response mode HTML.If you use the
JSON response mode, you can simplify DOM injection and click attribution with Nosto's helper methods.
This approach is recommended for custom frontend builds, we recommend looking into the Nosto Open Source packages.
Client: Session API: defaultSession()
defaultSession()In case you are running a SPA or headless frontend, you want more control about the campaign loading and need to disable autoloading to request the campaigns yourself.
You can also find a video for the Session API in the Nosto Partner Academy, just reach out to your Nosto contact if you don't have access yet. We also recommend to bookmark the video to debug the Session API.
The campaigns return
JSONby default, but in comparison to the JS API, you incorporate requesting campaigns with your page tagging/tracking viadefaultSession()(reference).Page tagging refers to the JS API (taggingProvider) and uses HTML and MUST NOT be mixed with the Session API.
Page tracking is similar to the page tagging but uses JavaScript calls to let Nosto know what is on the current page. For example:
The page tracking sends the same
ev1request which responds with the same campaign data and the same principles as the JS API.Since requesting campaigns is tied to the
defaultSession()for page tracking, you can run a very similar code block on the different page types (examples here and in the API reference).The methods like
viewFrontPage()orviewProduct("4")are the main indicator that campaigns will be returned.Adding
setPlacements(api.placements.getPlacements())or passing the placement IDs explicitly as an array determines from where campaigns will be requested. We recommend the first approach, getting all campaigns for all placements instead of requesting them one by one.Nosto provides you with ways to easily inject campaigns into placements and sets up event listeners for click attribution.
Calling
load()sends the request to Nosto, the returned Promise can be handled async or by chaining athen()to the request.Since there is no page tagging, you need to use the "Visitor" tab in the Nosto Debug Toolbar and the
ev1request in your network tab for verification and QA.There are several advanced cases to keep in mind and cover:
Using the category path that's in the Nosto backend (use the "Preview" feature and Nosto Debug Toolbar), not the URL slug.
You can filter products in a recommendation using
viewCustomField()which is the equivalent to dynamic filtering via the JS API (you MUST NOT mix these APIs).If you are using the
setRef()method (reference), pay close attention - the second parameter is the recommendation slot id (result_idof the response), not the placement div id.Using
load()only on the first request on the current page because it increments the page view counter (pvin the "ev1" response). On subsequent requests on the same page you must send the request withupdate()or pass a recommendation request flag like.load{skipPageViews: true}(details here).
You can still
setResponseMode("HTML")and request the Nosto-hosted templates if you're not running a SPA. The click attribution and template injection can be automated by callingenableCampaignInjection()(example).
Server: GraphQL API: updateSession()
updateSession()In case you don't want follow one of the client-based approaches, you can manage the Nosto session and campaign rendering via GraphQL.
Please beware of the following limitations:
You request the campaigns for a specific product ID or category (without placements) and will receive the RECs campaign IDs directly.
Therefore, you can't use Nosto built-in A/B testing for campaign widgets.
You need an alternative, full page A/B testing like Omniconvert in this case.
Dynamic filtering is not possible via GraphQL. We highly recommend to go with the Session API and use
viewCustomFieldNosto OCP cannot be retrieved via GraphQL (personalized banners or other HTML content).
The page tagging/event tracking (current customer data and shopping cart) can also be done via a GraphQL mutation that returns the session ID, example:
The request/response concept is the same as with the Session API: specify data about the session (cart and customer, see above), request product recommendations for a given page type and render the template while keeping attribution in mind. You will need to:
Set the
params.eventto match the current page type and specific e.g. the product ID, category path or search term for correct tracking and attribution.The
refparameter must match theresultId(= Nosto recommendation campaign slot ID) from the response (example response above).
Set the correct page type (
PageRequestEntityin the API reference) underpagesto specify the context from which you want to receive Nosto campaign data.
Parse the Nosto response and render your template.
Make sure you save the
resultIdand pass it to your nextupdateSession(params: { event: { type: VIEWED_PRODUCT } } )asreffor attribution when a shopper clicks on one of the products inside of your template.Since you don't use JavaScript, there is no event listener or helper function Nosto can provide. You will build the process yourself that is outlined in the parameterless attribution documentation (detailled example below).
DOM Injection and Click Attribution
Typical use case, options and adjustment depending on your implementation method:
A shopper is on a PDP (e.g. product ID 42), sees a Nosto product recommendation and clicks on a shown product (ID 200). You don't explicitly react to the click, you instead make sure the click listener for parameterless attribution is firing. See the parameterless attribution documentation for more details.
If you're using Nosto-hosted templates with autoloading, you don't need to do anything. Parameterless attribution is enabled and set up by default.
If you're manually requesting Nosto-hosted HTML templates via the JS API, you have two options:
Let Nosto inject the campaigns into the DOM via
injectCampaigns(), this is recommended, attribution is set up automatically.Inject the campaigns into the DOM yourself and set up attribution manually via attributeProductClicksInCampaign after rendering the campaign (example here).
If you're manually requesting Nosto-hosted HTML templates via the Session API, we recommend to add
enableCampaignInjection()to yourdefaultSession(). Nosto will automatically inject the campaigns into the DOM, parameterless attribution is enabled and set up by default.If you're manually requesting only the product data via JSON from a Nosto campaign via the Session API, you have two options after you've built the HTML for your campaigns in your code base:
Let Nosto inject the campaigns into the DOM via
injectCampaigns(), this is recommended, attribution is set up automatically.Inject the campaigns into the DOM yourself and set up attribution manually via attributeProductClicksInCampaign after rendering the campaign.
When a user then clicks on a product link within a Nosto recommendation (e.g. slot ID "productpage-nosto-2-fallback"), Nosto's event listener (previously set up via
enableCampaignInjection()for HTML templates andinjectCampaigns()orattributeProductClicksInCampaign()for JSON-based templates) captures and stores the current URL and reference of theresult_idin the shopper's browser local storage.The browser then navigates to the product URL.
The Nosto client script reads the previous URL and reference from the local storage and sets it as
refparameter for the ev1 request, which results in the attribution of the current product view to the previously shown recommendation campaign.
Comparison Table
Feature
Automatic Injection with Nosto Autoloading
JS API: createRecommendationRequest()
Session API: defaultSession()
Nosto Content via GraphQL
Best For
Conventional builds
Custom frontend builds (non-SPA) with e.g. customer group pricing/visibility (every platform) or highly complex product cards (non-Shopify)
SPAs and Headless frontends
Mobile apps or server-side rendered builds (when Nosto A/B testing, dynamic filtering and OCP isn't needed)
How it Works
Content is automatically injected into page templates.
Manually request campaigns after disabling autoloading.
Request campaigns as part of the page tracking/tagging flow.
Request campaigns as part of the page tracking/tagging flow.
Campaign Response Type
HTML (for Nosto-hosted templates)
HTML (default) or JSON
JSON (default), but can be set to HTML
RECs campaign slot IDs (no placements, OCP campaigns are not available)
Campaign Injection and Click Attribution
Handled automatically by Nosto.
Automatic for HTML mode with enableCampaignInjection(). For JSON mode, use injectCampaigns() or inject campaigns yourself and add api.attributeProductClicksInCampaign().
For JSON mode, use injectCampaigns() or inject campaigns yourself and add api.attributeProductClicksInCampaign(). Automatic for HTML mode.
Manual. Requires careful use of the event params in updateSession() mutation.
SPA Suitable
No (triggers a full page load)
No (recommended for custom builds, but not SPAs)
Yes (designed for SPAs and Headless)
Yes
Headless compatible
No
No
Yes
Yes
Fully customizable frontend
Yes
Yes
Yes
Yes
Suitable for complex use cases
Sometimes
Yes
Yes
Yes
Customized and managed only in Nosto dashboard
Yes (templates are in Nosto backend)
Depends on (can build templates in Nosto or own code base, injection needs to be triggered manually via JS)
Unlikely (you can build templates in Nosto but will likely build them in the own code base, injection needs to be triggered manually via JS)
No (can build templates in own code base via server-side rendering)
A/B Testing
Yes (via placements)
Yes (via placements)
Yes (via placements)
No (Nosto built-in A/B testing is not available, needs full page testing like OmniConvert)
Drawbacks
Not suitable for SPAs or Headless.
Not suitable for SPAs or Headless.
Requires a bit more planning because page tracking and campaign injection are combined
No Nosto A/B testing. No Dynamic Filtering. No OCP (HTML content/banners).
Last updated
Was this helpful?