Forum Discussion
Can a Code Block in Rise 360 be used to add Google Analytics JavaScript? If so, how?
Hello!
I’m curious if anyone has successfully used a Code Block in Rise 360 to insert Google Analytics JavaScript. If so, would you be willing to share how you approached it in beginner-friendly terms?
My team is looking to track page views for a few public-facing trainings hosted on our website using Google Analytics. Since these need to remain publicly accessible on our website, we have to stick with web publishing.
I don’t have any coding experience, so I’ve been researching possible approaches and came across a few options. I do plan to learn coding in the near future — I just need a just-in-time, just-enough solution that’s sustainable for now, if possible.
- Storyline via trigger (then inserted into Rise)
- This seems to be the most approachable route for a completely inexperienced coder such as myself.
-
Can I insert Google Analytics javascript in a trigger? | E-Learning Heroes
- Manual file modification (Post-Publish)
-
This feels too advanced and doesn't seem sustainable, especially if I need to watch for Articulate software updates that may impact the JavaScript.
-
- Third-Party Mods (such as the Mighty Chrome Extension)
- Wonderful idea, but my team does not have the funding to purchase any subscriptions at this time.
-
https://maestrolearning.com/blogs/articulate-rise-google-analytics/
If needed, I’ll go the Storyline route — but I was hoping the Code Block might be a simpler option.
Based on all of this, is this possible, or is Code Block not the right type of tool for this? If not, are there any newer, beginner-friendly approaches you’d recommend that might work?
Thank you so much for your time!
1 Reply
- SamHillSuper Hero
I think the best way is manual file modification, but you are correct, if the content is frequently updated and re-published, it is step that is easily missed.
With both the code block and storyline block methods, as far as I understand, the block would need to be included on every page of the content. As the content is bookmarked (cookies), the user is potentially returned to a different page whenever they launch the content, hence the need to include the block that adds GA on every page. Once added per session, it doesn't need to be added again. Any script to add the GA script should first check to see if it already exists before adding again.
Note: If the content does not bookmark and whenever a user opens the resource it always runs from the start, you can just include the code block on the first page (provided the first page is not the cover page with menu as a code block cannot be added to that page).
This is the major advantage of adding post publish, as you manually add the script in just one location.
I think the Rise block is the simpler solution as it just cuts out any need for Storyline.
Rise Code Block Google Analytics Code
Add a Rise Code Block to the top of each page in your project and paste in the following code.
Note: Ensure you update the ln:3 of the code with you Google Analytics Measurement ID.
const MEASUREMENT_ID = "G-XXXXXXXXXX";
<script> /** Replace with your GA4 Measurement ID (G-XXXXXXXXXX). */ const MEASUREMENT_ID = "G-XXXXXXXXXX"; const DEBUG = true; const dbg = (...args) => { if (DEBUG) console.debug("[add-ga]", ...args); }; (function addGoogleAnalytics() { dbg("start", { measurementId: MEASUREMENT_ID }); const scope = parent.parent.parent; const win = scope?.nodeType === 9 ? scope.defaultView : scope?.self ?? scope ?? window; const doc = scope?.nodeType === 9 ? scope : scope?.document ?? scope?.ownerDocument ?? document; dbg( "scope", scope, "constructor", scope?.constructor?.name, "doc", doc, "location", doc?.location?.href ?? doc?.URL ?? "(n/a)" ); if (!doc?.head || !win) { console.warn("[add-ga] no document.head or window on parent.parent.parent scope"); return; } const idKey = MEASUREMENT_ID; const already = win.__ga4InjectedIds && Object.prototype.hasOwnProperty.call(win.__ga4InjectedIds, idKey); if (already) { dbg("skip: already marked on target window", { idKey }); return; } if (doc.querySelector(`script[data-ga4-inline="${MEASUREMENT_ID}"]`)) { win.__ga4InjectedIds = win.__ga4InjectedIds || Object.create(null); win.__ga4InjectedIds[idKey] = true; dbg("skip: inline bootstrap already in DOM", { idKey }); return; } const gtagSrc = `googletagmanager.com/gtag/js`; const existingLoader = Array.prototype.some.call( doc.querySelectorAll(`script[src*="${gtagSrc}"]`), (el) => { const src = el.getAttribute("src") || ""; return src.includes(`id=${encodeURIComponent(MEASUREMENT_ID)}`) || src.includes(MEASUREMENT_ID); } ); if (existingLoader) { win.__ga4InjectedIds = win.__ga4InjectedIds || Object.create(null); win.__ga4InjectedIds[idKey] = true; dbg("skip: gtag.js loader for this ID already present", { idKey }); return; } win.__ga4InjectedIds = win.__ga4InjectedIds || Object.create(null); win.__ga4InjectedIds[idKey] = true; const loader = doc.createElement("script"); loader.async = true; loader.src = `https://www.googletagmanager.com/gtag/js?id=${encodeURIComponent(MEASUREMENT_ID)}`; doc.head.appendChild(loader); dbg("injected gtag.js loader", { src: loader.src }); const inline = doc.createElement("script"); inline.setAttribute("data-ga4-inline", MEASUREMENT_ID); inline.textContent = ` window.dataLayer = window.dataLayer || []; function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', ${JSON.stringify(MEASUREMENT_ID)}); `; doc.head.appendChild(inline); dbg("injected inline gtag bootstrap", { dataGa4Inline: MEASUREMENT_ID }); })(); </script>