Artikler

Server-side tracking i praksis: arkitektur, deduplikering og hvad det ikke løser

Server-side tracking giver bedre data til Meta og Google, når det er bygget rigtigt, og dobbelt-talte ordrer, når det ikke er. Her er arkitekturen, deduplikeringen, Safari-reglerne og samtykkekravet, som det ser ud i oktober 2026.

Hassan Aziz
Partner & Projektleder, Bullmade

Web12. oktober 202613 min læsning

Server-side tracking i praksis: arkitektur, deduplikering og hvad det ikke løser

Hvad server-side tracking er, og hvad det ikke er

Server-side tracking betyder, at målingen sendes fra en server, I kontrollerer, til Google, Meta og de andre platforme, i stedet for at hvert enkelt script i browseren sender direkte. Forskellen er, hvor data ender først, og hvem der bestemmer, hvad der sendes videre.

Det løser tre konkrete problemer. Ordrer, der aldrig blev målt, fordi tak-siden ikke loadede eller et script blev blokeret. Cookies, der forsvinder hurtigere end jeres købsrejse varer. Og manglende kontrol over, hvad tredjeparter får med, fordi deres scripts selv læser fra siden.

Det løser ikke samtykke. En bruger, der har sagt nej, har også sagt nej, når data går gennem jeres egen server. Og det løser ikke en rodet datalayer eller et manglende transaktions-ID. Server-side flytter de fejl et sted hen, hvor de er sværere at se.

Derfor er det deduplikering og samtykke, I skal bruge tiden på, og ikke selve serveren. Ordet er forklaret kort i ordbogen. Resten af artiklen er den lange version.

Tre arkitekturer: browser-tags, server-container og direkte API

Der er tre måder at få en konvertering fra webshoppen til en annonceplatform, og de fleste solide opsætninger bruger mindst to af dem samtidig.

Browser-tagsServer-container (sGTM)Direkte API
Hvor data opstårBrowserenBrowseren, men sendes til jeres server førstJeres backend, CRM eller ERP
EksemplerMeta Pixel, Google-tag, TikTok PixelGoogle Tag Manager server-container på Cloud Run eller StapeMeta Conversions API, Google Data Manager API, GA4 Measurement Protocol
Hvad I kan styreNæsten intet efter scriptet er loadetAlt, der sendes videre: felter, hashing, routingAlt, også hvornår eventet sendes
Rammer blokering og browserbegrænsningerJa, fuldtDelvist, browseren skal stadig nå jeres endpointNej, for selve afsendelsen
Kender brugerens kontekst (cookies, klik-ID, user agent)JaJa, via den indkommende requestKun det, I selv har gemt på ordren
Typisk ejerMarketingMarketing og udvikler sammenUdvikler

En server-container er et mellemled: browseren sender én strøm af events til jeres eget domæne, og containeren omsætter dem til kald til GA4, Google Ads, Meta og andre. Ved direkte API sender jeres backend selv eventet, typisk når ordren er betalt.

GA4 Measurement Protocol skiller sig ud. Google skriver direkte, at den er beregnet til at supplere den automatiske indsamling gennem gtag, Tag Manager eller Firebase og ikke til at erstatte den, og at man skal bruge tagging for at bruge protokollen. Den er altså ikke en genvej til en GA4 uden script på siden.

First-party-domæne og cookies i Safari

Når I sætter en server-container op, vælger I, hvor den skal svare. Google beskriver tre muligheder: standarddomænet hos hosting-udbyderen, et subdomæne som metrics.shop.dk, eller samme origin som shoppen, for eksempel shop.dk/metrics. Google anbefaler samme origin, og standarddomænet giver kun adgang til cookies sat med JavaScript.

Valget betyder mest i Safari, og reglerne er værd at have præcist:

  • Cookies sat med JavaScript og alt andet lager, scripts kan skrive i, slettes efter syv dage uden brugerinteraktion med sitet, ifølge WebKits egen beskrivelse af Intelligent Tracking Prevention.
  • Lander brugeren via et link med klik-ID fra et domæne, Safari har klassificeret som tracker, begrænses JavaScript-cookies på landingssiden til 24 timer.
  • Cookies sat af serveren i et HTTP-svar får normalt den levetid, I beder om. Men Safari registrerer tredjeparts CNAME-cloaking og tredjeparts IP-adresse-cloaking og begrænser i så fald cookies fra svaret til syv dage.

