← ThinkAloud · API-nøgler (profil) · English · Dansk

ThinkAloud API

ThinkAloud er API-first: UI'et bruger præcis de samme endpoints som beskrevet her. Tiltænkt server-til-server-integration (fx web-tracking.eu som add-on: måling finder siden med høj exit-rate + søgeordet — ThinkAloud simulerer *hvorfor* de smutter). Ingen CORS er åbnet med vilje: kald fra jeres backend, ikke fra browseren.

Base-URL: https://thinkaloud.activero.net (pilot; én maskine — kør én test ad gangen).

Auth — to måder:

  1. API-nøgle (anbefalet, Bureau-plan): Authorization: Bearer ta_... — oprettes på /app/profile → "API keys" (vises kun én gang; op til 10 aktive, tilbagekald enkeltvis). Nøglen giver konto-kontekst: kørsler tilskrives kontoen, credits trækkes, og GET /api/runs viser kun kontoens egne kørsler.
  2. Adgangskode (pilot/intern integration): X-Access-Code: <koden>. Serverens THINKALOUD_ACCESS_CODE er en komma-separeret liste — giv hver integration sin egen kode, så den kan tilbagekaldes uafhængigt. Uden konto-kontekst (ingen kreditering/ejerskab).

Læse-endpoints kræver ét af: signeret ?t=-token (fra status/list-svar), ejerskab, eller adgangskode. 401-detail er altid "access_denied".

Start en kørsel

POST /api/runs
Content-Type: application/json
X-Access-Code: <koden>

{
  "url": "https://example.com/side",
  "goal": "Forstå hvad siden tilbyder, og om det er relevant for dig.",
  "contentType": "dissemination",          // conversion | dissemination | reference
  "mode": "thinkaloud",                    // thinkaloud (UX) | e2e (funktionalitetstest)
  "lang": "da",                            // output-sprog for personaer + rapport (da | en)
  "model": "glm",                          // komma-sep.: glm (default, billigst),gemini,claude,llama,mistral (EU),grok (premium)
  "steps": 8,                              // trin pr. persona (e2e: brug 15)
  "synthesisModel": "grok",                // valgfri premium-pen: SKRIVER anbefalinger/syntese
                                           //   (personaerne beholder deres egen model).
                                           //   Udførlig (comprehensive) bruger grok automatisk.
  "personas": [
    {"id": "sogende", "label": "Søgende med konkret intention",
     "role": "Du googlede '<søgeord fra GSC>' og landede her. Du er utålmodig...",
     "style": "maalrettet"}                // valgfri: metodisk | rodet | maalrettet
  ]
}
→ {"run_id": "20260722-091653-f5fc0f"}

Til GSC-integrationen: byg personaens role af det rigtige søgeord ("Du googlede X …") i stedet for en opfundet profil — det er hele pointen.

Gatede sider (login/staging)

Tre valgfrie felter i samme POST /api/runs-body åbner sider bag en gate — KUN testkonti (personaerne klikker rigtigt rundt, inkl. destruktive knapper):

{
  "auth": {"user": "test", "password": "..."},        // HTTP Basic (staging-gates)
  "headers": {"X-Api-Key": "..."},                     // vilkårlige headers, fx nøgle-gatet site
  "storage_state": "{\"cookies\": [...]}"              // session-injektion: log selv ind, eksportér
}                                                      //   sessionen (Playwright storageState ELLER
                                                       //   Cookie-Editor-array) → SSO/2FA uden password

Sikkerhed: secrets gives kun til browser-harnessen via ephemere env-variabler — config.json på serveren beholder redigerede pladsholdere (***), og de optræder aldrig i rapport/log. Form-login med testkonto virker også uden felterne: skriv kontoen ind i goal ("log ind som test@… / kode …"), så udfører personaen selv login-formularen.

Poll status

GET /api/runs/{run_id}
→ {"run_id": ..., "status": "running|done|error", "log": "<tail>",
   "progress": {"phase": "reading", "pct": 42, "text": "Persona · Model", ...}}

Poll hvert 10-15 s. En kørsel tager typisk 1-5 min (flere personaer/modeller = længere; pr.-side-forankring koster ~25 s pr. ny unik side personaerne besøger).

Hent resultat

GET /api/runs/{run_id}/results          ← maskinlæsbart (integration)
GET /api/runs/{run_id}/report           ← HTML-rapport (menneske; deling: linket er åbent)
GET /api/runs/{run_id}/report.pdf       ← PDF

/results (kun ved status: "done"):

{
  "run_id": "...", "status": "done",
  "url": "...", "contentType": "...", "goal": "...", "mode": "thinkaloud", "lang": "da",
  "firstGlancePriming": true,            // personaernes første indtryk var saliency-forankret
  "modelsUsed": ["Gemini-2.5"],
  "personas": [{"label": "...", "model": "Gemini-2.5", "endedBy": "done"}],
  "outcomes":  [ /* e2e-mode: {label, model, succeeded, endedBy, steps, blocker, url, step} */ ],
  "issues":    [{"title": "...", "field": "tryghed|mening|kan|besvaer|defekt",
                 "summary": "...", "nPersonas": 2, "avgSev": 3.5, "models": ["Gemini-2.5"],
                 "pts": [{"label": "...", "model": "...", "url": "...", "what": "...",
                          "severity": 4, "step": 3}]}],
  "positives": [ /* samme form, severity 0 */ ],
  "attention": {"model": "deepgaze-iie", "on_action_total": 0.21, "off_action": 0.79,
                "elements": [{"name": "...", "kind": "handling|overskrift|billede",
                              "share": 0.17, "primary": true}]}
}

Tolkning: issues er sorteret værst-først (flest personaer → flest modeller → højest snit- severity). nPersonas >= 2 = konvergent. Alt er prædiktion, ikke måling — mærk det sådan i jeres UI. Valideringssløjfen: sammenlign prædikteret friktion med den faktiske exit-rate.

Øvrige endpoints

POST /api/panel              {brief|candidates, ...}  → fokusgruppe (synkron, 1-3 min; ~25 credits).
                                                       model default = "claude,glm": varianstest
                                                       2026-08-24 viste at ét-models-paneler kan
                                                       flippe vinderen mellem kørsler — to modeller
                                                       gav samme dom i 3/3 genkørsler
POST /api/suggest-personas   {url, goal?, lang?}     → foreslå personaer ud fra siden (gated)
GET  /sample                                          → statisk eksempel-rapport (åben)
GET  /api/defaults?lang=en                            → default-personaer + {"gated": true}
GET  /api/keys · POST /api/keys · DELETE /api/keys/{id}  → API-nøgle-administration
                                                       (kræver login-session, IKKE nøgle/kode)
GET  /api/auth/me                                     → konto + credit-saldo (virker m. Bearer)

MCP-server

npm-pakken thinkaloud-mcp eksponerer det hele som værktøjer i Claude Desktop/Code m.fl. — thinkaloud_start_test, thinkaloud_test_status, thinkaloud_test_results, thinkaloud_list_tests, thinkaloud_focus_group, thinkaloud_suggest_personas, thinkaloud_account. Én linje i Claude Code:

claude mcp add thinkaloud -e THINKALOUD_API_KEY=ta_DIN_NOEGLE -- npx -y thinkaloud-mcp

Auth via THINKALOUD_API_KEY (Bearer-nøglen ovenfor). Kildekoden ligger i mcp/ i repoet.