Analytics
Deepdots Popup Native SDK indeholder et indbygget analyselag, der indsamler adfærdsdata fra dine brugere og videresender dem til en dedikeret integration i dit Deepdots-workspace. Det deler eventmodellen og backend-kanalen med Web SDK’et, så dashboardene læses ens uanset platform.
Helper-metoderne (track, trackMessage, setMetric, …) har de samme navne på Android og iOS. Eksemplerne er i Kotlin; kald den identiske metode fra Swift med Swift-syntaks. Hvor platformene adskiller sig — initialisering, livscyklus, navigation — vises begge.
Opsætning
Sektion kaldt “Opsætning”Send et analytics-objekt til InitOptions med publicKey og integration-id’et for den integration, der er oprettet i dit Deepdots-workspace. Uden det kører SDK’et i dry-run-tilstand — hver event-payload printes til konsollen (Logcat / Xcode), men intet sendes.
Android
Sektion kaldt “Android”val options = InitOptions( popupOptions = PopupOptions(publicKey = "<your-public-key>"), analytics = AnalyticsKeys( publicKey = "<your-analytics-public-key>", integration = "<your-integration-id>", ), provideLang = { "da" }, metadata = mapOf("userId" to "customer-123"), // valgfrit — identificér brugeren)val sdk = DeepdotsPopups().apply { initialize(options) }let options = InitOptions( popupOptions: PopupOptions(id: nil, publicKey: "<your-public-key>", companyId: nil), provideLang: { Locale.current.language.languageCode?.identifier ?? "da" }, analytics: AnalyticsKeys( publicKey: "<your-analytics-public-key>", integration: "<your-integration-id>" ), metadata: ["userId": "customer-123"])let instance = DeepdotsSDK.DeepdotsPopups()instance.initialize(options: options)Automatiske data
Sektion kaldt “Automatiske data”Følgende data indsamles med nul ekstra kode, når SDK’et er initialiseret, tracking er slået til, og du har wiret livscyklus- og navigations-hooks:
| Data | Hvordan | Hvor det vises |
|---|---|---|
Skærmvisninger (deepdots_page_view) | setPath() ved hver navigation | Events |
Aktiv engagement-tid (deepdots_user_engagement) | Foreground/background-livscyklus | Events |
Vedvarende brugeridentitet (user_id) | Genereres ved første start, gemmes i SharedPreferences (Android) / NSUserDefaults (iOS) | Metadata |
| Enhedstype, OS-version, enhedsmodel, app-version | Hentes fra platformen | Context |
Sprog (deepdots_language) | provideLang-resolver, med fallback til platformens locale | Context |
Hvert flush sender de akkumulerede events som et batch. Backenden grupperer batches efter session, så du ser én tidslinje pr. besøg, ikke én post pr. flush.
Livscyklus og navigation
Sektion kaldt “Livscyklus og navigation”Modsat browseren kan det native SDK ikke selv observere navigation eller foreground/background-overgange. To hooks skal wires af hosten — uden dem er der ingen page_view-events, ingen engagement-tid og ingen sessionsgrænser.
Navigation
Sektion kaldt “Navigation”Kald setPath(path) ved hvert skærmskift. Det første kald starter navigations-tracking; hvert senere kald lukker den forrige skærms deepdots_page_view (med dens varighed) og åbner den næste:
sdk.setPath("/home")sdk.setPath("/products/42") // lukker "/home" med dens varighed, åbner "/products/42"Stien fodrer også popup-rute-triggers og rute-exit-popups, så hold den opdateret, selv hvis du kun bruger popups.
Sessioner og engagement
Sektion kaldt “Sessioner og engagement”Forbind SDK’et til app-livscyklussen, så en session åbnes i foreground og lukkes i background.
Android
Sektion kaldt “Android”// I din Activity / livscyklus-observer:override fun onStart() { super.onStart(); sdk.onForeground() }override fun onStop() { super.onStop(); sdk.onBackground() }NotificationCenter.default.addObserver(forName: UIApplication.willEnterForegroundNotification, object: nil, queue: .main) { _ in instance.onForeground()}NotificationCenter.default.addObserver(forName: UIApplication.didEnterBackgroundNotification, object: nil, queue: .main) { _ in instance.onBackground()}Sessioner
Sektion kaldt “Sessioner”En session er ét sammenhængende besøg. Backenden ejer session-id’et og syr batches sammen efter user_id. Begge ender signaleres eksplicit:
deepdots_session_start— ved hver sessionsåbning:initialize(), retur til foreground, samtykke viasetTrackingEnabled(true)og efter et brugerskift.deepdots_session_end— ved lukning, med enreason. Det afsluttende batch sendes medcompleted: true, hvilket fortæller backenden, at posten er færdig.
Det afsluttende batch flusher alt, der stadig er åbent, i rækkefølge: den aktuelle skærms deepdots_page_view, ethvert ventende deepdots_mini_service_exit, den akkumulerede deepdots_user_engagement og til sidst deepdots_session_end.
reason | Hvornår |
|---|---|
background | Appen går i baggrunden (onBackground()) |
user_change | setUserId() skiftede bruger |
tracking_disabled | setTrackingEnabled(false) |
manual | endSession() |
endSession()
Sektion kaldt “endSession()”Lukker sessionen eksplicit — ved logout eller i slutningen af et selvstændigt flow. Det næste sporede event åbner en ny.
sdk.endSession()setUserId(userId?)
Sektion kaldt “setUserId(userId?)”Rapporterer et brugerskift (login, logout eller kontoskift). Det lukker den forrige brugers session med reason: user_change, skifter identiteten og åbner en ny session, så de to brugere aldrig deler tidslinje:
sdk.setUserId("customer-123") // loginsdk.setUserId() // logout — tilbage til det anonyme idBrugerdefinerede events
Sektion kaldt “Brugerdefinerede events”Brug track(name, params?) til at registrere ethvert forretningsevent. Brug snake_case med små bogstaver for at være konsistent med de automatiske events.
sdk.track("add_to_cart", mapOf("product_id" to "p-123", "value" to 49.9, "currency" to "EUR"))sdk.track("checkout_started")Søgning
Sektion kaldt “Søgning”trackSearch registrerer en forespørgsel og dens antal resultater; SDK’et udleder has_results fra tallet.
sdk.trackSearch("running shoes", 0) // ingen resultater — has_results: falsesdk.trackSearch("t-shirt", 142) // has_results: trueFindbarhedsfriktion
Sektion kaldt “Findbarhedsfriktion”sdk.trackFindabilityFriction("checkout_address")Funnel-trin
Sektion kaldt “Funnel-trin”Grupper relaterede trin under samme funnel og taskId, så backenden kan beregne konverteringsrater:
sdk.trackFunnelStep("onboarding", "account_created", "task-42")sdk.trackFunnelStep("onboarding", "profile_completed", "task-42")Meningsfulde interaktioner
Sektion kaldt “Meningsfulde interaktioner”Registrer en meningsfuld interaktion — et øjeblik, der signalerer, at brugeren fik reel værdi ud af din app. interactionType er grupperingsdimensionen, så hold et lille, stabilt sæt af navne (get_help, homepage, contact_support):
sdk.trackMeaningfulInteraction("get_help")sdk.trackMeaningfulInteraction("homepage", mapOf("screen" to "/home"))Hvert kald udsender et deepdots_meaningful_interaction-event, der driver Effectiveness-dashboardet.
Sporing af mini-services
Sektion kaldt “Sporing af mini-services”En mini-service er ethvert afgrænset flow i din app (checkout, onboarding-wizard, supportchat). Signalér grænserne, og SDK’et sporer indgang, udgang og varighed:
sdk.enterMiniService("checkout", "home_banner")// … brugeren fuldfører eller forlader …sdk.exitMiniService("checkout") // udsender mini_service_exit med varighedenFlere mini-services kan være aktive samtidig; luk altid hver enkelt ved navn. Enhver survey, der vises, mens en mini-service er aktiv, får et mini_service-metadata-tag, så du kan filtrere CSAT efter flow-kontekst.
Brugerattributter
Sektion kaldt “Brugerattributter”setUserAttributes vedhæfter forretningsdimensioner til brugerens analytics-kontekst, inkluderet i hvert efterfølgende flush og kumulativt på tværs af kald:
sdk.setUserAttributes(mapOf( "plan" to "pro", "registration_status" to "registered", "sector" to "retail",))Kontaktpost
Sektion kaldt “Kontaktpost”setContactAttributes sender attributterne til POST /sdk/popups/contact og opretter eller opdaterer brugerens kontaktpost. Det er en suspend-funktion og udløses kun, når et userId blev angivet, og tracking er slået til; den returnerer true, hvis der blev lavet et POST, false, hvis attributterne var uændrede (deduplikering).
val sent = sdk.setContactAttributes(mapOf("language" to "da", "age" to 34, "plan" to "premium"))Du kan også sende contactAttributes i InitOptions for at udløse opdateringen ved opstart.
Metrics
Sektion kaldt “Metrics”setMetric(key, value) registrerer en målbar værdi — en mængde, der rapporteres sammen med brugerens kontekst, såsom kurvens værdi. Metrics lander i et dedikeret metrics-felt i payloaden, adskilt fra brugerattributter.
sdk.setMetric("cart_value", 49.99)sdk.setMetric("items_in_cart", 3)- Vedvarende — gensendes ved hvert flush, indtil den ændres.
- Overskriver pr. nøgle — samme nøgle erstatter den forrige værdi.
- Konverteres til string på wiren.
- Respekterer kill-switchen — en no-op, mens tracking er slået fra.
Brug attributter til hvem (dimensioner du grupperer efter) og metrics til hvor meget (mængder du måler).
Messaging
Sektion kaldt “Messaging”Spor livscyklussen for din apps notifikationer (push og in-app), så Deepdots kan måle levering, click-through og konvertering. Kald trackMessage ved hvert trin i funnelen:
sdk.trackMessage("delivered", id = "msg-42", title = "Summer Sale", channel = "push", campaign = "summer_sale")sdk.trackMessage("clicked", id = "msg-42", title = "Summer Sale", channel = "push")sdk.trackMessage("converted", id = "msg-42", title = "Summer Sale", channel = "push", value = 49.9, currency = "EUR")| Argument | Type | Beskrivelse |
|---|---|---|
stage | "delivered" / "clicked" / "converted" | Trin i beskedens funnel |
id | String | Korrelerer trinene for samme besked |
title | String | Grupperingsdimension for Messaging-metrics |
channel | "push" / "in_app" | Leveringskanal |
campaign | String? | Kampagnenavn (valgfrit) |
value / currency | Double? / String? | Konverteringsværdi (typisk ved converted) |
params | Map? | Ekstra nøgle/værdi-par |
Hvert kald udsender ét deepdots_message-event; backenden grupperer efter title for at beregne leveringsantal, CTR, unikke click-through-brugere, konverteringsrate og handlingsbrugere.
Regler for en korrekt funnel
Sektion kaldt “Regler for en korrekt funnel”CTR og konverteringsrate er forhold over delivered, så trinene skal passe sammen:
- Send alle tre trin.
deliveredsendes, når beskeden når enheden, før brugeren åbner den. Uden det er der ingen nævner. - Brug samme
idpå tværs af de tre trin. Unikt pr. afsendelse, ikke pr. kampagne. - Ét
id, én kanal. En kampagne sendt både som push og in-app skal bruge to forskelligeid-værdier, der deler sammecampaign. - Ét kald pr. trin.
Validering
Sektion kaldt “Validering”SDK’et kasserer kald, der bryder disse regler, i stedet for at videresende dem, og advarer i konsollen:
[DeepdotsPopups] trackMessage discarded (channel_conflict): message_id "msg-42" was already reported on channel "push"; discarding "in_app"| Regel | Hvad kasseres | reason |
|---|---|---|
channel skal være push eller in_app | Enhver anden værdi | invalid_channel |
Hvert (id, stage)-par sendes én gang | Det 2. kald til samme trin for samme besked | duplicate_stage |
Et id beholder sin kanal | Events på en anden kanal end den først sete | channel_conflict |
Tjekkene varer sessionen og er pr. enhed, og de sporer op til 500 message-id’er (ældste smides ud først). Hvis disse advarsler dukker op, peger de på en reel dobbelttælling — ret kaldstedet.
Crash- og fejlrapportering
Sektion kaldt “Crash- og fejlrapportering”Ufangede fejl på Kotlin-siden fanges automatisk, gemmes til lager og afspilles igen ved næste opstart — så det crash, der afsluttede en session, når stadig frem til Deepdots, selvom processen døde før næste flush. De vises som deepdots_app_crash-events og driver Stability-metrikkerne.
Rapportér håndterede fejl manuelt:
try { checkout()} catch (e: Throwable) { sdk.reportError(e, severity = "error", context = mapOf("screen" to "Checkout", "order_id" to "o-42"))}| Argument | Værdier | Standard |
|---|---|---|
severity | "fatal" / "error" / "warning" | "error" |
handled | Boolean | true |
context | frit map (præfikset ctx_ i payloaden) | — |
Crash-rapportering respekterer den samme samtykke-kill-switch som resten af analytics.
Privatliv og samtykke
Sektion kaldt “Privatliv og samtykke”Sæt trackingEnabled = false i InitOptions for at starte med al analytics- og kontakt-tracking slået fra — nyttigt, når du har brug for eksplicit samtykke først.
val options = InitOptions( popupOptions = PopupOptions(publicKey = "<your-public-key>"), trackingEnabled = false,)// Senere, når brugeren giver samtykke:sdk.setTrackingEnabled(true)setTrackingEnabled(false) lukker den aktuelle session med reason: tracking_disabled og suspenderer alle udgående kald — data indsamlet før fravalget leveres stadig, i stedet for at blive smidt væk. setTrackingEnabled(true) genoptager dem, tildeler et vedvarende user_id, hvis der ikke var gemt et, og åbner en ny session.
Forhåndsvisning og levering
Sektion kaldt “Forhåndsvisning og levering”Inspicér det aktuelle buffer uden at flushe, eller fremtving et flush (nyttigt i udvikling):
val preview = sdk.previewAnalytics() // det AnalyticsEnvelope, der ville blive sendtsdk.flushAnalytics() // send nuFlushes sker også automatisk (periodisk i foreground, ved buffer-størrelse og ved onBackground()). Kanalen er hærdet, så det afsluttende batch ikke går tabt:
- Genforsøger forbigående fejl — en netværksfejl eller et
5xx/408/429lægger batchet forrest i bufferen igen, i kronologisk rækkefølge, til genforsøg ved næste flush. - Rapporterer permanente fejl — et
4xx(fx et406for en ukendt Contact) logges med sin status og body, og batchet kasseres i stedet for at fejle i stilhed. - Beholder én post pr. besøg — indtil backenden returnerer et session-id, serialiseres batches i stedet for at blive sendt parallelt.