Et subdomæne med en CNAME til jeres hosting-udbyder ligner first-party i DNS, men det kører på en anden IP-adresse end shoppen. Ifølge gennemgangen af WebKit-ændringen fra Safari 16.4 hos bl.a. Stape sammenligner Safari den første halvdel af IP-adressen for serveren, der sætter cookien, med den side, brugeren er på. Er de forskellige, er cookien begrænset til syv dage, uanset hvad Set-Cookie siger.

Derfor er samme origin bag shoppens egen CDN eller load balancer den robuste løsning. Subdomænet er nemmere at sætte op og er fint, hvis I accepterer syv dage i Safari. Kører I sitet bag Cloudflare, kan I route en sti som /metrics til containeren, så IP-adressen er den samme som resten af sitet.

Safari fjerner desuden kendte tracking-parametre fra links i privat browsing. Et gclid eller fbclid, der aldrig når siden, kan ingen server genskabe.

Er det kun Google-tagget, I vil have på eget domæne, serverer Google tag gateway for advertisers Googles scripts gennem jeres CDN. Det er ikke en server-container og sender ikke til Meta.

Hosting: Cloud Run, Stape og hvad det koster

En server-container er et Docker-image fra Google, som skal køre et sted. De to almindelige veje er Google Cloud Run og en administreret udbyder som Stape.

Googles egen vejledning til Cloud Run anbefaler mindst to instanser i produktion for at mindske risikoen for datatab ved nedbrud, med autoskalering fra to til ti servere, som skulle kunne klare 35 til 350 requests i sekundet. Hver server kører med 1 vCPU og 0,5 GB hukommelse og koster ifølge Google cirka 45 dollars om måneden. Dertil kommer en separat preview-server til fejlfinding. Mere end 1 vCPU pr. server bliver ikke brugt og forstyrrer autoskaleringen, skriver Google i den manuelle opsætningsguide.

Stape tager sig af drift, opdateringer og custom domain og afregner efter antal requests. Prissiden viste 1. oktober 2026 en gratis plan op til 10.000 requests om måneden, Pro fra 17 dollars for 500.000 requests og Business fra 83 dollars for 5 millioner.

Regnestykket afhænger af, hvor mange events browseren sender til containeren. Hver sidevisning, hver produktvisning og hver læg-i-kurv er en request. Tæl jeres events i GA4 for en måned, og brug det tal som udgangspunkt.

Den reelle omkostning er sjældent hostingen, men opsætning, test og vedligehold, når Meta eller Google ændrer krav.

Deduplikering mellem pixel og Conversions API

Meta anbefaler at køre pixel og Conversions API side om side med de samme events. Det giver redundans, men kun hvis Meta kan se, at to events er det samme køb.

Reglen er enkel. Meta betragter to events som identiske, når de har samme event_name og samme event_id. I pixelen sendes ID’et som eventID i det fjerde argument, i API’et som event_id. Deduplikeringen gælder kun, hvis det andet event modtages inden for 48 timer efter det første.

// Browser: tak-siden eller Shopify web pixel
fbq('track', 'Purchase', { value: 1499.00, currency: 'DKK' }, { eventID: 'ordre_100234' });

// Server: Conversions API, samme navn og samme ID
{ "event_name": "Purchase", "event_id": "ordre_100234", "event_time": 1790000000,
  "action_source": "website", "event_source_url": "https://shop.dk/checkout/tak",
  "user_data": { "em": ["<sha256>"], "client_ip_address": "…", "client_user_agent": "…",
                 "fbp": "fb.1.1790000000000.123456789", "fbc": "fb.1.1790000000000.IwAR…" },
  "custom_data": { "value": 1499.00, "currency": "DKK" } }

Ordrenummeret er det bedste event_id til køb, fordi både browseren og serveren kender det. Til events uden ordre, som læg-i-kurv, skal ID’et genereres i browseren og sendes med til serveren, ellers kan de to sider ikke blive enige.

Der findes en reserveløsning, hvor Meta deduplikerer på fbp eller external_id sammen med samme event_name. Meta skriver, at den generelt kun virker, når browser-eventet kommer først og server-eventet bagefter. Med webhooks kommer serveren ofte først, så den løsning holder ikke for køb.

Og så detaljerne: Purchase og purchase er to forskellige events, ID’et må ikke få et præfiks kun det ene sted, og en webhook, der leveres to gange, giver en dublet, som I selv skal fange.

Event Match Quality og de parametre der flytter den

