Umami-statistik – skripttagg, photo-open, instagram-click, integritetstext #6

Merged
imagesbyolofsson merged 2 commits from feat/umami-stats-2026-11-14 into main 2026-11-14 02:22:01 +00:00
Owner

Merged after Linus's go-ahead 2026-11-14 03:19 (was: go-live needs Linus's "kör" (runbook: P:\imagesbyolofsson-growth\analytics\2026-11-14-umami-go-live-runbook.md).

  • MainLayout.astro: <script is:inline defer src="/ibo-stats.js"> in head (served by the portal; no-op until Umami is switched on).
  • portfolio.astro: photo-open event right after the existing cookie-free counter (unchanged).
  • data-umami-event="instagram-click" on the two Instagram links (footer + start page). No Facebook link is rendered.

No visible change: main vs branch builds differ only by the script tag, the data attributes and the one JS call. Cookie box and Meta Pixel untouched. /privacy: the "Anonym statistik" / "Anonymous statistics" section now covers Umami (text accepted by Linus 2026-11-14, commit b2aab0e); date 14 november 2026. Nothing else on the page changed.

🤖 Generated with Claude Code

**Merged after Linus's go-ahead 2026-11-14 03:19 (was: go-live needs Linus's "kör" (runbook: `P:\imagesbyolofsson-growth\analytics\2026-11-14-umami-go-live-runbook.md`).** - `MainLayout.astro`: `<script is:inline defer src="/ibo-stats.js">` in head (served by the portal; no-op until Umami is switched on). - `portfolio.astro`: `photo-open` event right after the existing cookie-free counter (unchanged). - `data-umami-event="instagram-click"` on the two Instagram links (footer + start page). No Facebook link is rendered. No visible change: main vs branch builds differ only by the script tag, the data attributes and the one JS call. Cookie box and Meta Pixel untouched. `/privacy`: the "Anonym statistik" / "Anonymous statistics" section now covers Umami (text accepted by Linus 2026-11-14, commit b2aab0e); date 14 november 2026. Nothing else on the page changed. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
imagesbyolofsson added 1 commit 2026-11-14 01:45:56 +00:00
ai-git-bot left a comment
Member

🤖 AI Code Review

1. Blocking issues

File / Area Problem Why it matters Suggested fix
src/pages/portfolio.astro – inline <script> The line (window as any).iboStats?.track('photo-open', { photo: statsItem(item) }); uses TypeScript‑only syntax (as any). Inline <script> blocks are emitted to the browser as plain JavaScript, so the cast will cause a syntax error and abort the whole script (the photo‑open handler will never run). Breaks the photo‑open interaction and may also stop the preceding stat('open', …) call, defeating the analytics goal. Remove the TypeScript cast. Use plain JavaScript, e.g.:
if (window.iboStats && typeof window.iboStats.track === 'function') { window.iboStats.track('photo-open', { photo: statsItem(item) }); }
or, if you want to keep optional‑chaining, simply:
window.iboStats?.track('photo-open', { photo: statsItem(item) });
src/layouts/MainLayout.astro – <script is:inline defer src="/ibo-stats.js"> is:inline tells Astro to inline the script content, but you also provide a src attribute. This combination is contradictory: Astro will try to inline the tag without fetching the external file, resulting in a script tag that has no content and a src that may be ignored, or it may produce a warning/error depending on the Astro version. The analytics loader (ibo-stats.js) might never be loaded, so all subsequent stat/iboStats calls will be no‑ops. Remove is:inline when using an external source:
<script defer src="/ibo-stats.js"></script>
If you need the script inlined (e.g., for CSP), fetch the file at build time and inline its contents instead of using src.
src/layouts/MainLayout.astro – data-umami-event on Instagram link Adding data-umami-event="instagram-click" is fine, but the link also has target="_blank" without rel="noopener noreferrer" in the updated markup? (The original line already had those attributes, and the diff shows they are still present, so this is OK.) No blocking issue here.
Potential global namespace clash The new script injects a global iboStats object. If another script on the site also defines a global with that name, it could be overwritten. Could cause unexpected behavior in other parts of the site. Verify that iboStats is uniquely named (e.g., window.__iboStats) or namespace it inside your own module. This is not a breaking change but worth a quick sanity check.

2. Non‑blocking suggestions

  • Consistency of optional‑chaining – In portfolio.astro you already call stat('open', …). If iboStats is not loaded yet, the optional‑chaining prevents errors, but you might want to guard the call with a check that the analytics script has finished loading (e.g., listen for load event on the script tag).
  • Lazy‑load the stats script – Since the stats are only needed after a user interaction (photo open), you could defer loading ibo-stats.js until the first interaction to reduce initial payload.
  • Add a small comment near the new script tag explaining why it’s placed in the <head> and that it must stay after the SEO/SchemaOrg components (helps future maintainers).
  • Accessibility – The data-umami-event attribute does not affect accessibility, but ensure that any additional clickable elements (e.g., the Instagram icon) have appropriate aria-labels, which they already do.

3. Tests

  • Unit / component tests – There are no automated tests covering the new analytics hooks. Consider adding a test that mounts the portfolio page, simulates a click on a gallery item, and asserts that window.iboStats.track is called with the expected payload (mock the global).
  • End‑to‑end test – In a CI pipeline, run a Cypress/Playwright test that opens a photo and checks that the network request to your analytics endpoint (or a mock) is triggered. This will catch regressions if the script fails to load or the call is syntactically broken.

