Spaces:
Sleeping
Sleeping
Commit ·
40f139d
1
Parent(s): c5a7532
Add Umami page-view tracking
Browse filesUses st.html(..., unsafe_allow_javascript=True) rather than
components.html: the latter sandboxes content in its own iframe, so
Umami would only ever see a meaningless iframe-scoped page instead of
real top-level pageviews. Guarded by an element id so a Streamlit
rerun (which happens on every interaction, not just navigation) never
injects a duplicate script tag or fires an extra pageview beacon.
Website ID/script URL are plain constants, not secrets -- they're
visible in any page's source regardless.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- app.py +3 -0
- src/analytics.py +33 -0
app.py
CHANGED
|
@@ -13,9 +13,12 @@ import streamlit as st
|
|
| 13 |
|
| 14 |
import google_oauth
|
| 15 |
import token_store
|
|
|
|
| 16 |
|
| 17 |
st.set_page_config(page_title="Board Game Tracker", layout="wide")
|
| 18 |
|
|
|
|
|
|
|
| 19 |
|
| 20 |
def _drive_redirect_uri() -> str:
|
| 21 |
return st.secrets["auth"]["redirect_uri"].removesuffix("/oauth2callback")
|
|
|
|
| 13 |
|
| 14 |
import google_oauth
|
| 15 |
import token_store
|
| 16 |
+
from analytics import inject_umami
|
| 17 |
|
| 18 |
st.set_page_config(page_title="Board Game Tracker", layout="wide")
|
| 19 |
|
| 20 |
+
inject_umami()
|
| 21 |
+
|
| 22 |
|
| 23 |
def _drive_redirect_uri() -> str:
|
| 24 |
return st.secrets["auth"]["redirect_uri"].removesuffix("/oauth2callback")
|
src/analytics.py
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import streamlit as st
|
| 2 |
+
|
| 3 |
+
# Not sensitive -- an analytics site ID is plain HTML visible in any page's
|
| 4 |
+
# source, so this lives as a code constant rather than a secret/env var.
|
| 5 |
+
_UMAMI_SCRIPT_URL = "https://umami-acsk4kc0kw04o4ww4gosgoos.c.ai-man.cc/script.js"
|
| 6 |
+
_UMAMI_WEBSITE_ID = "ae40c7e5-ca49-4786-b185-e0a90f337e55"
|
| 7 |
+
_SCRIPT_TAG_ID = "umami-analytics-script"
|
| 8 |
+
|
| 9 |
+
|
| 10 |
+
def inject_umami() -> None:
|
| 11 |
+
"""Injects the Umami tracking script into the page.
|
| 12 |
+
|
| 13 |
+
st.html renders directly into the top-level DOM (unlike
|
| 14 |
+
components.html, which sandboxes content in its own iframe -- Umami
|
| 15 |
+
would then only ever see a meaningless "iframe page" instead of real
|
| 16 |
+
pageviews). Guarded by an element id so a Streamlit rerun never injects
|
| 17 |
+
a second copy or fires a duplicate pageview.
|
| 18 |
+
"""
|
| 19 |
+
st.html(
|
| 20 |
+
f"""
|
| 21 |
+
<script>
|
| 22 |
+
if (!document.getElementById('{_SCRIPT_TAG_ID}')) {{
|
| 23 |
+
var s = document.createElement('script');
|
| 24 |
+
s.id = '{_SCRIPT_TAG_ID}';
|
| 25 |
+
s.defer = true;
|
| 26 |
+
s.src = '{_UMAMI_SCRIPT_URL}';
|
| 27 |
+
s.setAttribute('data-website-id', '{_UMAMI_WEBSITE_ID}');
|
| 28 |
+
document.head.appendChild(s);
|
| 29 |
+
}}
|
| 30 |
+
</script>
|
| 31 |
+
""",
|
| 32 |
+
unsafe_allow_javascript=True,
|
| 33 |
+
)
|