Event Match Quality er Metas score fra 0 til 10 for, hvor godt kundeoplysningerne på et server-event kan matches til en Meta-konto. Den ses pr. event i Events Manager.

Meta skelner skarpt mellem felter, der skal hashes, og felter, der ikke må:

FeltHash med SHA-256Bemærkning
em (e-mail)JaTrim mellemrum, små bogstaver før hashing
ph (telefon)JaKun cifre, med landekode, fx 45 foran danske numre
fn, ln, ct, zp, countryJaNormaliseres efter Metas regler
external_idAnbefalesJeres eget kunde-ID, det samme i pixel og API
client_ip_addressNejFra den oprindelige request, ikke serverens egen IP
client_user_agentNejPåkrævet for website-events
fbpNejVærdien af cookien _fbp
fbcNejVærdien af _fbc, eller bygget ud fra fbclid

fbc har formatet fb.1.<tidspunkt i ms>.<fbclid>. Mangler cookien, men står fbclid i URL’en, kan I bygge værdien selv på serveren. Klik-ID’et må ikke ændres, heller ikke store og små bogstaver. Meta anbefaler at gemme den formaterede værdi i 90 dage og at opdatere fbp og fbc løbende, fordi cookies skifter.

For et webhook-baseret køb betyder det, at fbp, fbc, IP og user agent skal fanges i browseren under checkout og gemmes på ordren. Webhooken kommer fra platformens server og kender ikke brugerens browser. Det er den hyppigste grund til lav match-kvalitet på server-events: e-mailen er med, men alt andet mangler.

event_source_url og action_source: website er også påkrævede for website-events. Meta anbefaler at sende events, så snart de sker, og helst inden for en time.

Enhanced Conversions og Googles server-vej

Google har sin egen version af samme idé. Enhanced conversions for web supplerer det eksisterende konverteringstag med førstepartsdata som e-mail, hashet med SHA-256, som Google matcher mod loggede ind Google-konti. Det kan sættes op med Google-tagget, i Google Tag Manager eller via API. Google advarer om, at data sendt på en anden måde end den, der er valgt i Google Ads, muligvis ikke bliver behandlet. Vælg én metode og hold fast i den.

Den rene server-vej er at uploade konverteringer fra backend. Google Ads API tager imod konverteringer med gclid, gbraid eller wbraid og hashede brugeroplysninger, og Google skriver, at man bør sende alle relevante data, også når der ikke er et GCLID. To ting er værd at vide i 2026. Google Ads understøtter ikke IP-matching for brugere i EØS, Storbritannien og Schweiz. Og fra 15. juni 2026 fejler upload via Google Ads API for udviklertokens, der ikke tidligere har sendt offline-konverteringer. Google henviser til Data Manager API, som også kan sende til GA4.

Deduplikering i Google Ads sker på transaktions-ID inden for samme konverteringshandling. Kommer der to konverteringer med samme ID, tælles den anden ikke. Det samme ID bruges senere til at trække konverteringer tilbage eller rette værdien ved returvarer.

Hvordan Consent Mode påvirker, hvad Google modtager, er et emne for sig. Det har vi skrevet om i Consent Mode v2: avanceret eller basis, så det springer vi over her.

Ordren skal komme fra webhooken, ikke fra tak-siden

Tak-siden er det mest skrøbelige sted at måle et køb. Brugeren skal nå tilbage fra betalingsudbyderen, siden skal loade, scriptet skal køre, og intet må blokere det. Shopify skriver det ligeud om eventet checkout_completed: det udløses typisk på tak-siden, og hvis siden ikke loader, bliver eventet slet ikke registreret. Har shoppen et upsell efter køb, udløses eventet på upsell-siden og ikke igen på tak-siden.

På Shopify er de gamle scripts på ordrestatussiden desuden lukket. Shopify slukkede dem for Plus-butikker i august 2025 og for resten 26. august 2026. Måling på tak-siden går nu gennem web pixels og customer events.

Ordre-webhooken er mere robust. Shopify sender orders/paid og refunds/create, når betalingen og refusionen er registreret i shoppen. I PrestaShop kan et modul hægte sig på actionValidateOrder, der får ordre, kurv, kunde, valuta og status, eller på actionOrderStatusPostUpdate, der kører ved hver statusændring og derfor kan vente til ordren faktisk er betalt.

