Documentation

How to use Glimt — from the dashboard UI and from the command line.

Overview

Glimt runs simulated users against your website and reports on what they struggled with. Each simulated user is a persona — a profile with distinct patience, trust requirements, and browsing habits. The agent navigates your site autonomously using an AI decision loop, then produces a scored report with friction points and recommendations.

You can trigger test runs from the dashboard UI or programmatically via the REST API using an API key.

Using the UI

Running a test

Go to New Test in the sidebar. Fill in:

  • Website URL — the page you want to test. Must be publicly reachable.
  • User Goal — what the simulated users are trying to accomplish, e.g. “Find pricing and sign up for a free trial”. At least 5 characters.
  • Simulated Users — pick one or more personas. You can add up to 10, and the same persona can appear multiple times.

Click Run test. The run is queued immediately and you are redirected to the run status page, which auto-refreshes until the run completes.

Personas

Each persona simulates a different type of user. They differ in patience, trust requirements, price sensitivity, comprehension level, and device type. See the persona reference below for details.

Testing authenticated pages

To test pages that require a login, go to Saved Logins and click Record login. Enter a name and the login URL. A controlled browser will open — log in using a dedicated test account, then click I’m logged in →. The session is saved and can be selected when creating test runs.

Always use a dedicated test account, never your personal credentials. The session cookies are stored encrypted in the database.

Reading the report

Once a run completes, open it from the dashboard and click View report. The report shows:

  • Clarity score — how quickly the persona understood what the page offered (0–100).
  • Path efficiency — how directly the persona reached the goal versus the optimal path (0–100).
  • Trust score — how much friction was caused by missing trust signals or pricing (0–100).
  • Friction index — weighted count of friction events (lower is better).
  • Friction issues — clustered problems with severity, affected personas, evidence quotes, and a suggested fix.
  • Session timeline — step-by-step replay of what each persona did, with screenshots and think-aloud commentary.

API

The Glimt REST API lets you trigger runs from CI pipelines, scripts, or any HTTP client. The base URL is your deployment origin, e.g. https://your-app.railway.app.

Authentication

Generate an API key under Settings → API Keys. Pass it in every request as a Bearer token:

Authorization: Bearer glmt_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

API keys are SHA-256 hashed before storage. Keep the raw key safe — it is shown only once.

Runs

Create a run

POST/api/v1/runs
curl -X POST https://your-app.railway.app/api/v1/runs \
  -H "Authorization: Bearer glmt_xxx" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://yoursite.com",
    "goal": "Find pricing and sign up for a free trial",
    "sessions": ["alex", "margaret", "zoe"]
  }'

Request body:

{
  "url":      string,           // required — must be a valid URL
  "goal":     string,           // required — min 5 characters
  "sessions": PersonaPreset[],  // required — 1–10 items, duplicates allowed
  "storageState"?: object|array // optional — Playwright state or Cookie-Editor export
}

Response 201:

{ "testRunId": "clxxxxxxxxxxx" }

List runs

GET/api/v1/runs
curl https://your-app.railway.app/api/v1/runs \
  -H "Authorization: Bearer glmt_xxx"

Response 200:

{
  "runs": [
    {
      "id": "clxxx",
      "url": "https://yoursite.com",
      "goal": "Find pricing...",
      "status": "COMPLETED",       // QUEUED | RUNNING | COMPLETED | FAILED
      "personaPresets": ["alex"],
      "sessionCount": 1,
      "queuedAt": "2026-04-07T10:00:00.000Z",
      "completedAt": "2026-04-07T10:05:00.000Z",
      ...
    }
  ]
}

Get a run

GET/api/v1/runs/:runId

Returns the full run including all sessions and their events. Useful for programmatic report parsing.

curl https://your-app.railway.app/api/v1/runs/clxxx \
  -H "Authorization: Bearer glmt_xxx"

Polling status

GET/api/v1/runs/:runId/status

Lightweight endpoint for polling — returns status and session progress without the full event payload.

curl https://your-app.railway.app/api/v1/runs/clxxx/status \
  -H "Authorization: Bearer glmt_xxx"

Response 200:

{
  "runId": "clxxx",
  "status": "RUNNING",
  "completedSessions": 1,
  "totalSessions": 3,
  "startedAt": "2026-04-07T10:00:05.000Z"
}

Sessions

GET/api/v1/sessions/:sessionId

Returns a single session with all its step events (perception snapshots, actions, scores, think-aloud commentary).

