# Spec 07: Dansk AIO-trigger-måling — "Vi målte det"

**Status:** Plan udarbejdet 2026-08-03; scripts bygget og smoke-testet samme
dag (10 keywords, derefter slettet — bølge 1 skal være én sammenhængende
kørsel). Afsnit 1-5 er metodeprotokol og låses FØR første måling — tallene
må ikke forme metoden. Afsnit 6-8 er build-spec.

**Protokol-ændringer under byggeriet (alle FØR lås og første måling):**
1. *Suppleringskilde:* Danske spørgsmåls-/sammenlignings-keywords ligger
   typisk under 50 søgninger/md og findes ikke i keyword_ideas. Underfyldte
   celler suppleres derfor fra Labs' keyword_suggestions (long-tail der
   indeholder seedet) med volumengulv ≥ 10.
2. *Filplaceringer:* `/data` er gitignoret, så den låste keyword-liste bor i
   `docs/benchmarks/aio-trigger/sample.json` (committes). Rå bølgedata
   forbliver lokalt i `data/aio-trigger/`.
3. *Én lib-ændring alligevel:* §4's stub-logning kræver, at `fetchLiveSerp`
   eksponerer stubbe. Nyt ikke-brydende returfelt `aiOverviewAsyncStub` i
   `lib/serp-provider.js`; alle andre kaldere ignorerer det.
4. *Manuelt gennemsyn i tre runder* (2026-08-03, dokumenteret i
   `docs/benchmarks/aio-trigger/ekskluderede.json` — 279 keywords med grund):
   Labs' relaterings-net er bredt nok til at lægge "bedste frisør københavn"
   under rejser og "hvad koster et pas" under b2b-software. Eksklusioner kan
   være globale eller scoped til én branche (dagligvare-tilbud er støj under
   e-handel, men legitime under mad-livsstil).
5. *Topikalitets-filter:* Runde 1-2 fjernede 271 keywords, men hver refill
   trak nyt junk op af de emne-mæssigt bundløse ideas-puljer. Regel: et
   keyword skal indeholde mindst én af branchens seed-stammer som substring.
   Konsekvensen er bevidst og skal stå i artiklens metodeafsnit: cellerne
   måler definerede emneklynger (vitaminer, influenza, varmepumper,
   rejseforsikring, ...), ikke "hele branchen".
6. *b2b-software bygges kun fra keyword_suggestions* — ideas-puljen for
   branchen var ~95 % branche-fremmed, fordi danske B2B-søgninger er for
   små til at optræde i et volumensorteret ideas-svar.
7. *Fri-puljen (40 høj-volumen keywords uden intent-markører) er droppet:*
   den selekterer pr. konstruktion for navigation, nyheder og sport og måler
   dermed noget andet end de fire intent-former.
8. *Nær-dublet-kollaps:* varianter der kun adskiller sig ved bindestreg,
   ordstilling eller småord ("hvad er crm system" / "hvad er et crm-system")
   kollapses; varianten med højest volumen beholdes.
9. *Endeligt sample: 850 keywords.* Ni celler er underfyldte og accepteres
   med deres mindre n (mindst: uddannelse/sammenligning 8,
   uddannelse/transaktionel 11, mad-livsstil/sammenligning 13,
   b2b-software/spoergsmaal 15, b2b-software/sammenligning 16) — det er
   reelle træk ved det danske søgemarked, ikke huller i indsamlingen.

