Gå til indhold

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.

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',
},
});

Følgende data indsamles med nul ekstra kode, så længe SDK’et er initialiseret:

DataHvordanHvor det vises
Skærmvisninger (deepdots_page_view)History API (pushState / popstate / hashchange)Events
Aktiv engagementstid (deepdots_user_engagement)visibilitychange-listenerEvents
Vedvarende brugeridentitet (user_id)Genereres ved første besøg, gemmes i localStorageMetadata
EnhedstypeUdledt fra User-Agent (mobile / tablet / desktop)Kontekst
User agentnavigator.userAgentKontekst
Sprog (deepdots_language)Registreres automatisk (se Sprogregistrering)Kontekst
App-versionappVersion 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.

Det sprog, der rapporteres i analytics-konteksten — sendt som deepdots_language i Feedback-metadataen — bestemmes automatisk, i denne rækkefølge:

  1. Det language, der sendes til init() — 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.
  2. navigator.language — browserens sprog (web).
  3. Intl-lokaliteten (Intl.DateTimeFormat().resolvedOptions().locale) — fallbacken der bruges, når navigator.language ikke er tilgængelig. Det er det, der får registreringen til at virke på React Native med Hermes, hvor navigator.language ikke findes.
  4. 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.


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 sige init(), tilbagevenden til forgrunden, samtykke givet med setTrackingEnabled(true) og efter et brugerskift. Hvis du initialiserer med trackingEnabled: false, åbnes den første session, når samtykket gives.
  • deepdots_session_end — ved lukning, med en reason. Afslutningsbatchen sendes med completed: 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.

reasonHvornår
page_hideSiden lukkes (pagehide) — web
backgroundAppen går i baggrunden (onBackground()) — React Native
user_changesetUserId() skiftede bruger
tracking_disabledsetTrackingEnabled(false)
manualendSession()

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.

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-id
popups.setUserId('customer-123');
// Logout: tilbage til SDK'ets anonyme id
popups.setUserId();

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' });

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: false
popups.trackSearch('t-shirt', 142); // has_results: true

Registrer de øjeblikke, hvor brugere har svært ved at finde det, de har brug for:

popups.trackFindabilityFriction('checkout_address');
popups.trackFindabilityFriction('plan_comparison');

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');

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.


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-flowet
popups.enterMiniService('checkout', 'home_banner');
// … brugeren fuldfører eller forlader flowet …
// Brugeren forlader det — send samme navn; varigheden beregnes automatisk
popups.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 nu
popups.exitMiniService('checkout'); // lukker checkout; support_chat forbliver åben

Ethvert 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.


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.

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' },
});

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): void

Metrikker lander i et dedikeret metrics-felt i analytics-payloaden (POST /sdk/feedback), adskilt fra metadata og fra brugerattributter.

  • Vedvarende — når den er sat, gensendes værdien ved hvert flush, indtil den ændres.
  • Overskriver pr. key — at kalde setMetric igen 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 key er en no-op.
  • Respekterer kill-switchen — det er en no-op, mens tracking er deaktiveret (se Privatliv og samtykke).

Begge knytter kontekst til brugeren, men de besvarer forskellige spørgsmål:

setUserAttributessetMetric
RepræsentererDimensioner at opdele efterMålbare værdier at rapportere
Eksempelplan: 'pro', sector: 'retail'cart_value: 49.99, items_in_cart: 3
Payload-feltmetadatametrics

Brug attributter til hvem — kategorierne du filtrerer og grupperer efter — og metrikker til hvor meget — mængderne du måler.


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å den
popups.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' });
FeltTypeBeskrivelse
stage (1. arg)'delivered' / 'clicked' / 'converted'Trin i besked-funnelen
idstringKorrelerer trinnene for den samme besked
titlestringGrupperingsdimension for Messaging-metrikker
channel'push' / 'in_app'Leveringskanal
campaignstring?Kampagnenavn (valgfrit)
value / currencynumber / stringKonverteringsværdi (typisk ved converted)
paramsobject?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.

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.

  1. Send alle tre stadier. delivered sendes, 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.
  2. Brug det samme id i alle tre stadier. Det er det, der korrelerer funnelet, og det skal være unikt pr. udsendelse, ikke pr. kampagne.
  3. Ét id, én kanal. Hvis en kampagne sendes både som push og som in-app-besked, brug to forskellige id-værdier med samme campaign.
  4. É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.

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"
RegelHvad kasseresreason
channel skal være push eller in_appEnhver anden værdiinvalid_channel
Hvert par (id, stage) sendes én gangDet 2. kald til samme stadie for samme beskedduplicate_stage
Et id beholder sin kanalEvents på en anden kanal end den først setechannel_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_conflictin_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.


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.

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.

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' } });
}
MulighedVærdierStandard
severity'fatal' / 'error' / 'warning''error'
handledbooleantrue
contextfri 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).


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.


I React Native kræver to automatiske adfærd eksplicit host-integration:

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);

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 flush

For at fremtvinge et flush manuelt (nyttigt til test):

popups.flushAnalytics();

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 til navigator.sendBeacon. Browsere afbryder den ikke længere undervejs.
  • Genforsøger forbigående fejl — en netværksfejl eller en 5xx / 408 / 429 læ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 en 406 for 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 });