curl https://your-app.railway.app/api/v1/sessions/clxxx \
  -H "Authorization: Bearer glmt_xxx"

Cancelling a run

POST/api/v1/runs/:runId/cancel

Sends a cancel signal to the worker. The current session finishes its step, then the run stops. Only works when status is QUEUED or RUNNING.

curl -X POST https://your-app.railway.app/api/v1/runs/clxxx/cancel \
  -H "Authorization: Bearer glmt_xxx"

Response 200:

{ "ok": true }

CLI / shell scripts

Glimt has no dedicated CLI binary — you use standard tools like curl or httpie with your API key. Here are common patterns.

Run a test and wait for completion

#!/bin/bash
API="https://your-app.railway.app/api/v1"
KEY="glmt_xxx"

# Create run
RUN_ID=$(curl -s -X POST "$API/runs" \
  -H "Authorization: Bearer $KEY" \
  -H "Content-Type: application/json" \
  -d '{"url":"https://yoursite.com","goal":"Find pricing","sessions":["alex","zoe"]}' \
  | jq -r '.testRunId')

echo "Run queued: $RUN_ID"

# Poll until done
while true; do
  STATUS=$(curl -s "$API/runs/$RUN_ID/status" \
    -H "Authorization: Bearer $KEY" | jq -r '.status')
  echo "Status: $STATUS"
  if [[ "$STATUS" == "COMPLETED" || "$STATUS" == "FAILED" ]]; then
    break
  fi
  sleep 10
done

echo "Done — view at https://your-app.railway.app/dashboard/runs/$RUN_ID"

Run in CI (GitHub Actions)

# .github/workflows/ux-test.yml
name: UX test
on:
  push:
    branches: [main]

jobs:
  useglimt:
    runs-on: ubuntu-latest
    steps:
      - name: Create run
        id: create
        run: |
          RUN_ID=$(curl -s -X POST "${{ vars.GLIMT_URL }}/api/v1/runs" \
            -H "Authorization: Bearer ${{ secrets.GLIMT_API_KEY }}" \
            -H "Content-Type: application/json" \
            -d '{"url":"${{ vars.SITE_URL }}","goal":"Sign up","sessions":["alex","margaret"]}' \
            | jq -r '.testRunId')
          echo "run_id=$RUN_ID" >> $GITHUB_OUTPUT

      - name: Wait for completion
        run: |
          for i in $(seq 1 30); do
            STATUS=$(curl -s "${{ vars.GLIMT_URL }}/api/v1/runs/${{ steps.create.outputs.run_id }}/status" \
              -H "Authorization: Bearer ${{ secrets.GLIMT_API_KEY }}" | jq -r '.status')
            echo "Status: $STATUS"
            [[ "$STATUS" == "COMPLETED" || "$STATUS" == "FAILED" ]] && break
            sleep 20
          done

Using Node.js

const BASE = "https://your-app.railway.app/api/v1";
const KEY  = process.env.GLIMT_API_KEY;

const headers = {
  "Authorization": `Bearer ${KEY}`,
  "Content-Type": "application/json",
};

// Create run
const { testRunId } = await fetch(`${BASE}/runs`, {
  method: "POST",
  headers,
  body: JSON.stringify({
    url: "https://yoursite.com",
    goal: "Find pricing and sign up",
    sessions: ["alex", "carlos", "margaret"],
  }),
}).then(r => r.json());

// Poll for completion
let status = "QUEUED";
while (status === "QUEUED" || status === "RUNNING") {
  await new Promise(r => setTimeout(r, 10_000));
  ({ status } = await fetch(`${BASE}/runs/${testRunId}/status`, { headers })
    .then(r => r.json()));
  console.log("Status:", status);
}

console.log("Report:", `https://your-app.railway.app/dashboard/runs/${testRunId}`);

Persona reference

The sessions field accepts an array of preset names. Each entry creates one simulated user session.

PresetProfileDeviceKey traits
alex30-year-old developerDesktopFast, low trust bar, skims content, acts immediately
margaret58-year-old retired teacherDesktopReads carefully, high trust & risk bar, needs clear value
carlos35-year-old non-native speakerDesktopThorough scroller, moderate trust, relies on structure not words
david42-year-old project managerDesktopPractical, average comprehension, goal-driven, moderate patience
zoe22-year-old Gen ZMobileScans only, ultra-low patience, expects instant clarity

You can include the same persona multiple times — each will run as an independent session with a different random seed, producing varied but comparable results.