**Formålet:** Danmarks første offentliggjorte måling af, hvor ofte Google
viser AI Overviews på danske søgninger. Bloggens AIO-artikel indrømmer selv
hullet ("Der findes ingen pålidelig dansk AIO-trigger-rate") — denne måling
lukker det. Leverer samtidig rådata til en opfølger: hvilke domæner citeres
i danske AI Overviews (den danske pendant til Ahrefs' Reddit/Wikipedia-tal).

**Hvorfor os:** SERP-pipelinen findes allerede (`lib/serp-provider.js`),
og vi kender den fejl, der ville have ødelagt målingen: uden
`load_async_ai_overview` melder DataForSEO "intet AI Overview" på SERP'er,
der har ét (asynkron stub — verificeret 3/8, se kommentar i serp-provider og
docs/study/README.md om `aio_present`-undertællingen). Et studie, der ikke
kender det flag, undertæller systematisk. Det bliver et metodeafsnit i
artiklen: forskellen på vores tal med og uden flaget er i sig selv et fund.

---

## 1. Forskningsspørgsmål (låses før måling)

- **F1 (primær):** Hvor stor en andel af danske søgninger udløser et AI
  Overview? Rapporteret uvægtet og volumenvægtet.
- **F2:** Hvordan varierer andelen med intent-form (spørgsmål, sammenligning,
  enkeltord, transaktionel)? Forventning fra USA-data: 85,9 % / 95,4 % /
  27,3 % (Seer, apr. 2026) — replikeres mønstret på dansk?
- **F3:** Hvordan varierer andelen på tværs af brancher? USA-benchmark:
  sundhed 88 %, uddannelse 83 %, e-handel ~4 % (BrightEdge, feb. 2026).
- **F4:** Hvor stabil er trigger-raten uge til uge (tre bølger)?
- **F5 (bonus, egen artikel):** Hvilke domæner citeres oftest i danske AI
  Overviews, og hvor mange kilder har et typisk dansk AIO?
- **F6 (bonus):** Desktop vs mobil — samme keywords, én bølge på begge.

**Ærlighed:** Alle tal publiceres uanset udfald, også hvis den danske
trigger-rate er lav nok til at underminere GEO-salgsargumentet. Det er
pointen med at måle frem for at gengive.

## 2. Keyword-sample (n = 1.000)

Stratificeret 8 brancher × 4 intent-former = 32 celler à ~30 keywords,
suppleret til 1.000 med en fri pulje af høj-volumen danske keywords.

**Brancher (8):** sundhed · finans/forsikring · rejser · e-handel/produkter ·
B2B/software · uddannelse · bolig/håndværk · mad/livsstil.

**Intent-former (4), regelbaseret klassifikation:**
- *Spørgsmål:* begynder med hv-ord eller "kan/skal/er ..."
- *Sammenligning:* indeholder "bedste", "vs", "sammenligning", "anmeldelse",
  "alternativ til"
- *Enkeltord/kort:* 1-2 ord, ingen intent-markører
- *Transaktionel:* indeholder "køb", "pris", "tilbud", "billig", "rabat"

**Kilde:** DataForSEO Labs (keyword ideas + søgevolumen, location Danmark,
sprog dansk). Samme leverandør som SERP-målingen — ingen nye afhængigheder.
Filter: volumen ≥ 50/md (dødvande-keywords siger intet om noget). Volumen
gemmes pr. keyword, så F1 kan vægtes og rapporteres i volumenbånd
(50-500, 500-5.000, >5.000).

**Publiceres:** Hele keyword-listen offentliggøres sammen med artiklen.
Reproducerbarhed er brandet — og gør tallet citerbart for presse og
konkurrenter (som dermed linker).

## 3. Måling

- `fetchLiveSerp` med **`loadAsyncAiOverview: true`** (ufravigeligt, jf. ovenfor),
  depth 20, location Danmark, sprog dansk.
- **Tre bølger med 7 dages mellemrum**, samme keywords, samme ugedag og
  tidsrum. Bølge 1 kørtes ved dagtid (besluttet ved lås 2026-08-05), så
  dagtid ER vinduet for alle tre bølger. F4 kræver mindst tre punkter for
  at skelne støj fra niveau.
- **Protokolafvigelse (dokumenteret 2026-08-13):** Bølge 2 kørte 13. august
  i stedet for 12. august — den schedulerede kørsel startede til tiden
  12/8 kl. 14:30, men strandede på en manglende tool-godkendelse og målte
  intet. Bølge 2 kørtes derfor dagen efter i SAMME tidsvindue (kl. 14:30).
  Intervallerne blev 8 + 7 dage (5/8 → 13/8 → 20/8) i stedet for 7 + 7.
  Ingen målinger gik tabt eller blev delvist gennemført 12/8.
- **Protokolafvigelse (dokumenteret 2026-08-21):** Bølge 3 kørte 21. august
  kl. 15:42 i stedet for 20. august kl. 14:30 — den schedulerede opgave lå
  i et forældet session-register, som scheduleren ikke længere læste, og
  blev derfor aldrig startet. Kørslen blev udført manuelt dagen efter og
  gennemført i én sammenhængende kørsel (850/850, 0 fejl, 0 stubbe). De
  faktiske intervaller blev 8 + 8 dage (5/8 → 13/8 → 21/8). Begge
  afvigelser er scheduleringsfejl hos os og uden berøring med selve
  målemetoden; de nævnes også i artiklens metodeafsnit.
- **Bølge 2 køres dobbelt:** desktop + mobil (F6). Bølge 1 og 3 kun desktop.
- AIO-tilstedeværelse defineres som: `aiOverview != null` (dvs. tekst eller
  referencer fundet efter async-load). Stub-tilfælde logges separat, så
  med/uden-flag-forskellen kan rapporteres (metodefundet).

**Kendte begrænsninger (skrives ind i artiklen, ikke i en fodnote):**
- DataForSEO leverer upersonaliserede SERP'er. Rigtige brugeres logged-in
  resultater kan afvige — tallet er et "neutralt udgangspunkt", ikke en
  brugerobservation som Pew/Gemius.
- Øjebliksbillede over tre uger, ikke en tidsserie. Dateres.
- Volumen ≥ 50-filteret betyder, at long-tail under 50/md ikke er dækket.

## 4. Data der gemmes

Rå SERP-svar som JSONL pr. bølge (reproducerbarhed + genanalyse til F5-
artiklen uden nye kald). Pr. keyword pr. bølge:

```
keyword, branche, intentForm, volumen, device, bølge, fetchedAt,
aioPresent, aioAsyncStub, aioTextLength, aioReferenceCount,
aioReferenceDomains[], paaCount, organicTop3Domains[], costUsd
```

Placering: `data/aio-trigger/` (JSONL, gitignoreret hvis > nogle MB) +
aggregeret resultat i `docs/benchmarks/aio-trigger-dk-<dato>.json` (committes).

## 5. Analyse og artiklens tal

- F1: andel med 95 %-CI (Wilson), uvægtet + volumenvægtet. Overall ±3 pp.
- F2/F3: andel pr. celle med CI. 30 keywords/celle giver ±13-18 pp — grovkornet,
  men nok til at skelne "sundhed ~80 %" fra "e-handel ~5 %". Rapporteres som
  intervaller, ikke punktestimater.
- F4: andel keywords der skifter AIO-status mellem bølger.
- F5: domæne-optælling på tværs af alle references; top-20-tabel.
- Sammenligning med USA-tal sker eksplicit som "mønster-replikation", aldrig
  som direkte tal-sammenligning (andre metoder, andre keyword-sæt).

## 6. Omkostning og tidsplan

| Post | Beregning | Ca. |
|---|---|---|
| Keyword-sampling (Labs) | ~40 kald | ~$1 |
| Bølge 1 + 3 (desktop) | 2 × 1.000 × ~$0,0055 | ~$11 |
| Bølge 2 (desktop + mobil) | 2 × 1.000 × ~$0,0055 | ~$11 |
| I alt | | **~$23 ≈ 160 kr.** |

Tidsplan: uge 1 sampling + bølge 1 · uge 2 bølge 2 · uge 3 bølge 3 +
analyse + artikel. Artiklen kan skrives i uge 2 med bølge 1-tal og
opdateres — men publiceres først, når alle tre bølger er i hus (F4 er
en del af troværdigheden).

## 7. Build-spec (tre scripts, genbruger eksisterende lib)

1. `scripts/aio-sample-keywords.mjs` — bygger samplet via DataForSEO Labs
   (keyword_ideas + keyword_suggestions til underfyldte celler),
   klassificerer intent-form regelbaseret, skriver
   `docs/benchmarks/aio-trigger/sample.json` med `locked: false`.
   Manuel gennemsyn FØR bølge 1 (fjern misklassifikationer — især
   branche-støj fra Labs' brede relaterings-net; dokumentér ændringer),
   sæt derefter `locked: true`. aio-run-wave.mjs nægter at køre en fuld
   bølge, mens `locked` er false (smoke-test med `--limit` er undtaget).
2. `scripts/aio-run-wave.mjs --wave=N [--device=mobile]` — kører en bølge
   mod `fetchLiveSerp`, resumérbar (springer allerede målte over), skriver
   JSONL + logger faktisk cost fra DataForSEO-svaret.
3. `scripts/aio-report.mjs` — aggregerer alle bølger til
   `docs/benchmarks/aio-trigger-dk-<dato>.json` + markdown-tabeller klar
   til artiklen.

Ingen Supabase-afhængighed — filbaseret, så målingen kan gentages om et år
uden migrations-bagage. Ingen ændringer i `lib/`.

## 8. Risici

- **Google ændrer SERP-layout midt i målingen** → bølge-design opdager det
  (F4 eksploderer); i så fald rapporteres bølgerne separat.
- **DataForSEO-flaget ændrer adfærd** → stub-logningen (aioAsyncStub) gør
  det synligt i data.
- **Trigger-raten er "kedelig"** (fx ensartet lav) → stadig publicerbart;
  "GEO er ikke din flaskehals endnu i branche X" er et ærligt og brugbart
  budskab, der matcher artiklens eksisterende råd om at tjekke egne queries.
- **Sample-bias:** Labs-keywords ≠ danskernes faktiske søgestrøm. Adresseres
  åbent: vi måler et stratificeret keyword-univers, ikke befolkningens
  søgninger (det kan kun clickstream-data som Gemius').