Webhooks har deres egne regler. Shopify garanterer ikke rækkefølgen, levering kan gå tabt, og den samme levering kan komme igen. Brug headeren X-Shopify-Webhook-Id til at frasortere gentagne leveringer, og kør et afstemningsjob, der jævnligt henter ordrerne og sender det, der mangler. Det er Shopifys egen anbefaling.

Modellen vi anbefaler til køb:

  1. Browseren sender Purchase med ordrenummeret som event-ID, når tak-siden loader.
  2. Under checkout gemmes fbp, fbc, gclid, IP, user agent og samtykkestatus på ordren.
  3. Webhooken eller ordre-hooket sender samme event med samme ID og de gemte værdier.
  4. Platformene deduplikerer. Loadede tak-siden ikke, står server-eventet alene.

Webhooken ved, at ordren findes. Browseren ved, hvem der klikkede. Kombinationen giver både dækning og match.

Samtykke: server-side flytter ikke kravet

EDPB, de europæiske datatilsyns fællesorgan, vedtog i oktober 2024 den endelige udgave af retningslinjer 2/2023 om rækkevidden af ePrivacy-direktivets artikel 5, stk. 3. Pointen er, at reglen ikke kun handler om cookies. Når JavaScript instruerer browseren i at sende oplysninger til et endpoint, er det adgang til information i brugerens udstyr, og tracking-pixels og tracking-links er nævnt eksplicit. Det gælder også, når endpointet er jeres eget subdomæne.

I Danmark fører Digitaliseringsstyrelsen tilsyn med cookiebekendtgørelsen, og Datatilsynet med databeskyttelsesreglerne. Deres fælles vejledning fra maj 2025 siger, at der skal indhentes samtykke til for eksempel besøgsstatistik og personaliserede annoncer, og at undtagelsen kun dækker teknologier, der er teknisk nødvendige for, at tjenesten virker. Vejledningen skriver også, at interesseafvejningsreglen normalt ikke kan bruges som grundlag for målrettet markedsføring baseret på adfærd på tværs af tjenester. Der er samtykke det korrekte grundlag.

Vi er ikke jurister, og den konkrete vurdering hører hjemme hos jeres rådgiver, men konsekvensen er til at følge:

  • Et browser-event til jeres server-container, som videresendes til Meta eller Google Ads, kræver samme samtykke, som hvis pixelen havde sendt det direkte.
  • Et køb sendt fra webhooken med hashet e-mail til Meta er en videregivelse af personoplysninger til markedsføring. At der ikke er en browser involveret i selve afsendelsen, ændrer ikke på, at det kræver et behandlingsgrundlag, og vejledningen peger på samtykke.
  • Feltet opt_out i Conversions API betyder, at Meta kun bruger eventet til attribution og ikke til optimering. Det er en teknisk indstilling og ikke en erstatning for samtykke.

Den praktiske regel er derfor, at samtykkestatus fra checkout gemmes på ordren, og at serveren tjekker den, før noget sendes videre. Google-tags i en server-container er consent-aware og læser samtykket fra den indkommende request. Google skriver, at man kun behøver opsætte Consent Mode i web-containeren. For Meta, TikTok og andre ikke-Google-tags i containeren er det jeres egen logik, der skal stoppe dem.

Det, server-side reelt giver her, er kontrol: I kan fjerne felter, før data forlader jeres server. Det er et privatlivsargument, ikke en undtagelse fra kravet.

Sådan tester I opsætningen

Hver platform har sit eget testværktøj, og I skal bruge dem alle, fordi de tester forskellige led.

GTM preview for server-containeren. Klik Preview i server-containeren. Til venstre ses de indkommende requests, som skal svare til browserens netværksfane, og de udgående requests viser, hvad containeren sendte til hver platform, og hvad den svarede. En 200-status fra containeren betyder ikke, at Meta accepterede eventet. Det står i svaret på den udgående request.

Meta Test Events. Events Manager genererer en testkode, som sendes med som test_event_code på server-events. Så ses de live i Test Events sammen med browser-events, og det fremgår, om de er deduplikeret. Fjern koden igen, før I går i produktion.

GA4 DebugView. Browser-events ses i DebugView, når debug-tilstand er slået til. Measurement Protocol-events kommer kun med, hvis I sætter debug_mode og engagement_time_msec i parametrene. Til at validere selve payloaden findes valideringsserveren på /debug/mp/collect, som svarer med fejl og aldrig skriver til rapporterne.