4. Overall assessment

The PR introduces valuable analytics events (Umami click tracking and photo‑open tracking) but contains two critical implementation errors that will prevent the code from executing:

  1. A TypeScript cast inside a client‑side <script> block (window as any) causing a syntax error.
  2. Misuse of is:inline together with a src attribute on the stats loader script, likely preventing the external script from loading.

Fix those two items (remove the TS cast, correct the script tag) and the changes are safe to merge. Afterwards, consider adding small test coverage for the new analytics hooks.


Automated review by AI Git Bot

## 🤖 AI Code Review **1. Blocking issues** | File / Area | Problem | Why it matters | Suggested fix | |-------------|---------|----------------|---------------| | **`src/pages/portfolio.astro` – inline `<script>`** | The line ` (window as any).iboStats?.track('photo-open', { photo: statsItem(item) }); ` uses TypeScript‑only syntax (`as any`). Inline `<script>` blocks are emitted to the browser as plain JavaScript, so the cast will cause a **syntax error** and abort the whole script (the photo‑open handler will never run). | Breaks the photo‑open interaction and may also stop the preceding `stat('open', …)` call, defeating the analytics goal. | Remove the TypeScript cast. Use plain JavaScript, e.g.: <br>`if (window.iboStats && typeof window.iboStats.track === 'function') { window.iboStats.track('photo-open', { photo: statsItem(item) }); }` <br>or, if you want to keep optional‑chaining, simply: <br>`window.iboStats?.track('photo-open', { photo: statsItem(item) });` | | **`src/layouts/MainLayout.astro` – `<script is:inline defer src="/ibo-stats.js">`** | `is:inline` tells Astro to inline the **script content**, but you also provide a `src` attribute. This combination is contradictory: Astro will try to inline the tag *without* fetching the external file, resulting in a script tag that has no content and a `src` that may be ignored, or it may produce a warning/error depending on the Astro version. | The analytics loader (`ibo-stats.js`) might never be loaded, so all subsequent `stat`/`iboStats` calls will be no‑ops. | Remove `is:inline` when using an external source: <br>`<script defer src="/ibo-stats.js"></script>` <br>If you need the script inlined (e.g., for CSP), fetch the file at build time and inline its contents instead of using `src`. | | **`src/layouts/MainLayout.astro` – `data-umami-event` on Instagram link** | Adding `data-umami-event="instagram-click"` is fine, but the link also has `target="_blank"` **without** `rel="noopener noreferrer"` in the updated markup? (The original line already had those attributes, and the diff shows they are still present, so this is OK.) No blocking issue here. | | **Potential global namespace clash** | The new script injects a global `iboStats` object. If another script on the site also defines a global with that name, it could be overwritten. | Could cause unexpected behavior in other parts of the site. | Verify that `iboStats` is uniquely named (e.g., `window.__iboStats`) or namespace it inside your own module. This is not a breaking change but worth a quick sanity check. | **2. Non‑blocking suggestions** * **Consistency of optional‑chaining** – In `portfolio.astro` you already call `stat('open', …)`. If `iboStats` is not loaded yet, the optional‑chaining prevents errors, but you might want to guard the call with a check that the analytics script has finished loading (e.g., listen for `load` event on the script tag). * **Lazy‑load the stats script** – Since the stats are only needed after a user interaction (photo open), you could defer loading `ibo-stats.js` until the first interaction to reduce initial payload. * **Add a small comment** near the new script tag explaining why it’s placed in the `<head>` and that it must stay after the SEO/SchemaOrg components (helps future maintainers). * **Accessibility** – The `data-umami-event` attribute does not affect accessibility, but ensure that any additional clickable elements (e.g., the Instagram icon) have appropriate `aria-label`s, which they already do. **3. Tests** * **Unit / component tests** – There are no automated tests covering the new analytics hooks. Consider adding a test that mounts the `portfolio` page, simulates a click on a gallery item, and asserts that `window.iboStats.track` is called with the expected payload (mock the global). * **End‑to‑end test** – In a CI pipeline, run a Cypress/Playwright test that opens a photo and checks that the network request to your analytics endpoint (or a mock) is triggered. This will catch regressions if the script fails to load or the call is syntactically broken. **4. Overall assessment** The PR introduces valuable analytics events (Umami click tracking and photo‑open tracking) but contains two critical implementation errors that will prevent the code from executing: 1. A TypeScript cast inside a client‑side `<script>` block (`window as any`) causing a syntax error. 2. Misuse of `is:inline` together with a `src` attribute on the stats loader script, likely preventing the external script from loading. Fix those two items (remove the TS cast, correct the script tag) and the changes are safe to merge. Afterwards, consider adding small test coverage for the new analytics hooks. --- *Automated review by AI Git Bot*
imagesbyolofsson added 1 commit 2026-11-14 02:14:39 +00:00
imagesbyolofsson changed title from WIP: Umami-statistik – skripttagg, photo-open, instagram-click (integritetstext saknas) to WIP: Umami-statistik – skripttagg, photo-open, instagram-click, integritetstext 2026-11-14 02:15:16 +00:00
imagesbyolofsson marked the pull request as ready for review 2026-11-14 02:22:00 +00:00
imagesbyolofsson merged commit 04fbcc9778 into main 2026-11-14 02:22:01 +00:00
Sign in to join this conversation.
No Reviewers
No labels
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: Imagesbyolofsson.se/imagesbyolofsson-se#6