Brand Store (Web)
A button on the product detail page that redirects users to the brand's store
Brand Store (Web)
A button on the OOP (product detail page) displayed below the product that redirects users directly to the brand's official store page.
What Is Brand Store?
Brand Store is a sponsored button that appears on product detail pages. When a user clicks it, they are redirected to the brand's (manufacturer's) official store where they can purchase the product directly.
Key concept: The ad server tells you IF a campaign is active for a given brand. Your shop decides WHETHER to display the button based on your own business logic.
How It Works
What the Ad Server Provides
Based on the manufacturer_id you pass, the ad server checks if there is an active campaign for this brand (manufacturer). If yes, it returns:
- Confirmation that a sponsored ad exists
- Click tracking URL for revenue attribution
- Brand logo URL in the
imagefield of the creative
Important: The ad server provides tracking information and the brand logo URL. Price and store URL still come from YOUR shop system.
What Your Shop Must Check
Before displaying the button, your shop should verify:
- Brand has a store page - Does this manufacturer have a brand shop in your system?
- Product offer exists - Does the brand's store have an offer for the current product?
- Price is competitive - Is the brand's offer cheaper than (or equal to) the current best price?
Display logic: Only show the Brand Store button if all conditions are met: active campaign (from ad server) + brand shop exists + competitive offer (from your shop).
Data Sources
| Source | Data |
|---|---|
| Ad Server | Whether campaign is active, click tracking URL, brand logo URL |
| Your Shop | Brand shop URL, price, shop name, offer availability |
Data Flow
- Pass
manufacturer_idto ad server viafetchNativeAd()or bidder request - Ad server returns tracking info IF campaign is active for this brand
- Your shop checks: Does brand have a store? Is offer available and competitive?
- If all conditions met → render button with your shop data + ad server tracking
Integration Flow Diagram
sequenceDiagram
participant User as Shop User
participant Page as Shop Page
participant ShopAPI as Shop API/Database
participant DAS as Ring DAS
User->>Page: 1. Request product page
Page->>DAS: 2. Fetch Ad (fetchNativeAd / bidder)
DAS-->>Page: Response with tracking URLs (if campaign active)
Note over Page: 3. Check if ad exists
Page->>ShopAPI: 4. Fetch brand store data
ShopAPI-->>Page: Brand shop URL, price, availability
Note over Page: 5. Verify conditions:<br/>- Brand shop exists?<br/>- Offer available?<br/>- Price competitive?<br/>(Logo comes from ad response)
alt All conditions met
Page->>User: 6. Display Brand Store button
Note over Page: Fire impression tracking
User->>Page: 7. Click button
Page->>DAS: Fire click tracking
Page->>User: Redirect to brand store
else Conditions not met
Note over Page: Hide ad slot
end
Live Demo
See the working implementation:
Frontend Integration (CSR)
Step 1: Load the SDK
Configure the SDK with your Ring DAS credentials. You will receive these values from your Ring DAS account manager.
| Parameter | Description |
|---|---|
target | Site and area identifier (see details below) |
tid | Your Ring DAS tenant ID (format: EA-XXXXXXX) |
dsainfo | Set to 1 to enable DSA (Digital Services Act) transparency info in responses |
Target format:
site/area
- site - Your website identifier assigned by Ring DAS, UPPERCASE (e.g.,
DEMO_PAGE)- area - Page type context where the ad appears, UPPERCASE:
HOMEPAGE,PRODUCT_DETAIL,LISTING,SEARCH- Mobile prefix - For mobile pages, add
M_prefix to site (e.g.,M_DEMO_PAGE/PRODUCT_DETAIL)Examples:
- Desktop product page:
DEMO_PAGE/PRODUCT_DETAIL- Mobile product page:
M_DEMO_PAGE/PRODUCT_DETAIL- Desktop homepage:
DEMO_PAGE/HOMEPAGE
<script>
dlApi = {
target: "DEMO_PAGE/PRODUCT_DETAIL", // Format: SITE/AREA. For mobile: M_SITE/AREA
tid: 'EA-<<NETWORK_ID>>', // your tenant ID - provided by Ring DAS
dsainfo: 1, // enable DSA transparency info
cmd: [] // command queue
};
</script>
<!-- SDK URL - provided by your Ring DAS account manager -->
<script src="https://<<DAS_CDN>>/<<NETWORK_ID>>/build/dlApi/minit.boot.min.js" async></script>The SDK script URL (
minit.boot.min.js) may differ depending on your integration. Your Ring DAS account manager will provide the correct URL for your setup.
Step 2: Configure Consent
As soon as possible after embedding the script, you should pass consent information. This determines whether personalized ads are served and controls the script's behavior.
dlApi.cmd.push(function (dlApi) {
dlApi.consent({npa: 0}); // 0 = consent given, 1 = no consent
});| Parameter | Value | Description |
|---|---|---|
npa | 0 | Consent given - personalized ads enabled |
npa | 1 | No consent - non-personalized ads only |
Step 3: Set Targeting Context
Set the manufacturer ID BEFORE fetching ads. This determines which brand's ad to display.
| Key-Value | Description |
|---|---|
manufacturer_id | Brand/manufacturer ID - determines which brand's ad to display |
IP | Page View ID — constant identifier for the current page load |
IV | Page View Unique ID — changes on every SPA view transition; equals IP on traditional pages |
TABID | Browser Tab Identifier — stable ID per browser tab session |
dlApi.cmd.push(function (dlApi) {
dlApi.addKeyValue('manufacturer_id', '12345678'); // determines which brand's ad to display
dlApi.addKeyValue('IP', '202603041502158687149647'); // page view ID
dlApi.addKeyValue('IV', '202603041502158687149647'); // page view unique ID (changes on SPA transitions)
dlApi.addKeyValue('TABID', 'tab-7f3e2a'); // browser tab identifier
});Why this matters: The
manufacturer_idtells the ad server which brand's campaign to check. For additional targeting options likecategory_idsandmain_category_id, see Set Targeting Context.
Step 4: Fetch the Ad
| Parameter | Description |
|---|---|
slot | Fixed value product-button for this format |
div | Container element ID - required for viewability measurement |
tplCode | Fixed value 1746213/Banner-Standard for Brand Store |
asyncRender | Set to true to manually control when impression is counted |
dlApi.cmd.push(function (dlApi) {
dlApi.fetchNativeAd({
slot: 'product-button', // fixed value for Brand Store
div: 'ad-brand-store', // container ID for viewability tracking
tplCode: '1746213/Banner-Standard', // fixed value for Brand Store
asyncRender: true // manually count impression with ad.render()
}).then(async function (ad) {
if (!ad) {
console.log('No ad available');
return;
}
// Ad exists - NOW fetch your shop data
// The ad server only provides tracking - YOU provide display data
const shopData = await fetchShopDataFromYourSystem('12345678');
// Render with YOUR shop data + ad tracking
renderBrandStoreButton(ad, shopData);
}).catch(function (err) {
console.error('Ad could not be loaded:', err);
});
// Trigger ad fetch
dlApi.fetch();
});Implementation note: The onclick handler shown below is an example. Your shop is responsible for implementing click tracking - simply fire a tracking pixel on product click using the constructed tracking URL.
Example code: The rendering function below is provided as a documentation example. Adapt it to your shop's templating system and styling requirements.
Step 5: Fetch Your Shop Data
The ad server tells you IF an ad exists and provides the brand logo. You must fetch price and URL data from your own system.
/**
* Fetch brand/product data from YOUR shop system
* @param {string} manufacturerId - Brand identifier used in targeting
* @returns {Promise<Object>} - Shop data for rendering
*/
async function fetchShopDataFromYourSystem(manufacturerId) {
// Replace with your actual product/brand API
const brandInfo = await yourBrandAPI.get(manufacturerId);
return {
productUrl: brandInfo.storeUrl, // URL to brand's store page
shopName: brandInfo.name, // Brand display name
price: brandInfo.currentOffer.price // Current price/offer
// Note: brand logo comes from ad.fields?.image (AD SERVER)
};
}Your responsibility: The function above is a template. Replace
yourBrandAPI.get()with your actual database query or API call.
Step 6: Render with Your Shop Data
/**
* Render the Brand Store button
* @param {Object} ad - Ad response from Ring DAS (provides tracking + brand logo)
* @param {Object} shopData - Your shop data (provides price and store URL)
*/
function renderBrandStoreButton(ad, shopData) {
// ─────────────────────────────────────────────────────────────
// DATA FROM AD SERVER (tracking + DSA info + brand logo)
// ─────────────────────────────────────────────────────────────
const clickUrl = ad.meta.adclick;
const dsaInfo = ad.dsa; // { behalf, paid, adrender }
const logoUrl = ad.fields?.image; // Brand logo from AD SERVER
// ─────────────────────────────────────────────────────────────
// DATA FROM YOUR SHOP (display info)
// shopData comes from fetchShopDataFromYourSystem()
// ─────────────────────────────────────────────────────────────
// shopData.productUrl - URL to brand's store page
// shopData.shopName - Brand display name
// shopData.price - Current price/offer
// Count impressions manually
ad.render();
// Render button combining SHOP data (price/URL) + AD SERVER data (tracking + logo)
const container = document.getElementById('ad-brand-store');
container.innerHTML =
'<span class="ad-label">Ad</span>' +
'<a href="' + shopData.productUrl + '" ' + // ← YOUR SHOP
'target="_blank" ' +
'rel="noopener nofollow sponsored" ' +
'onclick="new Image().src=\'' + clickUrl + '\';">' + // ← AD SERVER
'At <img src="' + logoUrl + '" alt="' + shopData.shopName + '"> ' + // ← AD SERVER (logo)
'for ' + shopData.price + // ← YOUR SHOP
'</a>';
}Backend Integration (SSR)
For server-side rendering, fetch ad data from the bidder before rendering the page.
Required: The SDK from Step 1 (Frontend) must still be loaded on the page for viewability tracking via
registerBidResponse().
Step 1: Fetch Ad from Bidder
Make a GET request to the Ring DAS bidder endpoint. The bidder URL will be provided by your Ring DAS account manager.
Request Configuration
| Parameter | Description |
|---|---|
BIDDER_URL | Bidder endpoint URL - provided by your Ring DAS account manager |
NETWORK_ID | Your Ring DAS network ID (without EA- prefix) |
tmax | Request timeout in milliseconds |
ext.src | Optional. Set to s2s for server-to-server requests |
ext.is_non_prebid_request | Set to true to receive the response in the correct server-to-server format (not Prebid.js format) |
Placement Parameters
These parameters define WHERE the ad appears and WHICH format to serve.
| Parameter | Description |
|---|---|
site.id | Your site identifier in Ring DAS |
site.ext.area | Page type context, UPPERCASE: HOMEPAGE, PRODUCT_DETAIL, LISTING, SEARCH |
imp[].tagid | Fixed value product-button for this format |
Targeting Parameters
| Parameter | Description |
|---|---|
ext.keyvalues.manufacturer_id | Manufacturer identifier for targeting |
ext.keyvalues.main_category_id | Main product category ID — primary category for ad matching and reporting |
ext.keyvalues.page_product_id | Product ID currently viewed — used for reporting purposes |
ext.keyvalues.page_product_name | Product name currently viewed — used for reporting purposes |
ext.keyvalues.IP | Page View ID — constant for the lifetime of a page load. See API Parameters Reference |
ext.keyvalues.IV | Page View Unique ID — changes on every SPA view transition; equals IP on traditional pages. See API Parameters Reference |
ext.keyvalues.TABID | Browser Tab Identifier — stable ID per browser tab session. See API Parameters Reference |
ext.keyvalues.ab_variant | A/B test variant identifier — string identifying which experiment variant the user is in (optional) |
Consent & Privacy Parameters
| Parameter | Description |
|---|---|
user.ext.npa | Consent flag: false = consent given, true = no consent |
regs.gdpr | GDPR applies flag: 1 = GDPR applies, 0 = does not apply |
regs.gpp | GPP consent string (optional) - TCF-compliant consent string from your CMP |
regs.ext.dsa | Set to 1 to request DSA transparency info in response |
Consent handling: You can pass consent via
user.ext.npa(simple flag) OR viaregs.gpp(TCF-compliant string). If you have a TCF-compliant CMP, use the GPP string for more granular consent information.
User Identifier
Important for backend integration: Pass a user identifier consistently per user. This enables frequency capping, personalization, and other targeting features. Without an identifier, each request is treated as a new user.
| Parameter | Description |
|---|---|
user.eids | OpenRTB Extended Identity Array — pass user identifiers with per-ID GDPR consent metadata. Supports session-level (atype: 500, no consent required) and device-level (atype: 1, consent required) identifiers. See API Parameters Reference for full field reference. |
user.ext.ids.lu | Local user ID from the ea_uuid cookie on your shop's domain (set by Ring DAS). Must follow the alphanumeric format (e.g., 202408221036415499301131). |
User identifiers:
user.eids— Pass your own session and/or tracking identifiers with GDPR consent metadata. Provide your session ID asatype: 500(no consent required) and your device/tracking ID asatype: 1(consent required).user.ext.ids.lu— The value from theea_uuidcookie set by Ring DAS. Used as Ring DAS's internal session identifier.Both can be sent simultaneously. See API Parameters Reference for the full
user.eidsfield reference.
// Node.js backend
const NETWORK_ID = `${NETWORK_ID}`; // your Ring DAS network ID
const BIDDER_URL = `https://das.idealo.com/${NETWORK_ID}/bid`; // provided by your account manager
// User identifiers — replace with actual values from your system
const SESSION_ID = 'your-session-id'; // session-level identifier (no GDPR consent required)
const TRACKING_ID = 'your-tracking-id'; // device-level tracking identifier (GDPR consent required)
const requestBody = {
id: Math.random().toString(16).substring(2, 15),
imp: [{
id: 'imp-1',
tagid: 'product-button', // fixed value for Brand Store
secure: 1,
native: { request: "{}" }
}],
site: {
id: 'DEMO_PAGE', // your site ID (UPPERCASE)
ext: {
area: 'PRODUCT_DETAIL' // page type (UPPERCASE): HOMEPAGE, PRODUCT_DETAIL, LISTING, SEARCH
}
},
user: {
eids: [{
source: 'your-domain.com',
inserter: 'your-domain.com',
uids: [
{
id: SESSION_ID,
atype: 500,
ext: { id_type: 'session', consent_required: false }
},
{
id: TRACKING_ID,
atype: 1,
ext: { id_type: 'tracking', consent_required: true }
}
]
}],
ext: {
npa: false, // false = consent given, true = no consent
ids: {
lu: '202408221036415499301131' // Ring DAS internal session ID (from ea_uuid cookie)
}
}
},
ext: {
network: NETWORK_ID,
keyvalues: {
manufacturer_id: '12345678', // manufacturer ID for targeting
main_category_id: 101, // main product category ID
page_product_id: '987654', // product ID for reporting
page_product_name: 'Example Product Name', // product name for reporting
IP: '202603041502158687149647', // page view ID
IV: '202603041502158687149647', // page view unique ID
TABID: 'tab-7f3e2a', // browser tab identifier
ab_variant: 'variant-b', // optional: A/B test variant identifier
},
is_non_prebid_request: true,
src: 's2s' // optional: indicates server-to-server request
},
regs: {
gdpr: 1, // 1 = GDPR applies, 0 = does not apply
gpp: 'YOUR_GPP_STRING', // optional: TCF-compliant consent string from CMP
ext: {
dsa: 1 // request DSA transparency info
}
},
tmax: 1000 // request timeout in milliseconds
};
// Send as GET request with body in data= parameter
const encodedData = encodeURIComponent(JSON.stringify(requestBody));
const response = await fetch(`${BIDDER_URL}?data=${encodedData}`);
// Check for no ad available (204 No Content)
if (response.status === 204) {
// No ad available for this request
console.log('No ad available');
}
const bidResponse = await response.json();No ad available: When no ad matches the request criteria, the server returns HTTP
204 No Contentwith an empty response body. Always check the status code before parsing JSON.
Step 2: Parse Response
const bid = bidResponse?.seatbid?.[0]?.bid?.[0];
if (!bid) {
// Fallback check - no bid in response
return null;
}
// Parse adm (it's a JSON string)
const adm = JSON.parse(bid.adm);
// Construct click tracking URL (from AD SERVER)
const clickUrl = adm.meta.adclick;
// DSA transparency info (from AD SERVER, requires regs.ext.dsa: 1 in request)
const dsaInfo = bid.ext?.dsa; // { behalf, paid, adrender }Step 2.5: Fetch Your Shop Data
Before rendering, fetch the product/brand details from your database:
// ─────────────────────────────────────────────────────────────
// FETCH DATA FROM YOUR SHOP DATABASE
// The ad server provides tracking + brand logo - YOU provide price and URL
// ─────────────────────────────────────────────────────────────
const shopData = await db.brands.findOne({
where: { manufacturerId: '12345678' },
select: {
storeUrl: true,
name: true,
currentPrice: true
// Note: brand logo comes from adm.fields?.image (AD SERVER)
}
});
// Now you have both data sources:
// - clickUrl, dsaInfo, adm.fields?.image (from AD SERVER - tracking + logo)
// - shopData (from YOUR DATABASE - price and store URL)Your responsibility: Replace the database query above with your actual ORM or API call. The ad server does NOT provide price or store URL — your shop provides those. The brand logo comes from
adm.fields?.image.
Step 3: Render HTML + Register Response
The href links to your shop's product page. The ad tracking is attached only to onclick - it fires a tracking pixel without affecting navigation.
<!-- Render with AD SERVER logo + YOUR shop price/URL -->
<div id="ad-brand-store">
<span class="ad-label">Ad</span>
<a href="<%= shopData.productUrl %>"
onclick="new Image().src='<%= clickUrl %>';">
At <img src="<%= adm.fields?.image %>"> for <%= shopData.price %>
</a>
</div>
<!-- Register for viewability and impression tracking -->
<script>
dlApi.cmd.push(function () {
// Arguments: raw bid response object, container element ID
dlApi.registerBidResponse(<%- JSON.stringify(adm) %>, 'ad-brand-store');
});
</script>
registerBidResponse()counts impressions. Only call it when the ad is rendered — never for empty slots. For multi-slot patterns, see Register Bid Response.
What the Ad Server Returns
| Field | Description |
|---|---|
ad.meta.adclick / adm.meta.adclick | Click tracking base URL |
ad.meta.adid / adm.meta.adid | Ad identifier |
ad.fields?.image / adm.fields?.image | Brand logo URL — use directly to display the brand logo |
ad.dsa.behalf / bid.ext?.dsa.behalf | Advertiser name (DSA compliance, requires dsainfo: 1) |
ad.dsa.paid / bid.ext?.dsa.paid | Entity that paid for the ad (DSA compliance) |
ad.dsa.adrender / bid.ext?.dsa.adrender | Ad render information (DSA compliance) |
The ad server does NOT return price or store URLs. Your shop provides those. The brand logo comes from
ad.fields?.image(frontend) oradm.fields?.image(backend).
Preview & Test Your Ads
Ad Preview & Debug Mode serves two distinct audiences — developers integrating the format and business stakeholders managing live campaigns.
For developers: Test backend integrations and verify ad rendering without running live campaigns. Use query string overrides (test_site, test_area, test_kwrd) to simulate different targeting contexts and adbeta to force a specific creative from any line item.
For advertisers and campaign managers: Preview a specific creative on a real publisher page before campaign launch — or verify it after changes. No development tools or server access required. Share a single URL (with the right query parameters) and anyone opening that link sees the exact creative that will run in production.
See Ad Preview & Debug Mode for the full parameter reference, backend implementation guide, and end-to-end tracking with X-ADP-EVENT-TRACK-ID.
Caching Considerations
Important: Improper caching can significantly reduce ad revenue and break tracking.
Do NOT cache:
- Tracking pixels - Caching impression/click pixels prevents accurate counting and drastically reduces revenue
- API responses - Caching bid responses prevents real-time optimization, budget pacing, and frequency capping
Safe to cache:
- Static assets (CSS, JS, images from your shop)
- Product data from your own database
Related
- Brand Store (Mobile Apps) - Native iOS/Android integration without JS SDK
- Format Overview - Compare available ad formats
- Ad Delivery Overview - Learn about Ring DAS ad delivery
Updated 4 days ago
