Brand Store (Mobile Apps)
Native iOS/Android integration for Brand Store format without JS SDK
Brand Store (Mobile Apps)
No SDK Required: This guide shows direct HTTP API integration for native mobile apps. For web integration with JavaScript SDK, see 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 in your mobile app. When a user taps 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 app 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 - Impression and viewability tracking endpoints
Important: The ad server provides tracking information and the brand logo URL. Price and store URL still come from YOUR app's data.
What Your App Must Check
Before displaying the button, your app 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 app's data).
Data Sources
| Source | Data |
|---|---|
| Ad Server | Whether campaign is active, click tracking URL, impression/viewability tracking, brand logo URL |
| Your App | Brand shop URL, price, shop name, offer availability |
Data Flow
- Pass
manufacturer_idto ad server via bidder request - Ad server returns tracking info IF campaign is active for this brand
- Your app checks: Does brand have a store? Is offer available and competitive?
- If all conditions met → render button with your app data + ad server tracking
Live Demo
See the working implementation:
- Live Preview - See how the format looks
- Mobile Integration Playground - Interactive step-by-step guide
Integration Flow Overview
sequenceDiagram
participant App as Mobile App
participant ShopAPI as Shop API/Database
participant Bidder as Ring DAS
participant Events as Events Tracking API
App->>Bidder: 1. Fetch Ad (GET /bid)
Bidder-->>App: Response with gctx, lctx, tracking URLs
Note over App: 2. Parse response
App->>ShopAPI: 3. Fetch brand store data
ShopAPI-->>App: Brand shop URL, price, availability
Note over App: 4. Verify conditions:<br/>- Brand shop exists?<br/>- Offer available?<br/>- Price competitive?
alt All conditions met
Note over App: 5. Render button with shop data<br/>(Logo from ad response)
App->>Events: 6. Fire Impression (/ems)
Note over App: Wait for viewability (50% visible, 1s)
App->>Events: 7. Fire Active View (/av)
Note over App: User taps ad
App->>Events: 8. Fire Click Tracking
Note over App: Open shop URL
else Conditions not met
Note over App: Hide ad slot
end
Optional Request Parameters
The following optional parameters can be passed to enhance user identification and page view tracking. For full field reference see API Parameters Reference.
{
"user": {
"eids": [{
"source": "your-domain.com",
"inserter": "your-domain.com",
"uids": [
{
"id": "your-session-id",
"atype": 500,
"ext": { "id_type": "session", "consent_required": false }
},
{
"id": "your-tracking-id",
"atype": 1,
"ext": { "id_type": "tracking", "consent_required": true }
}
]
}]
},
"ext": {
"keyvalues": {
"IP": "202603041502158687149647",
"IV": "202603041502158687149647",
"TABID": "tab-7f3e2a"
}
}
}Step 1: Fetch Ad from Bidder
Make a GET request to the Ring DAS bidder endpoint.
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 | Set to app for requests originating from a mobile application |
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: listing, search, product_card, main, other |
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 identifier for the current page load. See API Parameters Reference. |
ext.keyvalues.IV | Page View Unique ID — changes on every SPA view transition. See API Parameters Reference. |
ext.keyvalues.TABID | Browser Tab Identifier — stable ID per browser tab session. See API Parameters Reference. |
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.ext.dsa | Set to 1 to request DSA transparency info in response |
User Identifier
| Parameter | Description |
|---|---|
user.eids | OpenRTB Extended Identity Array — pass your session/tracking identifiers with GDPR consent metadata. See API Parameters Reference. |
user.ext.ids.lu | User identifier from ea_uuid cookie (see User Identifier below) |
Examples:
// iOS - Swift
import Foundation
let networkId = "7012768" // your Ring DAS network ID
let bidderUrl = "https://das.idealo.com/\(networkId)/bid"
let requestBody: [String: Any] = [
"id": UUID().uuidString,
"imp": [[
"id": "imp-1",
"tagid": "product-button",
"secure": 1,
"native": ["request": "{}"]
]],
"site": [
"id": "demo_page", // your site ID
"ext": ["area": "product_card"]
],
"user": [
"ext": [
"npa": false, // false = consent given
"ids": ["lu": generateUserId(), "sid": getSessionId()] // sid: your own persistent identifier (alternative to lu)
]
],
"ext": [
"network": networkId,
"keyvalues": [
"manufacturer_id": "12345678",
"main_category_id": 101,
"page_product_id": "987654",
"page_product_name": "Example Product Name"
],
"is_non_prebid_request": true,
"src": "app"
],
"regs": [
"gdpr": 1,
"ext": ["dsa": 1]
],
"tmax": 1000
]
// Encode and send as GET request
let jsonData = try! JSONSerialization.data(withJSONObject: requestBody)
let jsonString = String(data: jsonData, encoding: .utf8)!
let encoded = jsonString.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)!
let url = URL(string: "\(bidderUrl)?data=\(encoded)")!
URLSession.shared.dataTask(with: url) { data, response, error in
guard let httpResponse = response as? HTTPURLResponse else { return }
// Handle 204 No Content (no ad available)
if httpResponse.statusCode == 204 {
print("No ad available")
return
}
// Parse response...
}.resume()// Android - Kotlin
import okhttp3.*
import org.json.JSONArray
import org.json.JSONObject
import java.net.URLEncoder
val networkId = "7012768" // your Ring DAS network ID
val bidderUrl = "https://das.idealo.com/$networkId/bid"
val requestBody = JSONObject().apply {
put("id", java.util.UUID.randomUUID().toString())
put("imp", JSONArray().put(JSONObject().apply {
put("id", "imp-1")
put("tagid", "product-button")
put("secure", 1)
put("native", JSONObject().put("request", "{}"))
}))
put("site", JSONObject().apply {
put("id", "demo_page") // your site ID
put("ext", JSONObject().put("area", "product_card"))
})
put("user", JSONObject().apply {
put("ext", JSONObject().apply {
put("npa", false) // false = consent given
put("ids", JSONObject().put("lu", generateUserId()).put("sid", getSessionId())) // sid: your own persistent identifier (alternative to lu)
})
})
put("ext", JSONObject().apply {
put("network", networkId)
put("keyvalues", JSONObject().apply {
put("manufacturer_id", "12345678")
put("main_category_id", 101)
put("page_product_id", "987654")
put("page_product_name", "Example Product Name")
})
put("is_non_prebid_request", true)
put("src", "app")
})
put("regs", JSONObject().apply {
put("gdpr", 1)
put("ext", JSONObject().put("dsa", 1))
})
put("tmax", 1000)
}
// Encode and send as GET request
val encoded = URLEncoder.encode(requestBody.toString(), "UTF-8")
val request = Request.Builder().url("$bidderUrl?data=$encoded").build()
client.newCall(request).enqueue(object : Callback {
override fun onResponse(call: Call, response: Response) {
// Handle 204 No Content (no ad available)
if (response.code == 204) {
println("No ad available")
return
}
// Parse response...
}
override fun onFailure(call: Call, e: IOException) { }
})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
Extract tracking data from the bid response.
| Field | Description |
|---|---|
gctx | Global context - required for impression/viewability tracking |
lctx | Local context - required for impression/viewability tracking |
meta.adclick | Click tracking URL — fire as a pixel on user tap |
fields.image | Brand logo URL — use directly to display the brand logo |
bid.ext.dsa | DSA transparency info (if requested) |
Examples:
// iOS - Swift
guard let data = data,
let json = try? JSONSerialization.jsonObject(with: data) as? [String: Any],
let seatbid = json["seatbid"] as? [[String: Any]],
let bid = seatbid.first?["bid"] as? [[String: Any]],
let firstBid = bid.first,
let admString = firstBid["adm"] as? String,
let admData = admString.data(using: .utf8),
let adm = try? JSONSerialization.jsonObject(with: admData) as? [String: Any] else {
return
}
// Extract tracking data
let gctx = adm["gctx"] as? String
let lctx = adm["lctx"] as? String
// Click tracking URL
let clickUrl = (adm["meta"] as? [String: Any])?["adclick"] as? String
if let fields = adm["fields"] as? [String: Any] {
// Brand logo from AD SERVER
let logoUrl = fields["image"] as? String
}
// DSA info (optional)
let dsaInfo = (firstBid["ext"] as? [String: Any])?["dsa"] as? [String: Any]// Android - Kotlin
response.body?.string()?.let { body ->
val json = JSONObject(body)
val seatbid = json.optJSONArray("seatbid") ?: return
val bid = seatbid.optJSONObject(0)?.optJSONArray("bid")?.optJSONObject(0) ?: return
val adm = JSONObject(bid.getString("adm"))
// Extract tracking data
val gctx = adm.optString("gctx")
val lctx = adm.optString("lctx")
// Click tracking URL
val clickUrl = adm.optJSONObject("meta")?.optString("adclick", null)
// Brand logo from AD SERVER
val logoUrl = adm.optJSONObject("fields")?.optString("image", null)
// DSA info (optional)
val dsaInfo = bid.optJSONObject("ext")?.optJSONObject("dsa")
}Step 3: Render with Shop Data
Use YOUR app's product data to render the ad. The ad server does NOT return price or store URL — your app provides those. The brand logo comes from the ad response (fields.image).
// iOS - Swift
// YOUR shop data (price and URL) - brand logo comes from ad server!
struct ShopData {
let productUrl = "https://apple.com/store/iphone"
let shopName = "Apple"
let price = "€899.00"
// Note: brand logo comes from ad response (fields.image)
}
// Render button in your app's UI
// Attach click handler that:
// 1. Fires click tracking pixel
// 2. Opens shop URL// Android - Kotlin
// YOUR shop data (price and URL) - brand logo comes from ad server!
data class ShopData(
val productUrl: String = "https://apple.com/store/iphone",
val shopName: String = "Apple",
val price: String = "€899.00"
// Note: brand logo comes from ad response (fields.image)
)
// Render button in your app's UI
// Attach click handler that:
// 1. Fires click tracking pixel
// 2. Opens shop URLStep 4: Fire Impression Event
Fire this event when the ad is loaded and ready to display.
Endpoint: GET https://das.idealo.com/{NETWORK_ID}/v1/events-processor/ems
| Parameter | Description |
|---|---|
eventData | URL-encoded JSON with gctx and ems array |
gctx | Global context from bid response |
lctx | Local context from bid response |
is_measurable | Set to true to indicate viewability can be measured |
Examples:
// iOS - Swift
func fireImpression(gctx: String, lctx: String, networkId: String) {
let eventData: [String: Any] = [
"gctx": gctx,
"ems": [[
"lctx": lctx,
"is_measurable": true
]]
]
guard let jsonData = try? JSONSerialization.data(withJSONObject: eventData),
let jsonString = String(data: jsonData, encoding: .utf8),
let encoded = jsonString.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed),
let url = URL(string: "https://das.idealo.com/\(networkId)/v1/events-processor/ems?eventData=\(encoded)") else {
return
}
URLSession.shared.dataTask(with: url).resume()
}// Android - Kotlin
fun fireImpression(gctx: String, lctx: String, networkId: String) {
val eventData = JSONObject().apply {
put("gctx", gctx)
put("ems", JSONArray().put(JSONObject().apply {
put("lctx", lctx)
put("is_measurable", true)
}))
}
val encoded = URLEncoder.encode(eventData.toString(), "UTF-8")
val url = "https://das.idealo.com/$networkId/v1/events-processor/ems?eventData=$encoded"
client.newCall(Request.Builder().url(url).build()).enqueue(object : Callback {
override fun onFailure(call: Call, e: IOException) {}
override fun onResponse(call: Call, response: Response) {}
})
}Step 5: Fire Active View Event
Your App Must Implement Viewability Measurement!
Fire
/avonly when these conditions are met (MRC/IAB Standard):
- At least 50% of ad pixels are visible on screen
- Ad has been visible for at least 1 continuous second
Use platform APIs:
- iOS:
UIViewvisibility checks +CADisplayLinkorTimerfor duration- Android:
View.getGlobalVisibleRect()+Handlerfor duration tracking
Endpoint: GET https://das.idealo.com/{NETWORK_ID}/v1/events-processor/av
Examples:
// iOS - Swift
func fireActiveView(gctx: String, lctx: String, networkId: String) {
let eventData: [String: Any] = [
"gctx": gctx,
"ems": [[
"lctx": lctx
]]
]
guard let jsonData = try? JSONSerialization.data(withJSONObject: eventData),
let jsonString = String(data: jsonData, encoding: .utf8),
let encoded = jsonString.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed),
let url = URL(string: "https://das.idealo.com/\(networkId)/v1/events-processor/av?eventData=\(encoded)") else {
return
}
URLSession.shared.dataTask(with: url).resume()
}
// Example viewability implementation
class ViewabilityTracker {
private var timer: Timer?
private var visibleStartTime: Date?
private let requiredDuration: TimeInterval = 1.0
private let requiredVisibility: CGFloat = 0.5
func startTracking(adView: UIView, onViewable: @escaping () -> Void) {
timer = Timer.scheduledTimer(withTimeInterval: 0.1, repeats: true) { [weak self] _ in
guard let self = self else { return }
if self.isViewVisible(adView, threshold: self.requiredVisibility) {
if self.visibleStartTime == nil {
self.visibleStartTime = Date()
} else if Date().timeIntervalSince(self.visibleStartTime!) >= self.requiredDuration {
self.timer?.invalidate()
onViewable()
}
} else {
self.visibleStartTime = nil // Reset if visibility lost
}
}
}
private func isViewVisible(_ view: UIView, threshold: CGFloat) -> Bool {
guard let window = view.window else { return false }
let viewFrame = view.convert(view.bounds, to: window)
let intersection = viewFrame.intersection(window.bounds)
let visibleArea = intersection.width * intersection.height
let totalArea = viewFrame.width * viewFrame.height
return visibleArea / totalArea >= threshold
}
}// Android - Kotlin
fun fireActiveView(gctx: String, lctx: String, networkId: String) {
val eventData = JSONObject().apply {
put("gctx", gctx)
put("ems", JSONArray().put(JSONObject().put("lctx", lctx)))
}
val encoded = URLEncoder.encode(eventData.toString(), "UTF-8")
val url = "https://das.idealo.com/$networkId/v1/events-processor/av?eventData=$encoded"
client.newCall(Request.Builder().url(url).build()).enqueue(object : Callback {
override fun onFailure(call: Call, e: IOException) {}
override fun onResponse(call: Call, response: Response) {}
})
}
// Example viewability implementation
class ViewabilityTracker(
private val adView: View,
private val onViewable: () -> Unit
) {
private val handler = Handler(Looper.getMainLooper())
private var visibleStartTime: Long? = null
private val requiredDurationMs = 1000L
private val requiredVisibility = 0.5f
private val checkRunnable = object : Runnable {
override fun run() {
if (isViewVisible(adView, requiredVisibility)) {
if (visibleStartTime == null) {
visibleStartTime = System.currentTimeMillis()
} else if (System.currentTimeMillis() - visibleStartTime!! >= requiredDurationMs) {
onViewable()
return // Stop checking
}
} else {
visibleStartTime = null // Reset if visibility lost
}
handler.postDelayed(this, 100)
}
}
fun startTracking() {
handler.post(checkRunnable)
}
fun stopTracking() {
handler.removeCallbacks(checkRunnable)
}
private fun isViewVisible(view: View, threshold: Float): Boolean {
val visibleRect = Rect()
if (!view.getGlobalVisibleRect(visibleRect)) return false
val visibleArea = visibleRect.width() * visibleRect.height()
val totalArea = view.width * view.height
return visibleArea.toFloat() / totalArea >= threshold
}
}Step 6: Fire Click Tracking
Fire the click tracking pixel when the user taps the ad, then open the shop URL.
Examples:
// iOS - Swift
func handleAdClick(clickUrl: String, shopUrl: String) {
// 1. Fire click tracking pixel (non-blocking)
if let url = URL(string: clickUrl) {
URLSession.shared.dataTask(with: url).resume()
}
// 2. Open shop URL
if let url = URL(string: shopUrl) {
UIApplication.shared.open(url)
}
}// Android - Kotlin
fun handleAdClick(clickUrl: String, shopUrl: String, context: Context) {
// 1. Fire click tracking pixel (non-blocking)
client.newCall(Request.Builder().url(clickUrl).build()).enqueue(object : Callback {
override fun onFailure(call: Call, e: IOException) {}
override fun onResponse(call: Call, response: Response) {}
})
// 2. Open shop URL
val intent = Intent(Intent.ACTION_VIEW, Uri.parse(shopUrl))
context.startActivity(intent)
}User Identifier
A user identifier enables frequency capping, personalization, and other targeting features.
| 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 (set by Ring DAS). Must follow the alphanumeric format (e.g., 202502051230001234567890). |
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.
Critical: Persist the User Identifier!
Store this identifier persistently and reuse the same value across:
- All ad requests within a session
- All sessions for the same user
Why this matters:
- Frequency capping - Limits how often a user sees the same ad
- Budget pacing - Distributes advertiser spend evenly across users
- Attribution - Tracks conversions back to ad impressions
- Personalization - Enables relevant ad targeting
Generating a new
luon every app launch breaks these features and reduces ad effectiveness.
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 (images, fonts from your app)
- Product data from your own database
Complete Integration Example
Here's a complete Swift class showing the full integration flow:
// iOS - Swift - Complete Example
import Foundation
import UIKit
class BrandStoreAdManager {
private let networkId: String
private let bidderUrl: String
private let client = URLSession.shared
// Parsed ad data
private var gctx: String?
private var lctx: String?
private var clickUrl: String?
private var logoUrl: String?
private var userId: String
private var sessionId: String? // your own persistent identifier (alternative to lu)
init(networkId: String) {
self.networkId = networkId
self.bidderUrl = "https://das.idealo.com/\(networkId)/bid"
self.userId = Self.generateUserId()
}
// MARK: - Public API
func fetchAd(siteId: String, manufacturerId: String, completion: @escaping (Bool) -> Void) {
let requestBody = buildRequest(siteId: siteId, manufacturerId: manufacturerId)
guard let url = buildRequestURL(requestBody) else {
completion(false)
return
}
client.dataTask(with: url) { [weak self] data, response, _ in
guard let httpResponse = response as? HTTPURLResponse else {
completion(false)
return
}
if httpResponse.statusCode == 204 {
completion(false)
return
}
guard let data = data else {
completion(false)
return
}
self?.parseResponse(data)
completion(self?.gctx != nil)
}.resume()
}
func fireImpression() {
guard let gctx = gctx, let lctx = lctx else { return }
fireEvent(endpoint: "ems", gctx: gctx, lctx: lctx, isMeasurable: true)
}
func fireActiveView() {
guard let gctx = gctx, let lctx = lctx else { return }
fireEvent(endpoint: "av", gctx: gctx, lctx: lctx, isMeasurable: false)
}
func handleClick(shopUrl: String) {
// Fire click tracking
if let clickUrl = clickUrl, let url = URL(string: clickUrl) {
client.dataTask(with: url).resume()
}
// Open shop URL
if let url = URL(string: shopUrl) {
DispatchQueue.main.async {
UIApplication.shared.open(url)
}
}
}
// MARK: - Private Helpers
private func buildRequest(siteId: String, manufacturerId: String) -> [String: Any] {
return [
"id": UUID().uuidString,
"imp": [["id": "imp-1", "tagid": "product-button", "secure": 1, "native": ["request": "{}"]]],
"site": ["id": siteId, "ext": ["area": "product_card"]],
"user": ["ext": ["npa": false, "ids": ["lu": userId, "sid": sessionId]]],
"ext": ["network": networkId, "keyvalues": ["manufacturer_id": manufacturerId, "main_category_id": 101, "page_product_id": "987654", "page_product_name": "Example Product Name"], "is_non_prebid_request": true, "src": "app"],
"regs": ["gdpr": 1, "ext": ["dsa": 1]],
"tmax": 1000
]
}
private func buildRequestURL(_ body: [String: Any]) -> URL? {
guard let jsonData = try? JSONSerialization.data(withJSONObject: body),
let jsonString = String(data: jsonData, encoding: .utf8),
let encoded = jsonString.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) else {
return nil
}
return URL(string: "\(bidderUrl)?data=\(encoded)")
}
private func parseResponse(_ data: Data) {
guard let json = try? JSONSerialization.jsonObject(with: data) as? [String: Any],
let seatbid = json["seatbid"] as? [[String: Any]],
let bid = seatbid.first?["bid"] as? [[String: Any]],
let firstBid = bid.first,
let admString = firstBid["adm"] as? String,
let admData = admString.data(using: .utf8),
let adm = try? JSONSerialization.jsonObject(with: admData) as? [String: Any] else {
return
}
gctx = adm["gctx"] as? String
lctx = adm["lctx"] as? String
// Click tracking URL
clickUrl = (adm["meta"] as? [String: Any])?["adclick"] as? String
// Brand logo from AD SERVER
if let fields = adm["fields"] as? [String: Any],
let image = fields["image"] as? String {
logoUrl = image
}
}
private func fireEvent(endpoint: String, gctx: String, lctx: String, isMeasurable: Bool) {
var emsItem: [String: Any] = ["lctx": lctx]
if isMeasurable {
emsItem["is_measurable"] = true
}
let eventData: [String: Any] = ["gctx": gctx, "ems": [emsItem]]
guard let jsonData = try? JSONSerialization.data(withJSONObject: eventData),
let jsonString = String(data: jsonData, encoding: .utf8),
let encoded = jsonString.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed),
let url = URL(string: "https://das.idealo.com/\(networkId)/v1/events-processor/\(endpoint)?eventData=\(encoded)") else {
return
}
client.dataTask(with: url).resume()
}
private static func generateUserId() -> String {
let formatter = DateFormatter()
formatter.dateFormat = "yyyyMMddHHmmss"
let timestamp = formatter.string(from: Date())
let random = String(format: "%010d", Int.random(in: 0..<10_000_000_000))
return timestamp + random
}
}Related
- Brand Store (Web) - JavaScript SDK integration for web
- Format Overview - Compare available ad formats
- Ad Delivery Overview - Learn about Ring DAS ad delivery
Updated 7 days ago
