PageSourceSearch

https://bambuser.com/docs/assets/js/8641845c.c4d238e0.js

js bambuser.com collected 2026-09-24 08:30:28 UTC 41,646 bytes, 1 lines download raw bytes

1"use strict";(globalThis.webpackChunkbambuser_docs||=[]).push([[4308],{46925(e,n,r){r.r(n),r.d(n,{assets:()=>a,contentTitle:()=>l,default:()=>x,frontMatter:()=>o,metadata:()=>t,toc:()=>h});const t=JSON.parse('{"id":"mobileSDK/android/vc-android-purchase-tracking","title":"Android SDK \u2014 Shopper Events Tracking","description":"Attribute shopper events (purchase, add-to-cart, refund, product-view, wishlist) to Bambuser Video Consultation sessions from a native Android app.","source":"@site/video-consultation/mobileSDK/android/purchase-tracking.mdx","sourceDirName":"mobileSDK/android","slug":"/mobileSDK/android/mobile-sdk/android/purchase-tracking","permalink":"/docs/video-consultation/mobileSDK/android/mobile-sdk/android/purchase-tracking","draft":false,"unlisted":false,"tags":[],"version":"current","frontMatter":{"id":"vc-android-purchase-tracking","title":"Android SDK \u2014 Shopper Events Tracking","description":"Attribute shopper events (purchase, add-to-cart, refund, product-view, wishlist) to Bambuser Video Consultation sessions from a native Android app.","sidebar_label":"Shopper Events Tracking","slug":"mobile-sdk/android/purchase-tracking"},"sidebar":"someSidebars","previous":{"title":"Customer Events","permalink":"/docs/video-consultation/mobileSDK/android/mobile-sdk/android/customer-events"},"next":{"title":"Picture in Picture","permalink":"/docs/video-consultation/mobileSDK/android/mobile-sdk/android/picture-in-picture"}}');var s=r(74848),i=r(28453),d=r(4865),c=r(19365);const o={id:"vc-android-purchase-tracking",title:"Android SDK \u2014 Shopper Events Tracking",description:"Attribute shopper events (purchase, add-to-cart, refund, product-view, wishlist) to Bambuser Video Consultation sessions from a native Android app.",sidebar_label:"Shopper Events Tracking",slug:"mobile-sdk/android/purchase-tracking"},l="Shopper Events Tracking",a={},h=[{value:"How it works on mobile",id:"how-it-works-on-mobile",level:2},{value:"Entry point \u2014 <code>BambuserShopperSDK</code>",id:"entry-point--bambusershoppersdk",level:2},{value:"Hilt / DI wiring",id:"hilt--di-wiring",level:3},{value:"Plain Application",id:"plain-application",level:3},{value:"The <code>track</code> method",id:"the-track-method",level:2},{value:"What the SDK adds for you",id:"what-the-sdk-adds-for-you",level:3},{value:"Event reference",id:"event-reference",level:2},{value:"Object reference",id:"object-reference",level:2},{value:"Product Object",id:"product-object",level:3},{value:"Transaction Object",id:"transaction-object",level:3},{value:"Attribution \u2014 how the SDK routes events",id:"attribution--how-the-sdk-routes-events",level:2},{value:"Verification",id:"verification",level:2},{value:"See also",id:"see-also",level:2}];function u(e){const n={a:"a",admonition:"admonition",code:"code",h1:"h1",h2:"h2",h3:"h3",header:"header",hr:"hr",li:"li",ol:"ol",p:"p",pre:"pre",strong:"strong",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",ul:"ul",...(0,i.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(n.header,{children:(0,s.jsx)(n.h1,{id:"shopper-events-tracking",children:"Shopper Events Tracking"})}),"\n",(0,s.jsxs)(n.p,{children:["The Bambuser Shopper SDK for Android reports shopper events \u2014 purchases, cart activity, wishlist changes, refunds, product views \u2014 back to Bambuser so conversions and downstream behaviour attribute to the Video Consultation call the shopper had. Same events, same payload shape, and same BamHub insights as the ",(0,s.jsx)(n.a,{href:"/video-consultation/shopper-events-tracking",children:"web tracking library"}),", delivered natively."]}),"\n",(0,s.jsx)(n.admonition,{title:"When to use this",type:"tip",children:(0,s.jsx)(n.p,{children:'Fire events from your own app \u2014 after a purchase, on native "add to cart" taps, when the shopper opens a PDP, on refunds. Works with or without an active call: as long as the shopper interacted with a Bambuser Video Consultation call recently enough that a valid attribution window still exists, the event gets attributed to that call.'})}),"\n",(0,s.jsx)(n.hr,{}),"\n",(0,s.jsx)(n.h2,{id:"how-it-works-on-mobile",children:"How it works on mobile"}),"\n",(0,s.jsxs)(n.p,{children:["On web, attribution rides on the ",(0,s.jsx)(n.code,{children:"_bamls_usid"})," and ",(0,s.jsx)(n.code,{children:"_bamls_lcte"})," cookies the Bambuser embed sets in the browser. Cookies survive the shopper closing the tab, coming back a week later, and completing checkout \u2014 the tracking library reads them and POSTs the event to Bambuser."]}),"\n",(0,s.jsxs)(n.p,{children:["On mobile the widget lives inside an Android ",(0,s.jsx)(n.code,{children:"WebView"}),", whose cookie jar is scoped to that WebView and is cleared when the call ends. To match the web attribution model, the SDK:"]}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:["Persists the shopper's ",(0,s.jsx)(n.strong,{children:"user id"})," and ",(0,s.jsx)(n.strong,{children:"per-region LCTE (Localized Conversion Tracking Expiry)"})," to native storage (encrypted ",(0,s.jsx)(n.code,{children:"SharedPreferences"}),")."]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"Injects"})," those cookies into the ",(0,s.jsx)(n.code,{children:"WebView"})," on ",(0,s.jsx)(n.code,{children:"attach(...)"})," so the embed sees the same identity a browser would."]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"Clears"})," the cookies from the ",(0,s.jsx)(n.code,{children:"WebView"})," on ",(0,s.jsx)(n.code,{children:"detach()"})," so nothing bleeds between calls."]}),"\n",(0,s.jsxs)(n.li,{children:["Exposes a single ",(0,s.jsx)(n.code,{children:"track(event, data)"})," method on ",(0,s.jsx)(n.code,{children:"BambuserShopperSDK"})," that reads the persisted state and POSTs to ",(0,s.jsx)(n.code,{children:"<region>/collect/events"})," \u2014 no ",(0,s.jsx)(n.code,{children:"WebView"}),", no active call required."]}),"\n"]}),"\n",(0,s.jsxs)(n.p,{children:["The result: the shopper can end a call, keep browsing for hours or days, complete checkout, and the resulting ",(0,s.jsx)(n.code,{children:"purchase"})," event still attributes to that call."]}),"\n",(0,s.jsx)(n.hr,{}),"\n",(0,s.jsxs)(n.h2,{id:"entry-point--bambusershoppersdk",children:["Entry point \u2014 ",(0,s.jsx)(n.code,{children:"BambuserShopperSDK"})]}),"\n",(0,s.jsxs)(n.p,{children:["Create ",(0,s.jsx)(n.strong,{children:"one"})," instance per app scope (e.g. inside your ",(0,s.jsx)(n.code,{children:"Application"})," or DI graph) and hold on to it for the lifetime of the app. All event tracking goes through this handle \u2014 no ",(0,s.jsx)(n.code,{children:"BambuserCallController"})," needed."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-kotlin",children:'import 
1com.bambuser.callsshopper.BambuserEnvironment\nimport com.bambuser.callsshopper.BambuserShopperSDK\n\nval bambuser = BambuserShopperSDK(\n    context = applicationContext,\n    environment = BambuserEnvironment.US,   // .US or .EU\n    orgId = "YOUR_ORG_ID",\n)\n'})}),"\n",(0,s.jsxs)(n.p,{children:["The initializer kicks off a background coroutine that ensures a user id and an LCTE entry for the current region exist and haven't expired. You can call ",(0,s.jsx)(n.code,{children:"track(...)"})," immediately after \u2014 the SDK serializes state access internally."]}),"\n",(0,s.jsx)(n.h3,{id:"hilt--di-wiring",children:"Hilt / DI wiring"}),"\n",(0,s.jsx)(n.p,{children:"Provide the SDK as a singleton:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-kotlin",children:"@Module\n@InstallIn(SingletonComponent::class)\nobject BambuserModule {\n\n    @Provides\n    @Singleton\n    fun provideBambuserSDK(\n        @ApplicationContext context: Context,\n    ): BambuserShopperSDK = BambuserShopperSDK(\n        context = context,\n        environment = BambuserEnvironment.US,\n        orgId = BuildConfig.BAMBUSER_ORG_ID,\n    )\n}\n"})}),"\n",(0,s.jsx)(n.h3,{id:"plain-application",children:"Plain Application"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-kotlin",children:'class DemoApp : Application() {\n    lateinit var bambuser: BambuserShopperSDK\n        private set\n\n    override fun onCreate() {\n        super.onCreate()\n        bambuser = BambuserShopperSDK(\n            context = this,\n            environment = BambuserEnvironment.US,\n            orgId = "YOUR_ORG_ID",\n        )\n    }\n}\n'})}),"\n",(0,s.jsx)(n.hr,{}),"\n",(0,s.jsxs)(n.h2,{id:"the-track-method",children:["The ",(0,s.jsx)(n.code,{children:"track"})," method"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-kotlin",children:"suspend fun track(\n    event: String,\n    data: Map<String, Any?>,\n): Map<String, Any?>?\n"})}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:(0,s.jsx)(n.code,{children:"event"})})," \u2014 the event name. One of ",(0,s.jsx)(n.code,{children:'"purchase"'}),", ",(0,s.jsx)(n.code,{children:'"add-to-cart"'}),", ",(0,s.jsx)(n.code,{children:'"update-cart"'}),", ",(0,s.jsx)(n.code,{children:'"add-to-wishlist"'}),", ",(0,s.jsx)(n.code,{children:'"remove-from-wishlist"'}),", ",(0,s.jsx)(n.code,{children:'"product-view"'}),", ",(0,s.jsx)(n.code,{children:'"refund"'}),". See the ",(0,s.jsx)(n.a,{href:"#event-reference",children:"Event reference"})," for payload shape per event."]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:(0,s.jsx)(n.code,{children:"data"})})," \u2014 caller-shaped payload (",(0,s.jsx)(n.code,{children:"transaction"}),", ",(0,s.jsx)(n.code,{children:"products"}),", etc.). Any keys the SDK adds automatically (",(0,s.jsx)(n.code,{children:"userId"}),", ",(0,s.jsx)(n.code,{children:"eventType"}),", ",(0,s.jsx)(n.code,{children:"source"}),", ",(0,s.jsx)(n.code,{children:"sourceApp"}),", ",(0,s.jsx)(n.code,{children:"ref"}),", ",(0,s.jsx)(n.code,{children:"_meta_"}),") will be overwritten by the SDK's values if you pass them."]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"Returns"})," \u2014 the full payload that was POSTed on success, or ",(0,s.jsx)(n.code,{children:"null"})," when there is no valid LCTE region (the attribution window has elapsed \u2014 the event is silently dropped)."]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"Throws"})," \u2014 ",(0,s.jsx)(n.code,{children:"BambuserCallException.TrackingFailed(reason)"})," if every region POST fails."]}),"\n"]}),"\n",(0,s.jsxs)(n.p,{children:["The method is ",(0,s.jsx)(n.code,{children:"suspend"})," \u2014 call it from any coroutine scope. ",(0,s.jsx)(n.code,{children:"applicationScope"})," is a good default so the event still posts if the caller Activity is destroyed mid-request:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-kotlin",children:'applicationScope.launch {\n    runCatching {\n        bambuser.track(\n            event = "purchase",\n            data = mapOf(\n                "transaction" to mapOf(...),\n                "products"    to listOf(...),\n            ),\n        )\n    }.onFailure { Log.w("Bambuser", "track failed", it) }\n}\n'})}),"\n",(0,s.jsx)(n.h3,{id:"what-the-sdk-adds-for-you",children:"What the SDK adds for you"}),"\n",(0,s.jsxs)(n.p,{children:["Before POSTing, the SDK enriches your ",(0,s.jsx)(n.code,{children:"data"})," with:"]}),"\n",(0,s.jsxs)(n.table,{children:[(0,s.jsx)(n.thead,{children:(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.th,{children:"Field"}),(0,s.jsx)(n.th,{children:"Value"})]})}),(0,s.jsxs)(n.tbody,{children:[(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"userId"})}),(0,s.jsx)(n.td,{children:"The persisted shopper id (from native storage)."})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"eventType"})}),(0,s.jsxs)(n.td,{children:["The ",(0,s.jsx)(n.code,{children:"event"})," argument."]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"ref"})}),(0,s.jsx)(n.td,{children:"The host app's package name."})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"_meta_"})}),(0,s.jsxs)(n.td,{children:[(0,s.jsx)(n.code,{children:"{ bundleVersion, osVersion, deviceModel, sdkVersion }"}),"."]})]})]})]}),"\n",(0,s.jsx)(n.p,{children:"You don't need to (and shouldn't) set these yourself."}),"\n",(0,s.jsx)(n.hr,{}),"\n",(0,s.jsx)(n.h2,{id:"event-reference",children:"Event reference"}),"\n",(0,s.jsxs)(n.p,{children:["Payload shapes mirror the ",(0,s.jsx)(n.a,{href:"/video-consultation/shopper-events-tracking#event-reference",children:"web tracking library"}
1)," one-for-one. The SDK does not validate the schema \u2014 Bambuser's ingest does \u2014 so send exactly what the event expects."]}),"\n",(0,s.jsxs)(d.A,{defaultValue:"purchase",values:[{label:"Purchase",value:"purchase"},{label:"Add to Cart",value:"add-to-cart"},{label:"Update Cart",value:"update-cart"},{label:"Add to Wishlist",value:"add-to-wishlist"},{label:"Remove from Wishlist",value:"remove-from-wishlist"},{label:"Product View",value:"product-view"},{label:"Refund",value:"refund"}],children:[(0,s.jsxs)(c.A,{value:"purchase",children:[(0,s.jsx)(n.p,{children:"Track a completed purchase. This is the primary conversion event."}),(0,s.jsxs)(n.table,{children:[(0,s.jsx)(n.thead,{children:(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.th,{children:"Name"}),(0,s.jsx)(n.th,{children:"Type"}),(0,s.jsx)(n.th,{children:"Required"}),(0,s.jsx)(n.th,{children:"Description"})]})}),(0,s.jsxs)(n.tbody,{children:[(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"transaction"})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.a,{href:"#transaction-object",children:(0,s.jsx)(n.code,{children:"Transaction"})})}),(0,s.jsx)(n.td,{children:"Yes"}),(0,s.jsx)(n.td,{children:"Order-level details."})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"products"})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.a,{href:"#product-object",children:(0,s.jsx)(n.code,{children:"List<Product>"})})}),(0,s.jsx)(n.td,{children:"Yes"}),(0,s.jsx)(n.td,{children:"Line items purchased."})]})]})]}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-kotlin",children:'bambuser.track(\n    event = "purchase",\n    data = mapOf(\n        "transaction" to mapOf(\n            "id"             to "abcd",\n            "currency"       to "USD",\n            "subtotal"       to 70.99,   // sum of price \xd7 quantity across products\n            "total"          to 81.25,   // subtotal \u2212 discount + tax + shippingCost\n            "discount"       to 2.00,    // order-level (product-level goes on the line)\n            "tax"            to 8.27,\n            "shippingCost"   to 3.99,\n            "shippingMethod" to "Home delivery",\n            "coupon"         to "SUMMER_SALE",\n        ),\n        "products" to listOf(\n            mapOf(\n                "id"       to "314-7216-102",\n                "name"     to "Tennis Shoe Classic - Size 10",\n                "image"    to "https://example.com/images/314-7216-102.jpg",\n                "price"    to 70.99,\n                "currency" to "USD",\n                "discount" to 5.00,\n                "coupon"   to "SUMMER_SALE",\n                "quantity" to 1,\n                "brand"    to "Plausible Co.",\n                "category" to "Footwear > Sports > Tennis",\n                "location" to "https://example.com/products/314-7216",\n            ),\n        ),\n    ),\n)\n'})})]}),(0,s.jsxs)(c.A,{value:"add-to-cart",children:[(0,s.jsxs)(n.p,{children:["Fire when a shopper adds an item to their cart through your native UI. (Cart activity that originates from ",(0,s.jsx)(n.strong,{children:"inside the widget"})," \u2014 the agent's cart tool \u2014 is already tracked by Bambuser; you only need to instrument your app's own \"add to cart\" surface.)"]}),(0,s.jsxs)(n.table,{children:[(0,s.jsx)(n.thead,{children:(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.th,{children:"Name"}),(0,s.jsx)(n.th,{children:"Type"}),(0,s.jsx)(n.th,{children:"Required"}),(0,s.jsx)(n.th,{children:"Description"})]})}),(0,s.jsx)(n.tbody,{children:(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"products"})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.a,{href:"#product-object",children:(0,s.jsx)(n.code,{children:"List<Product>"})})}),(0,s.jsx)(n.td,{children:"Yes"}),(0,s.jsx)(n.td,{children:"Items added."})]})})]}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-kotlin",children:'bambuser.track(\n    event = "add-to-cart",\n    data = mapOf(\n        "products" to listOf(\n            mapOf(\n                "id"       to "314-7216-102",\n                "quantity" to 1,\n                "name"     to "Tennis Shoe Classic - Size 10",\n                "image"    to "https://example.com/images/314-7216-102.jpg",\n                "price"    to 70.99,\n                "currency" to "USD",\n                "brand"    to "Plausible Co.",\n                "category" to "Footwear > Sports > Tennis",\n                "location" to "https://example.com/products/314-7216",\n            ),\n        ),\n    ),\n)\n'})})]}),(0,s.jsxs)(c.A,{value:"update-cart",children:[(0,s.jsxs)(n.p,{children:["Fire when the shopper changes the quantity of an item \u2014 or removes it (set ",(0,s.jsx)(n.code,{children:"quantity"})," to ",(0,s.jsx)(n.code,{children:"0"}),"). The ",(0,s.jsx)(n.code,{children:"quantity"})," field should reflect the ",(0,s.jsx)(n.strong,{children:"new total"})," for that item after the update."]}),(0,s.jsxs)(n.table,{children:[(0,s.jsx)(n.thead,{children:(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.th,{children:"Name"}),(0,s.jsx)(n.th,{children:"Type"}),(0,s.jsx)(n.th,{children:"Required"}),(0,s.jsx)(n.th,{children:"Description"})]})}),(0,s.jsx)(n.tbody,{children:(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"products"})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.a,{href:"#product-object",children:(0,s.jsx)(n.code,{children:"List<Product>"})})}),(0,s.jsx)(n.td,{children:"Yes"}),(0,s.jsx)(n.td,{children:"Items with new quantities."})]})})]}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-kotlin",children:'bambuser.track(\n    event = "update-cart",\n    data = mapOf(\n        "products" to listOf(\n            mapOf(\n                "id"       to "314-7216-102",\n                "quantity" to 2,\n                "name"     to "Tennis Shoe Classic - Size 10",\n                "price"    to 70.99,\n                "currency" to "USD",\n            ),\n        ),\n    ),\n)\n'})})]}
1),(0,s.jsxs)(c.A,{value:"add-to-wishlist",children:[(0,s.jsxs)(n.p,{children:["For apps with a wishlist feature. ",(0,s.jsx)(n.code,{children:"quantity"})," is forced to ",(0,s.jsx)(n.code,{children:"1"}),"."]}),(0,s.jsxs)(n.table,{children:[(0,s.jsx)(n.thead,{children:(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.th,{children:"Name"}),(0,s.jsx)(n.th,{children:"Type"}),(0,s.jsx)(n.th,{children:"Required"}),(0,s.jsx)(n.th,{children:"Description"})]})}),(0,s.jsx)(n.tbody,{children:(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"products"})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.a,{href:"#product-object",children:(0,s.jsx)(n.code,{children:"List<Product>"})})}),(0,s.jsx)(n.td,{children:"Yes"}),(0,s.jsx)(n.td,{children:"Items added to the wishlist."})]})})]}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-kotlin",children:'bambuser.track(\n    event = "add-to-wishlist",\n    data = mapOf(\n        "products" to listOf(\n            mapOf(\n                "id"       to "314-7216-102",\n                "name"     to "Tennis Shoe Classic - Size 10",\n                "price"    to 70.99,\n                "currency" to "USD",\n            ),\n        ),\n    ),\n)\n'})})]}),(0,s.jsxs)(c.A,{value:"remove-from-wishlist",children:[(0,s.jsxs)(n.p,{children:["Companion to ",(0,s.jsx)(n.code,{children:"add-to-wishlist"}),". ",(0,s.jsx)(n.code,{children:"quantity"})," is forced to ",(0,s.jsx)(n.code,{children:"1"}),"."]}),(0,s.jsxs)(n.table,{children:[(0,s.jsx)(n.thead,{children:(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.th,{children:"Name"}),(0,s.jsx)(n.th,{children:"Type"}),(0,s.jsx)(n.th,{children:"Required"}),(0,s.jsx)(n.th,{children:"Description"})]})}),(0,s.jsx)(n.tbody,{children:(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"products"})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.a,{href:"#product-object",children:(0,s.jsx)(n.code,{children:"List<Product>"})})}),(0,s.jsx)(n.td,{children:"Yes"}),(0,s.jsx)(n.td,{children:"Items removed from the wishlist."})]})})]}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-kotlin",children:'bambuser.track(\n    event = "remove-from-wishlist",\n    data = mapOf(\n        "products" to listOf(\n            mapOf(\n                "id"       to "314-7216-102",\n                "name"     to "Tennis Shoe Classic - Size 10",\n                "price"    to 70.99,\n                "currency" to "USD",\n            ),\n        ),\n    ),\n)\n'})})]}),(0,s.jsxs)(c.A,{value:"product-view",children:[(0,s.jsxs)(n.p,{children:["Fire when the shopper opens a product detail page. Useful for insight views and advanced attribution analytics. ",(0,s.jsx)(n.code,{children:"quantity"})," is forced to ",(0,s.jsx)(n.code,{children:"1"}),"."]}),(0,s.jsxs)(n.table,{children:[(0,s.jsx)(n.thead,{children:(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.th,{children:"Name"}),(0,s.jsx)(n.th,{children:"Type"}),(0,s.jsx)(n.th,{children:"Required"}),(0,s.jsx)(n.th,{children:"Description"})]})}),(0,s.jsx)(n.tbody,{children:(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"products"})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.a,{href:"#product-object",children:(0,s.jsx)(n.code,{children:"List<Product>"})})}),(0,s.jsx)(n.td,{children:"Yes"}),(0,s.jsx)(n.td,{children:"Product(s) viewed (usually one)."})]})})]}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-kotlin",children:'bambuser.track(\n    event = "product-view",\n    data = mapOf(\n        "products" to listOf(\n            mapOf(\n                "id"       to "314-7216-102",\n                "name"     to "Tennis Shoe Classic - Size 10",\n                "price"    to 70.99,\n                "currency" to "USD",\n                "location" to "https://example.com/products/314-7216",\n            ),\n        ),\n    ),\n)\n'})})]}),(0,s.jsxs)(c.A,{value:"refund",children:[(0,s.jsx)(n.p,{children:"Fire when a purchase is refunded (partial or full)."}),(0,s.jsxs)(n.table,{children:[(0,s.jsx)(n.thead,{children:(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.th,{children:"Name"}),(0,s.jsx)(n.th,{children:"Type"}),(0,s.jsx)(n.th,{children:"Required"}),(0,s.jsx)(n.th,{children:"Description"})]})}),(0,s.jsxs)(n.tbody,{children:[(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"transaction"})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.a,{href:"#transaction-object",children:(0,s.jsx)(n.code,{children:"Transaction"})})}),(0,s.jsx)(n.td,{children:"Yes"}),(0,s.jsxs)(n.td,{children:["Preferably reference the original order's ",(0,s.jsx)(n.code,{children:"id"}),"."]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"products"})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.a,{href:"#product-object",children:(0,s.jsx)(n.code,{children:"List<Product>"})})}),(0,s.jsx)(n.td,{children:"Yes"}),(0,s.jsx)(n.td,{children:"Line items refunded."})]})]})]}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-kotlin",children:'bambuser.track(\n    event = "refund",\n    data = mapOf(\n        "transaction" to mapOf(\n            "id"             to "abcd",   // original order id where possible\n            "subtotal"       to 70.99,\n            "currency"       to "USD",\n            "discount"       to 2.00,\n            "total"          to 87.18,\n            "tax"            to 14.2,\n            "shippingCost"   to 3.99,\n            "shippingMethod" to "Home delivery",\n            "coupon"         to "SUMMER_SALE",\n        ),\n        "products" to listOf(\n            mapOf(\n                "id"       to "314-7216-102",\n                "quantity" to 1,\n                "name"     to "Tennis Shoe Classic - Size 10",\n                "price"    to 70.99,\n                "currency" to "USD",\n                "discount" to 5.00,\n                "coupon"   to "SUMMER_SALE",\n            ),\n        ),\n    ),\n)\n'})})]})]}),"\n",(0,s.jsx)(n.hr,{}),"\n",(0,s.jsx)(n.h2,{id:"object-reference",children:"Object reference"}),"\n",(0,s.jsx)(n.h3,{id:"product-object",children:"Product Object"}),"\n",(0,s.jsxs)(n.p,{children:["Used inside the ",(0,s.jsx)(n.code,{children:"products"})," list of every event."]}),"\n",(0,s.jsxs)(n.table,{children:[(0,s.jsx)(n.thead,{children:(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.th,{children:"Field"}),(0,s.jsx)(n.th,{children:"Type"}),(0,s.jsx)(n.th,{children:"Required"}),(0,s.jsx)(n.th,{children:"Description"})]})}),(0,s.jsxs)(n.tbody,{children:[(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"id"})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"String"})}),(0,s.jsx)(n.td,{children:"Yes"}),(0,s.jsx)(n.td,{children:"Product identifier (SKU / variant id)."})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"price"})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"Double"})}),(0,s.jsx)(n.td,{children:"Yes"}),(0,s.jsx)(n.td,{children:"Unit price with product-level discount already applied."})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"currency"})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"String"})}),(0,s.jsx)(n.td,{children:"Yes"}),(0,s.jsxs)(n.td,{children:["ISO 4217 three-letter code (",(0,s.jsx)(n.code,{children:"USD"}),", ",(0,s.jsx)(n.code,{children:"EUR"}),", \u2026)."]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"quantity"})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"Int"})}),(0,s.jsx)(n.td,{children:"Yes*"}),(0,s.jsxs)(n.td,{children:["Not required for ",(0,s.jsx)(n.code,{children:"product-view"}
1),", ",(0,s.jsx)(n.code,{children:"add-to-wishlist"}),", ",(0,s.jsx)(n.code,{children:"remove-from-wishlist"})," (forced to ",(0,s.jsx)(n.code,{children:"1"}),")."]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"name"})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"String"})}),(0,s.jsx)(n.td,{children:"No"}),(0,s.jsx)(n.td,{children:"Human-readable product name."})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"image"})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"String"})}),(0,s.jsx)(n.td,{children:"No"}),(0,s.jsx)(n.td,{children:"Image URL."})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"discount"})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"Double"})}),(0,s.jsx)(n.td,{children:"No"}),(0,s.jsx)(n.td,{children:"Product-level discount amount, if any."})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"coupon"})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"String"})}),(0,s.jsx)(n.td,{children:"No"}),(0,s.jsx)(n.td,{children:"Coupon applied to this line, if any."})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"brand"})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"String"})}),(0,s.jsx)(n.td,{children:"No"}),(0,s.jsx)(n.td,{children:"Brand name."})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"category"})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"String"})}),(0,s.jsx)(n.td,{children:"No"}),(0,s.jsxs)(n.td,{children:["Category path \u2014 free-form (e.g. ",(0,s.jsx)(n.code,{children:"Footwear > Sports > Tennis"}),")."]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"location"})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"String"})}),(0,s.jsx)(n.td,{children:"No"}),(0,s.jsx)(n.td,{children:"Canonical product page URL."})]})]})]}),"\n",(0,s.jsx)(n.h3,{id:"transaction-object",children:"Transaction Object"}),"\n",(0,s.jsxs)(n.p,{children:["Used by ",(0,s.jsx)(n.code,{children:"purchase"})," and ",(0,s.jsx)(n.code,{children:"refund"})," events."]}),"\n",(0,s.jsxs)(n.table,{children:[(0,s.jsx)(n.thead,{children:(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.th,{children:"Field"}),(0,s.jsx)(n.th,{children:"Type"}),(0,s.jsx)(n.th,{children:"Required"}),(0,s.jsx)(n.th,{children:"Description"})]})}),(0,s.jsxs)(n.tbody,{children:[(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"id"})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"String"})}),(0,s.jsx)(n.td,{children:"Yes"}),(0,s.jsx)(n.td,{children:"Transaction id. For refunds, prefer the original order id."})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"subtotal"})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"Double"})}),(0,s.jsx)(n.td,{children:"Yes"}),(0,s.jsxs)(n.td,{children:[(0,s.jsx)(n.code,{children:"price \xd7 quantity"})," summed across all products. Excludes order-level discount, tax, shipping."]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"currency"})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"String"})}),(0,s.jsx)(n.td,{children:"Yes"}),(0,s.jsx)(n.td,{children:"ISO 4217 code."})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"total"})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"Double"})}),(0,s.jsx)(n.td,{children:"Yes"}),(0,s.jsxs)(n.td,{children:[(0,s.jsx)(n.code,{children:"subtotal \u2212 discount + tax + shippingCost"}),". For refunds: total amount refunded."]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"tax"})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"Double"})}),(0,s.jsx)(n.td,{children:"Yes"}),(0,s.jsx)(n.td,{children:"Total tax on the transaction."})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"shippingCost"})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"Double"})}),(0,s.jsx)(n.td,{children:"Yes"}),(0,s.jsx)(n.td,{children:"Shipping cost."})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"discount"})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"Double"})}),(0,s.jsx)(n.td,{children:"No"}),(0,s.jsx)(n.td,{children:"Order-level discount. Product-level discounts live on each line."})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"coupon"})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"String"})}),(0,s.jsx)(n.td,{children:"No"}),(0,s.jsx)(n.td,{children:"Order-level coupon code."})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"shippingMethod"})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"String"})}),(0,s.jsx)(n.td,{children:"No"}),(0,s.jsx)(n.td,{children:"Human-readable shipping method."})]})]})]}),"\n",(0,s.jsx)(n.hr,{}),"\n",(0,s.jsx)(n.h2,{id:"attribution--how-the-sdk-routes-events",children:"Attribution \u2014 how the SDK routes events"}),"\n",(0,s.jsx)(n.p,{children:"Two identifiers are persisted in native storage as soon as the SDK initializes:"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:(0,s.jsx)(n.code,{children:"userId"})})," \u2014 a UUID that identifies this device/install. 1-year rolling expiry. Same value used across all regions."]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"LCTE entries"})," \u2014 one per region (",(0,s.jsx)(n.code,{children:"us"}),", ",(0,s.jsx)(n.code,{children:"eu"}),"). Each entry carries ",(0,s.jsx)(n.code,{children:"{ userId, region, expiry }"})," with a 30-day rolling window."]}),"\n"]}),"\n",(0,s.jsxs)(n.p,{children:["When you call ",(0,s.jsx)(n.code,{children:"track(...)"}),", the SDK:"]}),"\n",(0,s.jsxs)(n.ol,{children:["\n",(0,s.jsxs)(n.li,{children:["Looks up which regions have a ",(0,s.jsx)(n.strong,{children:"live"})," LCTE entry (not expired)."]}),"\n",(0,s.jsxs)(n.li,{children:["If none, the call is a no-op and returns ",(0,s.jsx)(n.code,{children:"null"})," \u2014 the shopper's attribution window has elapsed."]}),"\n",(0,s.jsxs)(n.li,{children:["Otherwise, POSTs the payload to ",(0,s.jsx)(n.code,{children:"/collect/events"})," on each eligible region concurrently. As long as at least one region accepts, the call succeeds."]}),"\n"]}),"\n",(0,s.jsxs)(n.p,{children:["New LCTE entries are minted when a call reaches ",(0,s.jsx)(n.code,{children:"Connected"}),", and refreshed every time the shopper interacts with a call \u2014 so a shopper who takes weekly calls stays attributable indefinitely."]}),"\n",(0,s.jsxs)(n.admonition,{title:"userId lifecycle",type:"note",children:[(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"userId"})," is device-scoped. It does ",(0,s.jsx)(n.strong,{children:"not"})," change when:"]}),(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:["The environment switches from ",(0,s.jsx)(n.code,{children:"US"})," to ",(0,s.jsx)(n.code,{children:"EU"})," (same id gets a new LCTE for the new region)."]}),"\n",(0,s.jsxs)(n.li,{children:["The ",(0,s.jsx)(n.code,{children:"WebView"}),"'s cookies are wiped between calls."]}),"\n",(0,s.jsx)(n.li,{children:"The host app signs a different user in / out (SDK has no visibility into your auth)."}),"\n"]}),(0,s.jsxs)(n.p,{children:["It ",(0,s.jsx)(n.strong,{children:"does"})," change when the app is reinstalled or the user data is cleared. Per-customer attribution across devices is not yet supported \u2014 talk to your Bambuser rep if you need it."]})]}),"\n",(0,s.jsx)(n.hr,{}),"\n",(0,s.jsx)(n.h2,{id:"verification",children:"Verification"}),"\n",(0,s.jsx)(n.p,{children:"To confirm events are landing:"}),"\n",(0,s.jsxs)(n.ol,{children:["\n",(0,s.jsxs)(n.li,{children:["Use Charles Proxy or Proxyman with SSL proxying enabled for ",(0,s.jsx)(n.code,{children:"svc-prod-us.liveshopping.bambuser.com"})," (or the EU equivalent). On Android 7+ you'll need a network-security-config for your debug build."]}),"\n",(0,s.jsx)(n.li,{children:"Trigger the event in your app (place a test order, add to cart, etc.)."}),"\n",(0,s.jsxs)(n.li,{children:["You should see a ",(0,s.jsx)(n.code,{children:"POST /collect/events"})," with your enriched payload."]}),"\n",(0,s.jsxs)(n.li,{children:["Cross-check in BamHub \u2192 ",(0,s.jsx)(n.strong,{children:"Analytics \u2192 Shopper events"})," that the event appears under the same user id."]}),"\n"]}),"\n",(0,s.jsxs)(n.p,{children:["For the broader verification flow (including how Bambuser attributes events to specific calls), see ",(0,s.jsx)(n.a,{href:"/video-consultation/shopper-events-tracking-video-consultation-verification",children:"Tracking Verification"}),"."]}),"\n",(0,s.jsx)(n.hr,{}),"\n",(0,s.jsx)(n.h2,{id:"see-also",children:"See also"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.a,{href:"/video-consultation/shopper-events-tracking",children:"Shopper Events Tracking (web)"})," \u2014 the same events on the browser side."]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.a,{href:"/docs/video-consultation/mobileSDK/android/mobile-sdk/android/customer-events",children:"Customer Events"})," \u2014 ",(0,s.jsx)(n.strong,{children:"during-call"})," cart / product events fired to the agent's widget. Different c
1oncept, different endpoint."]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.a,{href:"/docs/video-consultation/mobileSDK/android/mobile-sdk/android/installation",children:"Installation"})," \u2014 how to add the SDK to your Android project."]}),"\n"]})]})}function x(e={}){const{wrapper:n}={...(0,i.R)(),...e.components};return n?(0,s.jsx)(n,{...e,children:(0,s.jsx)(u,{...e})}):u(e)}},19365(e,n,r){r.d(n,{A:()=>o});r(96540);var t=r(18215),s=r(47751);const i="tabItem_Ymn6";var d=r(74848);function c({children:e,className:n,hidden:r}){return(0,d.jsx)("div",{role:"tabpanel",className:(0,t.A)(i,n),hidden:r,children:e})}function o({children:e,className:n,value:r}){const{selectedValue:t,lazy:i}=(0,s.uc)(),o=r===t;return!o&&i?null:(0,d.jsx)(c,{className:n,hidden:!o,children:e})}},4865(e,n,r){r.d(n,{A:()=>j});r(96540);var t=r(18215),s=r(17559),i=r(47751),d=r(23104),c=r(92303);const o="tabList__CuJ",l="tabItem_LNqP";var a=r(74848);function h({className:e}){const{selectedValue:n,selectValue:r,tabValues:s,block:c}=(0,i.uc)(),o=[],{blockElementScrollPositionUntilNextRender:h}=(0,d.a_)(),u=e=>{const t=e.currentTarget,i=o.indexOf(t),d=s[i].value;d!==n&&(h(t),r(d))},x=e=>{let n=null;switch(e.key){case"Enter":u(e);break;case"ArrowRight":{const r=o.indexOf(e.currentTarget)+1;n=o[r]??o[0];break}case"ArrowLeft":{const r=o.indexOf(e.currentTarget)-1;n=o[r]??o[o.length-1];break}}n?.focus()};return(0,a.jsx)("ul",{role:"tablist","aria-orientation":"horizontal",className:(0,t.A)("tabs",{"tabs--block":c},e),children:s.map(({value:e,label:r,attributes:s})=>(0,a.jsx)("li",{role:"tab",tabIndex:n===e?0:-1,"aria-selected":n===e,ref:e=>{o.push(e)},onKeyDown:x,onClick:u,...s,className:(0,t.A)("tabs__item",l,s?.className,{"tabs__item--active":n===e}),children:r??e},e))})}function u({children:e}){return(0,a.jsx)("div",{className:"margin-top--md",children:e})}function x({className:e,children:n}){return(0,a.jsxs)("div",{className:(0,t.A)(s.G.tabs.container,"tabs-container",o),children:[(0,a.jsx)(h,{className:e}),(0,a.jsx)(u,{children:n})]})}function j(e){const n=(0,c.A)(),r=(0,i.OC)(e);return(0,a.jsx)(i.O_,{value:r,children:(0,a.jsx)(x,{className:e.className,children:(0,i.vT)(e.children)})},String(n))}},47751(e,n,r){r.d(n,{OC:()=>j,O_:()=>b,uc:()=>m,vT:()=>a});var t=r(96540),s=r(90612),i=r(205),d=r(57485),c=r(70679),o=r(31682),l=r(74848);function a(e){return t.Children.toArray(e).filter(e=>"\n"!==e)}function h(e){const{values:n,children:r}=e;return(0,t.useMemo)(()=>{const e=n??function(e){return t.Children.toArray(e).flatMap(e=>{if(!e)return[];if((0,t.isValidElement)(e)&&function(e){const{props:n}=e;return!!n&&"object"==typeof n&&"value"in n}(e))return[e];const n="string"==typeof e.type?e.type:e.type.name;throw new Error(`Docusaurus error: Bad <Tabs> child <${n}>: all children of the <Tabs> component should be <TabItem>, and every <TabItem> should have a unique "value" prop.\nIf you do not want to pass on a "value" prop to the direct children of <Tabs>, you can also pass an explicit <Tabs values={...}> prop.`)}).map(({props:{value:e,label:n,attributes:r,default:t}})=>({value:e,label:n,attributes:r,default:t}))}(r);return function(e){const n=(0,o.XI)(e,(e,n)=>e.value===n.value);if(n.length>0)throw new Error(`Docusaurus error: Duplicate values "${n.map(e=>`'${e.value}'`).join(", ")}" found in <Tabs>. Every value needs to be unique.`)}(e),e},[n,r])}function u({value:e,tabValues:n}){return n.some(n=>n.value===e)}function x({queryString:e=!1,groupId:n}){const r=(0,s.W6)(),i=function({queryString:e=!1,groupId:n}){if("string"==typeof e)return e;if(!1===e)return null;if(!0===e&&!n)throw new Error('Docusaurus error: The <Tabs> component groupId prop is required if queryString=true, because this value is used as the search param name. You can also provide an explicit value such as queryString="my-search-param".');return n??null}({queryString:e,groupId:n});return[(0,d.aZ)(i),(0,t.useCallback)(e=>{if(!i)return;const n=new URLSearchParams(r.location.search);n.set(i,e),r.replace({...r.location,search:n.toString()})},[i,r])]}function j(e){const{defaultValue:n,queryString:r=!1,groupId:s}=e,d=h(e),[o,l]=(0,t.useState)(()=>function({defaultValue:e,tabValues:n}){if(0===n.length)throw new Error("Docusaurus error: the <Tabs> component requires at least one <TabItem> children component");if(e){if(!u({value:e,tabValues:n}))throw new Error(`Docusaurus error: The <Tabs> has a defaultValue "${e}" but none of its children has the corresponding value. Available values are: ${n.map(e=>e.value).join(", ")}. If you intend to show no default tab, use defaultValue={null} instead.`);return e}const r=n.find(e=>e.default)??n[0];if(!r)throw new Error("Unexpected error: 0 tabValues");return r.value}({defaultValue:n,tabValues:d})),[a,j]=x({queryString:r,groupId:s}),[p,m]=function({groupId:e}){const n=function(e){return e?`docusaurus.tab.${e}`:null}(e),[r,s]=(0,c.Dv)(n);return[r,(0,t.useCallback)(e=>{n&&s.set(e)},[n,s])]}({groupId:s}),b=(()=>{const e=a??p;return u({value:e,tabValues:d})?e:null})();(0,i.A)(()=>{b&&l(b)},[b]);return{selectedValue:o,selectValue:(0,t.useCallback)(e=>{if(!u({value:e,tabValues:d}))throw new Error(`Can't select invalid tab value=${e}`);l(e),j(e),m(e)},[j,m,d]),tabValues:d,lazy:e.lazy??!1,block:e.block??!1}}const p=(0,t.createContext)(null);function m(){const e=t.useContext(p);if(!e)throw new Error("useTabsContext() must be used within a Tabs component");return e}function b(e){return(0,l.jsx)(p.Provider,{value:e.value,children:e.children})}},28453(e,n,r){r.d(n,{R:()=>d,x:()=>c});var t=r(96540);const s={},i=t.createContext(s);function d(e){const n=t.useContext(i);return t.useMemo(function(){return"function"==typeof e?e(n):{...n,...e}},[n,e])}function c(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:d(e.components),t.createElement(i.Provider,{value:n},e.children)}}}]);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.