En testplan, der fanger det meste:

  1. Gennemfør et køb med samtykke givet. Tjek at browser og server sender samme event-ID, og at Meta viser eventet som deduplikeret.
  2. Gennemfør et køb med samtykke afvist. Tjek at intet sendes til Meta og Google Ads fra hverken browser eller server.
  3. Luk fanen før tak-siden loader. Tjek at server-eventet kommer alene og tælles én gang.
  4. Lav en refusion. Tjek at den når GA4 som refund og Google Ads som en justering.
  5. Sammenlign en uges ordrer i shoppen med købene i GA4, Google Ads og Meta, ordre for ordre på ID.

Typiske fejl

De fleste af dem opdages først, når nogen sammenligner med ordrerne i shoppen.

  • Dobbelt-tælling. Pixelen og serveren sender forskellige ID’er, eller kun den ene sender ID. Ser ROAS pludselig markant bedre ud dagen efter lanceringen, er det første sted at kigge, om deduplikeringen virker.
  • Tomt transaktions-ID. GA4 deduplikerer alle køb med transaction_id="" som ét køb. En fejl i datalayeren kan dermed reducere en hel måneds køb til nogle få.
  • Manglende valuta. Uden currency kan værdien ikke bruges. Send altid ISO-koden, DKK, og send beløbet som tal og ikke som tekst med tusindtalsseparator.
  • Refunderinger, der aldrig sendes. Google Ads kan trække konverteringer tilbage eller rette værdien, men kun for konverteringer med transaktions-ID. GA4 har et refund-event. Sender I ingen af delene, optimerer budstrategien på ordrer, der kom retur.
  • Testordrer i produktion. Interne testkøb sendes med til platformene. Markér testordrer i shoppen, og lad serveren filtrere dem fra på e-mail, kunde-ID eller betalingsmetode.
  • Serverens IP i stedet for brugerens. En webhook-handler, der sætter sin egen IP som client_ip_address, får alle ordrer til at se ud som om de kommer fra samme datacenter.
  • For gamle events. Et afstemningsjob, der sender ordrer efter otte dage, får hele batchen afvist af Meta. GA4 Measurement Protocol accepterer højst 72 timers tilbagedatering.

Hvornår det kan betale sig

Gevinsten afhænger af, hvor meget I bruger på annoncer, og hvor dårlig jeres nuværende dækning er.

SituationAnbefalingHvorfor
Shopify, få kanaler, lavt annoncebudgetBrug platformens egne apps til Meta og Google førstShopifys Meta-kanal understøtter Conversions API uden egen server
Annoncebudget i Meta af betydning, lav match-kvalitet på købConversions API fra webhook med gemte browser-værdierKøb er det event, der flytter optimeringen mest
Flere platforme: GA4, Google Ads, Meta, TikTokServer-container på samme originÉn strøm fra browseren, kontrol over hvad der sendes til hvem
Headless eller egen checkoutServer-events fra backend, browser-events med samme IDI har allerede ordren på serveren
Lang købsrejse, B2B, leads der lukkes offlineDirekte API fra CRM eller ERPKonverteringen sker ikke på sitet
Primært GA4-statistik, ingen betydelig annonceringLad væreGevinsten er lille, og samtykke er stadig flaskehalsen
Ingen ejer til vedligeholdLad være, eller køb det som driftEn ubemandet container fejler stille

Før I bygger noget, så tag tre tal: antal ordrer i shoppen sidste måned, antal køb i GA4 og antal køb i Meta og Google Ads. Er forskellen lille, er det ikke tracking, der er jeres problem. Er den stor, så find ud af, om det skyldes samtykke, blokering eller fejl i opsætningen, for kun de to sidste kan server-side gøre noget ved.

Den analyse er der, vi starter i tracking og konverteringer, og selve opbygningen i shoppen hører under analytics og tracking. I er velkomne til at skrive til os med jeres tre tal.

Kilder

Kilderne er tjekket 1. oktober 2026. Platformene ændrer deres krav løbende, så tjek dokumentationen, før I bygger.

EmneWeb

Relaterede artikler om Web

Læs også

01 Kritisk sikkerhedshul i PHP: opdatér til 8.4.27, 8.3.36, 8.2.35 eller 8.5.12 nu Sikkerhed · 6 min 02 PrestaShop og det kritiske PHP-hul: mange shops kører på en PHP uden rettelse Sikkerhed · 6 min 03 Facebook hacket: hvad gør jeg med virksomhedens side og Instagram? Sikkerhed · 18 min