feat(assistant): one-time disclaimer note + GA4 question-report guide
- Add a subtle disclaimer under the greeting (EN/MK/SI): "automated guide, can make mistakes — check the linked page for official steps." Shown once, not on every message, so it sets expectations without clutter. Persistent footer disclaimer stays. - docs/GA4-ASSISTANT-REPORT.md: step-by-step for registering the custom dimensions and building the "top questions" + "unanswered questions" explorations in GA4 (dev-only doc, not deployed). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
661943bb34
commit
55bc101410
|
|
@ -52,6 +52,13 @@
|
||||||
.msa-open .msa-panel { display: flex; animation: msa-rise .22s ease; }
|
.msa-open .msa-panel { display: flex; animation: msa-rise .22s ease; }
|
||||||
@keyframes msa-rise { from { opacity: 0; transform: translateY(12px); } to { opacity: 1; transform: none; } }
|
@keyframes msa-rise { from { opacity: 0; transform: translateY(12px); } to { opacity: 1; transform: none; } }
|
||||||
|
|
||||||
|
/* one-time disclaimer note under the greeting */
|
||||||
|
.msa-note {
|
||||||
|
font-size: 12px; line-height: 1.45; color: #6a787e;
|
||||||
|
background: #fff8ec; border: 1px solid #f0e3c8; border-radius: 10px;
|
||||||
|
padding: 8px 11px;
|
||||||
|
}
|
||||||
|
|
||||||
/* suggested-question chips */
|
/* suggested-question chips */
|
||||||
.msa-chips { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 4px; }
|
.msa-chips { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 4px; }
|
||||||
.msa-chips-label { width: 100%; font-size: 12.5px; color: #5a6b72; margin-bottom: 2px; }
|
.msa-chips-label { width: 100%; font-size: 12.5px; color: #5a6b72; margin-bottom: 2px; }
|
||||||
|
|
|
||||||
11
assistant.js
11
assistant.js
|
|
@ -15,16 +15,19 @@
|
||||||
var UIS = {
|
var UIS = {
|
||||||
en: { title: "Ask MSOS", open: "Ask MSOS", placeholder: "Ask a question…", send: "Send", close: "Close",
|
en: { title: "Ask MSOS", open: "Ask MSOS", placeholder: "Ask a question…", send: "Send", close: "Close",
|
||||||
greeting: "Hi! 👋 Ask me anything about studying in Slovenia or about MSOS — I'll point you to the right page. You can ask in English, Macedonian or Slovene.",
|
greeting: "Hi! 👋 Ask me anything about studying in Slovenia or about MSOS — I'll point you to the right page. You can ask in English, Macedonian or Slovene.",
|
||||||
|
disc: "I'm an automated guide and can make mistakes — for official steps, deadlines and amounts, always check the linked page.",
|
||||||
found: "Here's what I found:", also: "You might also like:", more: "Read more",
|
found: "Here's what I found:", also: "You might also like:", more: "Read more",
|
||||||
none: "I couldn't find a clear answer for that. These might help:", tryLabel: "Popular questions:",
|
none: "I couldn't find a clear answer for that. These might help:", tryLabel: "Popular questions:",
|
||||||
guideUrl: "/en/student-welcome-guide/", disclaimer: "Answers come straight from this website." },
|
guideUrl: "/en/student-welcome-guide/", disclaimer: "Answers come straight from this website." },
|
||||||
mk: { title: "Прашај MSOS", open: "Прашај MSOS", placeholder: "Постави прашање…", send: "Испрати", close: "Затвори",
|
mk: { title: "Прашај MSOS", open: "Прашај MSOS", placeholder: "Постави прашање…", send: "Испрати", close: "Затвори",
|
||||||
greeting: "Здраво! 👋 Прашај ме било што за студирање во Словенија или за MSOS — ќе те упатам до вистинската страница. Можеш да прашаш на македонски, англиски или словенечки.",
|
greeting: "Здраво! 👋 Прашај ме било што за студирање во Словенија или за MSOS — ќе те упатам до вистинската страница. Можеш да прашаш на македонски, англиски или словенечки.",
|
||||||
|
disc: "Јас сум автоматски водич и можам да згрешам — за официјални чекори, рокови и износи, секогаш провери ја поврзаната страница.",
|
||||||
found: "Еве што најдов:", also: "Можеби ќе ти користи и:", more: "Прочитај повеќе",
|
found: "Еве што најдов:", also: "Можеби ќе ти користи и:", more: "Прочитај повеќе",
|
||||||
none: "Не најдов јасен одговор. Ова можеби ќе помогне:", tryLabel: "Популарни прашања:",
|
none: "Не најдов јасен одговор. Ова можеби ќе помогне:", tryLabel: "Популарни прашања:",
|
||||||
guideUrl: "/mk/student-welcome-guide/", disclaimer: "Одговорите доаѓаат директно од оваа страница." },
|
guideUrl: "/mk/student-welcome-guide/", disclaimer: "Одговорите доаѓаат директно од оваа страница." },
|
||||||
si: { title: "Vprašaj MSOS", open: "Vprašaj MSOS", placeholder: "Zastavi vprašanje…", send: "Pošlji", close: "Zapri",
|
si: { title: "Vprašaj MSOS", open: "Vprašaj MSOS", placeholder: "Zastavi vprašanje…", send: "Pošlji", close: "Zapri",
|
||||||
greeting: "Živjo! 👋 Vprašaj me karkoli o študiju v Sloveniji ali o MSOS — usmeril te bom na pravo stran. Vprašaš lahko v slovenščini, angleščini ali makedonščini.",
|
greeting: "Živjo! 👋 Vprašaj me karkoli o študiju v Sloveniji ali o MSOS — usmeril te bom na pravo stran. Vprašaš lahko v slovenščini, angleščini ali makedonščini.",
|
||||||
|
disc: "Sem samodejni vodnik in se lahko zmotim — za uradne korake, roke in zneske vedno preveri povezano stran.",
|
||||||
found: "Tole sem našel:", also: "Morda te zanima tudi:", more: "Preberi več",
|
found: "Tole sem našel:", also: "Morda te zanima tudi:", more: "Preberi več",
|
||||||
none: "Nisem našel jasnega odgovora. Morda pomaga to:", tryLabel: "Pogosta vprašanja:",
|
none: "Nisem našel jasnega odgovora. Morda pomaga to:", tryLabel: "Pogosta vprašanja:",
|
||||||
guideUrl: "/si/student-welcome-guide/", disclaimer: "Odgovori prihajajo neposredno s te spletne strani." }
|
guideUrl: "/si/student-welcome-guide/", disclaimer: "Odgovori prihajajo neposredno s te spletne strani." }
|
||||||
|
|
@ -283,7 +286,13 @@
|
||||||
function open() {
|
function open() {
|
||||||
opened = true; root.classList.add("msa-open");
|
opened = true; root.classList.add("msa-open");
|
||||||
panel.setAttribute("aria-hidden", "false"); launch.setAttribute("aria-expanded", "true");
|
panel.setAttribute("aria-hidden", "false"); launch.setAttribute("aria-expanded", "true");
|
||||||
if (!log.childNodes.length) { bubble(esc(UI.greeting), "bot"); renderChips(); loadIndex(PAGE_LANG); }
|
if (!log.childNodes.length) {
|
||||||
|
bubble(esc(UI.greeting), "bot");
|
||||||
|
var note = document.createElement("div");
|
||||||
|
note.className = "msa-note"; note.textContent = UI.disc;
|
||||||
|
log.appendChild(note);
|
||||||
|
renderChips(); loadIndex(PAGE_LANG);
|
||||||
|
}
|
||||||
setTimeout(function () { input.focus(); }, 60);
|
setTimeout(function () { input.focus(); }, 60);
|
||||||
}
|
}
|
||||||
function close() { opened = false; root.classList.remove("msa-open"); panel.setAttribute("aria-hidden", "true"); launch.setAttribute("aria-expanded", "false"); launch.focus(); }
|
function close() { opened = false; root.classList.remove("msa-open"); panel.setAttribute("aria-hidden", "true"); launch.setAttribute("aria-expanded", "false"); launch.focus(); }
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,105 @@
|
||||||
|
# Reading "Ask MSOS" questions in Google Analytics
|
||||||
|
|
||||||
|
The assistant sends one Google Analytics event every time someone asks a
|
||||||
|
question (only if they accepted cookies). This guide shows how to see those
|
||||||
|
questions — your **real FAQs** and, most valuably, the questions it **couldn't
|
||||||
|
answer** (so you know what to add next).
|
||||||
|
|
||||||
|
Property: **G-WVYV807VSS**. You need *Editor/Admin* access to that GA4 property.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## What gets sent
|
||||||
|
|
||||||
|
| Event name | `assistant_query` |
|
||||||
|
|---|---|
|
||||||
|
| `q` | the question text (first 120 chars) |
|
||||||
|
| `result` | `curated` (great answer) · `search` (found pages) · `none` (**no answer — a gap!**) |
|
||||||
|
| `q_lang` | language of the question: `en` / `mk` / `si` |
|
||||||
|
| `page_lang` | language of the page they were on |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Step 1 — Register the parameters (one-time, required)
|
||||||
|
|
||||||
|
GA4 hides custom parameters until you register them as **custom dimensions**.
|
||||||
|
Do this once:
|
||||||
|
|
||||||
|
1. GA4 → **Admin** (gear, bottom-left) → **Custom definitions** → **Create custom dimension**.
|
||||||
|
2. Create **four** dimensions, all with **Scope = Event**:
|
||||||
|
| Dimension name | Event parameter |
|
||||||
|
|---|---|
|
||||||
|
| Question | `q` |
|
||||||
|
| Result | `result` |
|
||||||
|
| Question language | `q_lang` |
|
||||||
|
| Page language | `page_lang` |
|
||||||
|
3. Click **Save** for each.
|
||||||
|
|
||||||
|
> ⚠️ Data only starts collecting into these dimensions **from the moment you
|
||||||
|
> create them** (it isn't retroactive), so set them up early. Reports take
|
||||||
|
> **24–48 h** to populate — but you can verify instantly in Step 2.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Step 2 — Verify it's working right now (Realtime)
|
||||||
|
|
||||||
|
1. Open the live site, **Accept** the cookie banner, open **Ask MSOS**, ask a test question.
|
||||||
|
2. In GA4 → **Reports** → **Realtime**.
|
||||||
|
3. Scroll to **"Event count by Event name"** → you should see **`assistant_query`**.
|
||||||
|
Click it to see the parameters coming in.
|
||||||
|
|
||||||
|
(If you don't see it: make sure you clicked *Accept* on cookies — the event is
|
||||||
|
intentionally not sent otherwise.)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Step 3 — Build the "Top questions" report (Exploration)
|
||||||
|
|
||||||
|
1. GA4 → **Explore** (left menu) → **Blank** exploration.
|
||||||
|
2. **Variables** column → next to **Dimensions** click **+** → add **Question**,
|
||||||
|
**Result**, **Question language**. → next to **Metrics** click **+** → add **Event count**.
|
||||||
|
3. In the **Settings** ("Tab Settings") column:
|
||||||
|
- **Rows** → drag in **Question**.
|
||||||
|
- **Values** → drag in **Event count**.
|
||||||
|
- **Filters** → drag in the field, choose... actually add a filter:
|
||||||
|
**Event name** `exactly matches` `assistant_query`.
|
||||||
|
(If "Event name" isn't offered, add the dimension **Event name** first.)
|
||||||
|
4. You now have a ranked list of the most-asked questions. Sort by Event count (click the column).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Step 4 — The gold mine: unanswered questions
|
||||||
|
|
||||||
|
Duplicate the tab (or add a filter) and set:
|
||||||
|
|
||||||
|
- **Rows**: Question
|
||||||
|
- **Values**: Event count
|
||||||
|
- **Filter**: **Result** `exactly matches` `none`
|
||||||
|
|
||||||
|
This is the list of questions the assistant **failed to answer**. Each one is a
|
||||||
|
prompt to either (a) add a curated answer in `assistant.js`, or (b) write/clarify
|
||||||
|
a page. This is how the assistant gets smarter over time.
|
||||||
|
|
||||||
|
Tip: also break down by **Question language** to see if MK/SI users are being
|
||||||
|
served as well as EN users.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Optional — a quick recurring check
|
||||||
|
|
||||||
|
Save the exploration (it autosaves). Once a week, open it and look at:
|
||||||
|
- **Top 10 questions** → your real FAQ list (consider promoting these on pages).
|
||||||
|
- **`result = none`** → your to-do list for new answers/content.
|
||||||
|
- **`result = search`** (not `curated`) → common questions worth turning into a
|
||||||
|
polished curated answer (edit the `INTENTS` list in `assistant.js`).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Privacy note
|
||||||
|
|
||||||
|
The question text is user-typed, so **avoid encouraging personal data** in the
|
||||||
|
prompt (the placeholder just says "Ask a question…"). Google's terms forbid
|
||||||
|
sending personal identifiers (emails, names) to GA. Questions are truncated to
|
||||||
|
120 characters and only sent **after cookie consent**. If you ever want zero
|
||||||
|
text stored, you can drop the `q` parameter in `assistant.js` and keep only the
|
||||||
|
`result`/language counts.
|
||||||
Loading…
Reference in New Issue