Skip to main content

Tagged Products SDK – Developer Guide

Use the tagged-products format when another system already renders the product cards on your page, for example a recommendation widget, and some of those products are advertised on GoWit.

The SDK does not render anything. It finds the cards your widget marked, asks the ad server which of them are sponsored for a dedicated placement, and attaches click tracking to the matched cards. Impressions are recorded when the ad server answers, so the request is sent only for cards that are on screen.


1. Quick Start​

Add the shared SDK configuration and script to your site. The configuration is the same as for the Sponsored Product SDK.

  • UUID: Your marketplace's unique identifier. You can find this in your GoWit dashboard.
  • Hostname: The URL of your GoWit ad server. Your GoWit team will provide your hostname during integration setup.
<script>
window.__rma__conf = {
base_url: "YOUR_HOSTNAME_HERE",
id: "YOUR_UUID_HERE",
auto_impression: true,
};
</script>
<script
defer
id="retail-ads-library"
src="https://sdk.gowit.com/gowit.js"
></script>

Requirement: auto impression must be on for your marketplace, and auto_impression: true must be in the configuration. This format never sends impression events from the browser. With auto impression off, the placement records no impressions and no CPM spend.


2. The Ad Placement​

Create a dedicated Sponsored Product placement for the widget in the GoWit dashboard and turn on the setting Only products sent in the request. With this setting the ad server answers only with products whose SKU was sent in the request. Products outside the request are never returned.

Three settings matter for a widget placement:

SettingRecommendation
Minimum ads0 or 1. The SDK sends small requests, one per batch of visible cards.
Maximum adsCaps each response. Set it to at least batch_size (default 10): sponsored cards above the cap get no ad and are not asked again on this page.
Page contextThe page type the widget sits on. Campaigns are eligible by page type, as for every placement.

See Ad Placement Setup for the full form.


3. Marking the Cards​

The system that renders the cards marks every card that may carry an ad with one attribute on the card's root element:

<div class="product-card" data-gowit="1">
<a class="product-link" href="/drill-pro-2000/p/1000089639">...</a>
<button data-code="1000089639">Add to favourites</button>
</div>

The SDK needs two things from a marked card:

NeedDefault sourceConfigurable with
The marker[data-gowit="1"] on the card rootcard_selector
The SKUA data-code attribute on the card or any element inside it; if none, the first link whose path contains /p/<sku>sku_attribute, sku_extractor

The SKU must be the same product identifier you send to GoWit in your product feed. A card without a SKU is skipped.


4. Pushing the Format​

<script>
window.__rma__ads = window.__rma__ads || [];
window.__rma__ads.push({
format: "tagged-products",
placement_id: YOUR_PLACEMENT_ID, // the widget placement, as a number
root: ".recommendation-widget", // optional, default: the whole document
card_selector: '[data-gowit="1"]', // optional, default shown
sku_attribute: "data-code", // optional, default shown
batch_size: 10, // optional, default 10
debounce_ms: 150, // optional, default 150
label_mode: "none", // optional: "none" | "badge"
onRender: (matched) => console.log(matched.length, "sponsored cards"),
onError: (err) => console.log("Tagged products failed", err),
});
</script>
FieldDescription
formatMust be "tagged-products".
placement_idIdentifier of the widget placement. Must be a positive integer; a numeric string such as "12" is accepted. Any other value (0, null, "", a non-numeric string) stops the format and calls onError.
root(optional) CSS selector or element that contains the widget. Limits the scan to that element. Defaults to the document. A selector that matches nothing yet is not an error: the SDK waits and scans the element when it renders.
card_selector(optional) Selector of the marked cards. Default [data-gowit="1"].
sku_attribute(optional) Attribute that carries the SKU on the card or inside it. Default data-code.
sku_extractor(optional) (cardElement) => string | null. Overrides the attribute and the link parsing.
batch_size(optional) Maximum SKUs per ad request. Default 10.
debounce_ms(optional) Wait before a request, so cards that appear together share one request. Default 150.
label_mode(optional) "none" adds nothing. "badge" appends a small label to each matched card: the ad server's label, else "AD" in the browser language.
label_text(optional) Text of the badge. Defaults to the label the ad server returns, else the SDK's translation.
onRender(optional) Called after each batch with the matched cards: [{ sku, ad, element }].
onError(optional) Called with the Error or the failed Response when a request fails or the config is invalid: a non-positive placement_id, a selector the browser rejects, or a root that is neither a selector nor an element.

Push the format once per page. The SDK keeps watching the page for cards that appear later. A second push for the same placement replaces the first one and keeps its answers, so no SKU is asked twice.


5. How It Works​

  1. The SDK watches the page with a MutationObserver, so cards rendered after page load are found. A root selector that is not on the page yet is picked up when it renders.
  2. Each marked card is observed. When at least 10% of a card is visible, its SKU joins the next batch.
  3. After debounce_ms, the SDK sends one ad request per batch_size SKUs to the widget placement, with max_ads equal to the number of SKUs in the request. The SKUs travel in the request's products list.
  4. The ad server returns the SKUs that are sponsored right now, each with an ad_id. Impressions are recorded at this moment.
  5. The SDK matches each returned ad to its card by SKU and attaches click tracking. A click is sent once per ad and the card's own link keeps working.
  6. Every SKU is asked about once per page. A card that the widget re-renders is re-attached from the page cache, without a new request. If the widget reuses a card element for another product, the SDK removes the old click tracking and badge and treats the card as new.

A marked card gets no ad when the product has no active campaign, is out of stock, has no budget, or when the widget's list is older than the campaign change. This is expected.


6. Debugging​

Add #gowit_sdk_debug to the URL. The console then shows the format settings at start, a warning for each marked card without a SKU, a note while a root selector is still pending, and the server answer for a batch with no ad.

Common causes of "no ad on a marked card":

  • The placement setting Only products sent in the request is off. The server then answers with its own ranking, and the SKUs rarely match.
  • placement_id is not a positive integer, or card_selector / root is not a valid selector. onError fires and no request is sent.
  • The SKU on the card is not the SKU in your product feed.
  • The card was never on screen. Scroll the carousel.

7. FAQ​

Q: Does the SDK change the widget's markup?
A: No. It only adds a click listener, and a badge when label_mode is "badge". For the badge it also sets position: relative on a card whose position is static.

Q: Why are impressions not sent from the browser?
A: The ad server records the impression when it answers, and the SDK asks only for cards on screen. A second impression from the browser would count the same view twice, so the format never sends one.

Q: Can I use this on search and category pages too?
A: Yes. Set search_term or category_path in window.__rma__conf as for the other formats; they are sent with every request.