Analytics
Deepdots Popup SDK indeholder et indbygget analyselag, der indsamler adfærdsdata fra dine brugere og videresender dem til en dedikeret integration i dit Deepdots-workspace. Det lader dig måle engagement, navigationsmønstre og forretningskritiske events uden at tilføje et separat analyseværktøj.
Opsætning
Sektion kaldt “Opsætning”Tilføj et analytics-objekt til init() 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 — alle events logges til konsollen, men intet sendes.
import { DeepdotsPopups } from '@magicfeedback/popup-sdk';
const popups = new DeepdotsPopups();popups.init({ apiKey: 'YOUR_PUBLIC_API_KEY', analytics: { publicKey: 'YOUR_ANALYTICS_PUBLIC_KEY', integration: 'YOUR_INTEGRATION_ID', },});Automatiske data
Sektion kaldt “Automatiske data”Følgende data indsamles med nul ekstra kode, så længe SDK’et er initialiseret:
| Data | Hvordan | Hvor det vises |
|---|---|---|
Skærmvisninger (deepdots_page_view) | History API (pushState / popstate / hashchange) | Events |
Aktiv engagementstid (deepdots_user_engagement) | visibilitychange-listener | Events |
Vedvarende brugeridentitet (user_id) | Genereres ved første besøg, gemmes i localStorage | Metadata |
| Enhedstype | Udledt fra User-Agent (mobile / tablet / desktop) | Kontekst |
| User agent | navigator.userAgent | Kontekst |
Sprog (deepdots_language) | Registreres automatisk (se Sprogregistrering) | Kontekst |
| App-version | appVersion sendt til init() | Kontekst |
Hvert flush (skjult faneblad, lukket side eller manuelt flushAnalytics()) sender de akkumulerede events som et batch. Backenden grupperer batches efter session, så du ser én tidslinje pr. brugerbesøg, ikke én post pr. flush.
Sprogregistrering
Sektion kaldt “Sprogregistrering”Det sprog, der rapporteres i analytics-konteksten — sendt som deepdots_language i Feedback-metadataen — bestemmes automatisk, i denne rækkefølge:
- Det
language, der sendes tilinit()— et eksplicit BCP-47-tag som'es-ES'. Sæt dette, når din app har sin egen i18n, og du vil tvinge det rapporterede sprog. navigator.language— browserens sprog (web).Intl-lokaliteten (Intl.DateTimeFormat().resolvedOptions().locale) — fallbacken der bruges, nårnavigator.languageikke er tilgængelig. Det er det, der får registreringen til at virke på React Native med Hermes, hvornavigator.languageikke findes.- Hvis ingen af disse giver et resultat, udelades feltet.
popups.init({ apiKey: 'YOUR_PUBLIC_API_KEY', analytics: { publicKey: 'YOUR_ANALYTICS_PUBLIC_KEY', integration: 'YOUR_INTEGRATION_ID' }, language: 'es-ES', // valgfrit — tvinger analytics-sproget; registreres automatisk, hvis udeladt});Det bestemte sprog er også det, popup-sprogmålretning (segments.lang) matches imod, så sætter du language eksplicit, fastlægger du begge ting på én gang. I React Native kræver dette 1.1.8 eller nyere — se React Native → Sprogsegmenter.
Sessioner
Sektion kaldt “Sessioner”En session er ét sammenhængende besøg. Backenden ejer session-id’et og syr batches sammen efter user_id, så et besøg læses som én tidslinje i stedet for én post pr. flush.
Fra 1.2.0 signaleres begge ender af en session eksplicit:
deepdots_session_start— ved hver sessionsåbning. Det vil sigeinit(), tilbagevenden til forgrunden, samtykke givet medsetTrackingEnabled(true)og efter et brugerskift. Hvis du initialiserer medtrackingEnabled: false, åbnes den første session, når samtykket gives.deepdots_session_end— ved lukning, med enreason. Afslutningsbatchen sendes medcompleted: true, hvilket er det, der fortæller backenden, at posten er færdig.
Afslutningsbatchen flusher alt, der stadig var åbent, i denne rækkefølge: den aktuelle skærms deepdots_page_view, en eventuel ventende deepdots_mini_service_exit, den akkumulerede deepdots_user_engagement og til sidst deepdots_session_end. Intet efterlades til et flush, der aldrig kommer.
reason | Hvornår |
|---|---|
page_hide | Siden lukkes (pagehide) — web |
background | Appen går i baggrunden (onBackground()) — React Native |
user_change | setUserId() skiftede bruger |
tracking_disabled | setTrackingEnabled(false) |
manual | endSession() |
endSession()
Sektion kaldt “endSession()”Lukker sessionen eksplicit. Brug den ved logout eller ved afslutningen af et selvindeholdt flow, når besøget er slut, men siden eller appen ikke er:
popups.endSession();Den næste sporede event åbner en ny session.
setUserId(userId?)
Sektion kaldt “setUserId(userId?)”Rapporterer et brugerskift — login, logout eller kontoskift. Den lukker den forrige brugers session med reason: 'user_change', skifter identiteten og åbner en ny session, så de to brugere aldrig deler tidslinje:
// Login: tilskriv det følgende dit eget bruger-idpopups.setUserId('customer-123');
// Logout: tilbage til SDK'ets anonyme idpopups.setUserId();Brugerdefinerede events
Sektion kaldt “Brugerdefinerede events”Brug track(name, params?) til at registrere enhver forretnings-event. Event-navne er frie strenge — brug snake_case med små bogstaver for at være konsistent med de automatiske events.
popups.track('add_to_cart', { product_id: 'p-123', value: 49.9, currency: 'EUR' });popups.track('checkout_started');popups.track('plan_upgraded', { plan: 'pro', billing: 'annual' });Søgning
Sektion kaldt “Søgning”trackSearch registrerer en søgeforespørgsel sammen med antallet af resultater. SDK’et tilføjer automatisk has_results: boolean ud fra antallet.
popups.trackSearch('løbesko', 0); // ingen resultater — has_results: falsepopups.trackSearch('t-shirt', 142); // has_results: trueFindbarhedsfriktion
Sektion kaldt “Findbarhedsfriktion”Registrer de øjeblikke, hvor brugere har svært ved at finde det, de har brug for:
popups.trackFindabilityFriction('checkout_address');popups.trackFindabilityFriction('plan_comparison');Funnel-trin
Sektion kaldt “Funnel-trin”Spor trin inde i en navngiven funnel. Grupper relaterede trin under samme funnel og taskId, så backenden kan beregne konverteringsrater:
popups.trackFunnelStep('onboarding', 'account_created', 'task-42');popups.trackFunnelStep('onboarding', 'profile_completed', 'task-42');popups.trackFunnelStep('onboarding', 'first_popup_seen', '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):
popups.trackMeaningfulInteraction('get_help');popups.trackMeaningfulInteraction('homepage', { screen: '/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 workflow i din app (checkout-flow, onboarding-guide, support-chat). SDK’et sporer indgang, udgang og varighed automatisk, når du signalerer grænserne:
// Brugeren går ind i checkout-flowetpopups.enterMiniService('checkout', 'home_banner');
// … brugeren fuldfører eller forlader flowet …
// Brugeren forlader det — send samme navn; varigheden beregnes automatiskpopups.exitMiniService('checkout');Flere mini-services kan være aktive på én gang (f.eks. en support-chat åbnet under checkout). Luk altid hver enkelt ved navn, så det rette workflow får sin deepdots_mini_service_exit og varighed:
popups.enterMiniService('checkout', 'home_banner');popups.enterMiniService('support_chat', 'fab'); // begge aktive nupopups.exitMiniService('checkout'); // lukker checkout; support_chat forbliver åbenEthvert survey, der vises, mens en mini-service er aktiv, får automatisk et mini_service-metadata-tag (den senest indtastede), hvilket lader dig filtrere CSAT-resultater efter workflow-kontekst i Deepdots.
Brugerattributter
Sektion kaldt “Brugerattributter”Kald setUserAttributes for at knytte forretningsattributter til brugerens analytics-kontekst. Disse inkluderes i hvert efterfølgende flush.
popups.setUserAttributes({ plan: 'pro', registration_status: 'registered', sector: 'retail',});Attributter er kumulative — hvert kald flettes med tidligere angivne.
Kontaktpost
Sektion kaldt “Kontaktpost”setContactAttributes sender attributterne til POST /sdk/popups/contact og opretter eller opdaterer brugerens kontaktpost i Deepdots. Dette endpoint kaldes kun, når et userId blev angivet i init(), og tracking er aktiveret.
const sent = await popups.setContactAttributes({ language: 'en', age: 34, plan: 'premium' });// sent: true hvis et POST blev udført, false hvis attributterne ikke er ændret (deduplikering)Du kan også sende contactAttributes direkte i init() for at udløse kontaktopdateringen ved opstart:
popups.init({ apiKey: 'YOUR_PUBLIC_API_KEY', userId: 'user-123', contactAttributes: { plan: 'premium', language: 'en' },});Metrikker
Sektion kaldt “Metrikker”Kald setMetric(key, value) for at registrere en målbar værdi — en mængde, du vil rapportere sammen med brugerens analytics-kontekst, såsom kurvværdi eller antal varer i kurven.
popups.setMetric('cart_value', 49.99);popups.setMetric('items_in_cart', 3);Signaturen er:
setMetric(key: string, value: string | number | boolean): voidMetrikker lander i et dedikeret metrics-felt i analytics-payloaden (POST /sdk/feedback), adskilt fra metadata og fra brugerattributter.
Adfærd
Sektion kaldt “Adfærd”- Vedvarende — når den er sat, gensendes værdien ved hvert flush, indtil den ændres.
- Overskriver pr. key — at kalde
setMetricigen med samme key erstatter den tidligere værdi. - Konverteres til string — værdien gemmes som string på wiren (
49.99→"49.99"). - Tomme keys ignoreres — et kald med tom
keyer en no-op. - Respekterer kill-switchen — det er en no-op, mens tracking er deaktiveret (se Privatliv og samtykke).
Metrikker vs. brugerattributter
Sektion kaldt “Metrikker vs. brugerattributter”Begge knytter kontekst til brugeren, men de besvarer forskellige spørgsmål:
setUserAttributes | setMetric | |
|---|---|---|
| Repræsenterer | Dimensioner at opdele efter | Målbare værdier at rapportere |
| Eksempel | plan: 'pro', sector: 'retail' | cart_value: 49.99, items_in_cart: 3 |
| Payload-felt | metadata | metrics |
Brug attributter til hvem — kategorierne du filtrerer og grupperer efter — og metrikker til hvor meget — mængderne 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 pr. besked. Brug en enkelt metode, trackMessage(stage, options), ved hvert trin i besked-funnelen:
// Notifikationen blev leveret (push modtaget, eller in-app-besked vist)popups.trackMessage('delivered', { id: 'msg-42', title: 'Summer Sale', channel: 'push', campaign: 'summer_sale' });
// Brugeren trykkede / klikkede på denpopups.trackMessage('clicked', { id: 'msg-42', title: 'Summer Sale', channel: 'push' });
// Brugeren fuldførte den tilsigtede handling (f.eks. købte)popups.trackMessage('converted', { id: 'msg-42', title: 'Summer Sale', channel: 'push', value: 49.9, currency: 'EUR' });| Felt | Type | Beskrivelse |
|---|---|---|
stage (1. arg) | 'delivered' / 'clicked' / 'converted' | Trin i besked-funnelen |
id | string | Korrelerer trinnene for den samme besked |
title | string | Grupperingsdimension for Messaging-metrikker |
channel | 'push' / 'in_app' | Leveringskanal |
campaign | string? | Kampagnenavn (valgfrit) |
value / currency | number / string | Konverteringsværdi (typisk ved converted) |
params | object? | Ekstra nøgle/værdi-par |
Hvert kald udsender én deepdots_message-event; backenden grupperer efter title (og opdeler efter registreringsstatus / kanal) for at beregne leveringsantal, CTR, unikke click-through-brugere, konverteringsrate og handlingsbrugere.
Regler for et korrekt funnel
Sektion kaldt “Regler for et korrekt funnel”CTR og konverteringsrate er forhold målt op imod delivered. Hvis stadierne ikke passer sammen, bliver de tal forkerte — og mangler delivered, bliver værdierne umulige, fordi nævneren er nul.
- Send alle tre stadier.
deliveredsendes, når beskeden når enheden, før brugeren åbner den — ved in-app-beskeder når den vises. Uden den findes der ingen nævner. - Brug det samme
idi alle tre stadier. Det er det, der korrelerer funnelet, og det skal være unikt pr. udsendelse, ikke pr. kampagne. - Ét
id, én kanal. Hvis en kampagne sendes både som push og som in-app-besked, brug to forskelligeid-værdier med sammecampaign. - Ét kald pr. stadie. Hvis din klik-handler kan køre ad to veje — åbning af notifikationen plus et deep link — sørg for, at kun én af dem udsender
clicked.
Validering
Sektion kaldt “Validering”Fra 1.2.0 kasserer SDK’et kald, der bryder disse regler, i stedet for at videresende dem, og advarer i konsollen (advarslens tekst leveres på spansk):
[DeepdotsPopups] trackMessage descartado (channel_conflict): message_id "msg-42" ya se reportó en channel "push"; se descarta "in_app"| Regel | Hvad kasseres | reason |
|---|---|---|
channel skal være push eller in_app | Enhver anden værdi | invalid_channel |
Hvert par (id, stage) sendes én gang | Det 2. kald til samme stadie for samme besked | duplicate_stage |
Et id beholder sin kanal | Events på en anden kanal end den først sete | channel_conflict |
Kontrollerne gælder for sessionen og er pr. enhed, og de overvåger op til 500 besked-id’er (de ældste fjernes først). Et afvist kald bruger ikke state: efter en channel_conflict på in_app bliver samme stadie på den korrekte kanal stadig sendt.
Hvis du ser disse advarsler under integrationen, peger de på en reel dobbelttælling — ret kaldstedet i stedet for at ignorere dem.
Crash- og fejlrapportering
Sektion kaldt “Crash- og fejlrapportering”SDK’et opfanger applikationsfejl og viser dem som deepdots_app_crash-events, hvilket driver Stability-metrikkerne (crash-frie brugere, crashes pr. release og enhed). En deepdots_session_start-event udsendes ved hver sessionsåbning, så backenden kan beregne crash-frie rater.
Automatisk opfangning
Sektion kaldt “Automatisk opfangning”Uhåndterede fejl opfanges automatisk — på web via window.onerror / unhandledrejection, og i React Native via global.ErrorUtils (koblet af setupReactNative). Opfangede crashes gemmes lokalt og afspilles ved næste opstart, fordi processen kan dø før næste flush — så det crash, der afsluttede en session, når stadig frem til Deepdots.
Manuel fejlrapportering
Sektion kaldt “Manuel fejlrapportering”Brug reportError til håndterede fejl, med en valgfri alvorlighedsgrad og fri kontekst:
try { await checkout();} catch (e) { popups.reportError(e, { severity: 'error', context: { screen: 'Checkout', order_id: 'o-42' } });}| Mulighed | Værdier | Standard |
|---|---|---|
severity | 'fatal' / 'error' / 'warning' | 'error' |
handled | boolean | true |
context | fri nøgle/værdi-map (præfikset ctx_ i payloaden) | — |
Crash-konteksten (app-version, OS, enhed) opfanges i det øjeblik, crashet sker, så et crash på en ældre release rapporterer stadig den version, det skete på.
Crash-rapportering respekterer den samme samtykke-kill-switch som resten af analytics (trackingEnabled / setTrackingEnabled).
Privatliv og samtykke
Sektion kaldt “Privatliv og samtykke”Sæt trackingEnabled: false i init() for at starte med al analytics- og kontakt-tracking deaktiveret — nyttigt, når du har brug for eksplicit brugersamtykke, før du indsamler data.
popups.init({ apiKey: 'YOUR_PUBLIC_API_KEY', trackingEnabled: false,});
// Senere, når brugeren giver samtykke:popups.setTrackingEnabled(true);setTrackingEnabled(false) lukker den aktuelle session med reason: 'tracking_disabled' og suspenderer alle udgående kald (analytics, kontakt) — de data, der blev indsamlet før fravalget, leveres stadig i stedet for at blive smidt væk. setTrackingEnabled(true) genoptager dem, tildeler et vedvarende user_id, hvis et ikke allerede var gemt, og åbner en ny session.
React Native
Sektion kaldt “React Native”I React Native kræver to automatiske adfærd eksplicit host-integration:
Navigationssporing
Sektion kaldt “Navigationssporing”Fordi History API er utilgængeligt, skal du rapportere skærmændringer manuelt efter hver navigations-event:
// I React Navigations onStateChange-callback:popups.setScreen(route.name);Livscyklus (engagementstid)
Sektion kaldt “Livscyklus (engagementstid)”Forbind SDK’et til appens forgrunds-/baggrunds-livscyklus, så engagementstiden måles korrekt, og events flushes, når appen går i baggrunden:
import { AppState } from 'react-native';
AppState.addEventListener('change', (state) => { if (state === 'active') popups.onForeground(); else popups.onBackground(); // lukker sessionen og flusher});Forhåndsvisning af events før afsendelse
Sektion kaldt “Forhåndsvisning af events før afsendelse”Under udvikling kan du inspicere den aktuelle event-buffer uden at flushe:
const preview = popups.previewAnalytics();console.log(preview.events); // alle events i kø siden sidste flushFor at fremtvinge et flush manuelt (nyttigt til test):
popups.flushAnalytics();Leveringsgarantier
Sektion kaldt “Leveringsgarantier”Flush sker automatisk — hvert 30. sekund i forgrunden, når bufferen når 20 events, når fanen skjules, og når siden eller appen lukkes. Du har sjældent brug for selv at kalde flushAnalytics(). Fra 1.1.8 og frem er kanalen hærdet, så det sidste batch i et besøg — det, der bærer det afsluttende deepdots_page_view og deepdots_user_engagement — ikke går tabt:
- Overlever navigation og lukning — forespørgslen bruger
keepalive, og det afsluttende flush ved sidelukning skifter tilnavigator.sendBeacon. Browsere afbryder den ikke længere undervejs. - Genforsøger forbigående fejl — en netværksfejl eller en
5xx/408/429lægger batchet tilbage forrest i bufferen i kronologisk orden, så det genforsøges ved næste flush. Op til 200 events holdes; derudover kasseres de ældste. - Rapporterer permanente fejl — en
4xx(for eksempel en406for en ukendt Contact) logges med status og svarets indhold, og batchet kasseres i stedet for at fejle lydløst. - Holder én post pr. besøg — indtil backend har returneret et session-id, serialiseres batches i stedet for at sendes parallelt, så et besøg ikke deles over to poster.
flushAnalytics() tager et final-flag, som er det, SDK’et selv bruger ved sidelukning. Send det kun, hvis du implementerer din egen nedlukningssti — det foretrækker sendBeacon og venter ikke på svaret:
popups.flushAnalytics({ final: true });